#!/usr/bin/env python
# ###########################################################################
#
# This file is part of Taurus
#
# http://taurus-scada.org
#
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
#
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus. If not, see <http://www.gnu.org/licenses/>.
#
# ###########################################################################
"""
taurusdevicepropertytable.py:
"""
# todo: tango-centric
from taurus.external.qt import Qt, QtCore, QtGui
from taurus.qt.qtgui.base import TaurusBaseWidget
from taurus.core.taurusdevice import TaurusDevice
[docs]
class TaurusPropTable(QtGui.QTableWidget, TaurusBaseWidget):
"""
This widget will show a list of properties of device and the list of
values.
"""
# TODO add a frame for Add, Delete and Refresh buttons!
# TODO This widget is Tango-centric
def __init__(self, parent=None, designMode=False):
try:
name = "TaurusPropTable"
self._useParentModel = True
self._localModel = ""
self.call__init__wo_kw(QtGui.QTableWidget, parent)
self.call__init__(TaurusBaseWidget, name, designMode=designMode)
self.setObjectName(name)
self.defineStyle()
self.db = None
except Exception:
self.traceback()
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# TaurusBaseWidget over writing methods
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
def setModel(self, model, **kwargs):
TaurusBaseWidget.setModel(self, model)
# Update the table
modelObj = self.getModelObj()
if modelObj is None:
dev_name = None
self.db = None
else:
validator = modelObj.getNameValidator()
groups = validator.getUriGroups(modelObj.getFullName())
dev_name = groups["devname"]
# -----------------------------------------------------------------
# Workaround for bug-256
# (use next line instead of the other one when bug-256 is fixed)
# self.db = modelObj.getParentObj() # use this instead
self.db = modelObj.factory().getAuthority(groups["authority"])
# -----------------------------------------------------------------
self.setTable(dev_name)
[docs]
def sizeHint(self):
return QtGui.QTableWidget.sizeHint(self)
[docs]
def minimumSizeHint(self):
return QtGui.QTableWidget.minimumSizeHint(self)
[docs]
def getModelClass(self, **kwargs):
return TaurusDevice
[docs]
@classmethod
def getQtDesignerPluginInfo(cls):
ret = TaurusBaseWidget.getQtDesignerPluginInfo()
ret["module"] = "taurus.qt.qtgui.table"
ret["group"] = "Taurus Views"
ret["icon"] = "designer:table.png"
return ret
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# QT properties
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
model = QtCore.pyqtProperty(
"QString",
TaurusBaseWidget.getModel,
setModel,
TaurusBaseWidget.resetModel,
)
#: (deprecated))
useParentModel = QtCore.pyqtProperty(
"bool",
TaurusBaseWidget.getUseParentModel,
TaurusBaseWidget.setUseParentModel,
TaurusBaseWidget.resetUseParentModel,
)
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# My methods
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
@QtCore.pyqtSlot("QString")
def setTable(self, dev_name):
"""
Fills the table with the names of properties and their values for the
given device.
"""
if dev_name is None:
return # TODO: the table should be cleaned
elif self.db is None:
self.warning("Model must be set before calling setTable")
return
try:
self.cellChanged.disconnect(self.valueChanged)
except Exception:
pass
dev_name = str(dev_name)
self.list_prop = list(self.db.get_device_property_list(dev_name, "*"))
self.setRowCount(len(self.list_prop))
for i in range(0, len(self.list_prop)):
elem = self.list_prop[i]
self.setText(elem, i, 0)
self.dictionary = self.db.get_device_property(
dev_name, self.list_prop
)
self.debug(
"Getting %s properties: %s -> %s",
dev_name,
self.list_prop,
self.dictionary,
)
value = self.dictionary[elem]
self.debug(
"TaurusPropsTable: property %s is type %s", elem, type(value)
)
USE_TABLES = False
if USE_TABLES:
self.setPropertyValue(value, i, 1)
else:
if not isinstance(value, str): # not something like an string
# adding new lines in between elements in the list
value = "\n".join(str(v) for v in value)
self.setText(str(value), i, 1)
self.updateStyle()
self.dev_name = dev_name
self.setWindowTitle("%s Properties" % dev_name)
self.resizeColumnsToContents()
self.resizeRowsToContents()
[docs]
def defineStyle(self):
"""Defines the initial style for the widget"""
self.setWindowTitle("Properties")
self.setColumnCount(2)
self.setRowCount(0)
self.setGeometry(QtCore.QRect(0, 0, 400, 500))
self.setColumnWidth(0, 124)
self.setColumnWidth(1, 254)
headerItem = QtGui.QTableWidgetItem()
headerItem.setText(
QtGui.QApplication.translate(
"PLCTabWidget",
"Property Name",
None,
QtGui.QApplication.UnicodeUTF8,
)
)
self.setHorizontalHeaderItem(0, headerItem)
headerItem1 = QtGui.QTableWidgetItem()
headerItem1.setText(
QtGui.QApplication.translate(
"PLCTabWidget", "Value", None, QtGui.QApplication.UnicodeUTF8
)
)
self.setHorizontalHeaderItem(1, headerItem1)
hh = self.horizontalHeader()
if hh.length() > 0:
hh.setSectionResizeMode(hh.ResizeToContents)
[docs]
def updateStyle(self):
self.resizeRowsToContents()
hh = self.horizontalHeader()
if hh.length() > 0:
hh.setSectionResizeMode(hh.ResizeToContents)
# self.resizeColumnsToContents()
[docs]
def setText(self, value, i=None, j=None):
item = QtGui.QTableWidgetItem()
item.setFlags(Qt.Qt.ItemIsEnabled)
item.setText(
QtGui.QApplication.translate(
"PLCTabWidget", value, None, QtGui.QApplication.UnicodeUTF8
)
)
if i is not None and j is not None:
self.setItem(i, j, item)
# TODO: the info does not change with the events.
[docs]
def valueDoubleClicked(self, x, y):
self.info("TaurusPropTable.valueDoubleClicked(%s,%s)" % (x, y))
# opens a dialog for multiline edition
self.editProperty()
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# @name Property Edition
# @{
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
def addProperty(self):
text, ok = QtGui.QInputDialog.getText(
self, "New Property", "Property name:"
)
if ok:
text1 = str(text)
new_prop_name = str(text1)
new_prop_value = "0"
dict1 = {new_prop_name: [new_prop_value]}
self.db.put_device_property(self.dev_name, dict1)
self.setTable(self.dev_name)
[docs]
def deleteProperty(self):
row = self.currentRow()
prop_name = self.item(row, 0).text()
list = [str(prop_name)]
yes = QtGui.QMessageBox.Ok
no = QtGui.QMessageBox.Cancel
result = QtGui.QMessageBox.question(
self,
"Removing property",
"Would you like to delete property '" + prop_name + "' ?",
yes,
no,
)
if result == yes:
self.db.delete_device_property(self.dev_name, list)
self.setTable(self.dev_name)
[docs]
def editProperty(self):
row = self.currentRow()
col = self.currentColumn()
item1 = QtGui.QTableWidgetItem()
item1 = self.item(row, 0)
prop_name = item1.text()
prop_name = str(prop_name)
self.prop_name2 = prop_name
self.info("TaurusPropsTable.editProperty(%s)" % prop_name)
item2 = QtGui.QTableWidgetItem()
item2 = self.item(row, 1)
prop_value = item2.text()
prop_value = str(prop_value)
if col == 0:
new_text, ok = QtGui.QInputDialog.getText(
self, "Rename", "Write new name of property:"
)
if ok:
new_text = str(new_text)
new_text = str(new_text)
list = [prop_name]
dict = {new_text: [prop_value]}
# usuwanie musze umiescic gdzies wczesniej bo inaczej usuwam
# juz zmieniana nazwe z listy property
self.db.delete_device_property(self.dev_name, list)
self.db.put_device_property(self.dev_name, dict)
self.setTable(self.dev_name)
elif col == 1:
# Create the dilog to edit multiply text
dialogx = EditTextDialog(self)
dialogx.setText(prop_value)
dialogx.exec_()
ok = dialogx.getResult() # OK or Cancel
if ok:
new_text = (
dialogx.getNewText()
) # method of dialog to get the changed text
self.setNewPropertyValue(new_text)
[docs]
def setNewPropertyValue(self, new_text):
new_text = str(new_text)
new_text = str(new_text)
values = {self.prop_name2: new_text.replace("\r", "").split("\n")}
self.db.put_device_property(self.dev_name, values)
self.setTable(self.dev_name)
self.updateStyle()
# @}
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# Methods for database commands
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
def get_device_property_names(self, dev_name, wildcard="*"):
return self.db.get_device_property_list(dev_name, wildcard)
[docs]
def put_device_property(self, dev_name, dict):
return self.db.put_device_property(dev_name, dict)
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# @name DEPRECATED METHODS
# @{
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
def valueChanged(self):
"""@deprecated valueChanged THIS DOES NOTHING!"""
row = self.currentRow()
# item = QtGui.QTableWidgetItem()
item = self.item(row, 0)
prop_name = item.text()
prop_name = str(prop_name)
# item_2 = QtGui.QTableWidgetItem()
item_2 = self.item(row, 1)
prop_value = item_2.text()
prop_value = str(prop_value)
dict = {prop_name: [prop_value]}
list = [self.prop_name]
self.db.delete_device_property(self.dev_name, list)
self.db.put_device_property(self.dev_name, dict)
[docs]
def setPropertyValue(self, value, i, j):
"""This method inserts a new table widget inside the cell
@deprecated ... use setText() and editProperty() event call instead!!!
"""
if len(value) == 1 and isinstance(value[0], str):
value = value[0]
if isinstance(value, str): # and '\n' in value:
value = value.split("\n")
if False: # isinstance(value,str):
item = QtGui.QTableWidgetItem()
item.setText(
QtGui.QApplication.translate(
"PLCTabWidget", value, None, QtGui.QApplication.UnicodeUTF8
)
)
self.setItem(i, j, item)
else:
item = QtGui.QTableWidget(len(value), 1)
item.setItemDelegate(Delegate(item))
item.horizontalHeader().hide()
item.verticalHeader().hide()
# item.setGridStyle(Qt.Qt.DashLine)
for k, v in enumerate(value):
cell = QtGui.QTableWidgetItem()
cell.setText(
QtGui.QApplication.translate(
"PLCTabWidget", v, None, QtGui.QApplication.UnicodeUTF8
)
)
item.setItem(k, 0, cell)
item.setSizePolicy(
QtGui.QSizePolicy.MinimumExpanding,
QtGui.QSizePolicy.MinimumExpanding,
)
self.setCellWidget(i, j, item)
self.resizeColumnsToContents()
self.resizeRowsToContents()
return
# @}
class EditTextDialog(QtGui.QDialog):
"""This class create the dialog using to edit multiply text"""
def __init__(self, parent=None):
print("In EditTextDialog.__init__()")
QtGui.QDialog.__init__(self, parent)
self.setModal(1)
self.initComponents()
self.show()
self.result = 0
# Signals
self.buttonBox.accepted.connect(self.pressOK)
self.buttonBox.rejected.connect(self.close)
def initComponents(self):
widgetLayout = QtGui.QVBoxLayout(self)
widgetLayout.setContentsMargins(10, 10, 10, 10)
self.editText = QtGui.QTextEdit()
self.buttonBox = QtGui.QDialogButtonBox()
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel
| QtGui.QDialogButtonBox.NoButton
| QtGui.QDialogButtonBox.Ok
)
widgetLayout.addWidget(self.editText)
widgetLayout.addWidget(self.buttonBox)
def pressOK(self):
print("In EditTextDialog.pressOk()")
self.new_text = self.editText.toPlainText()
self.result = 1
self.close()
def setText(self, text):
self.editText.setText(text)
self.new_text = text
def getNewText(self):
return self.new_text
def getResult(self):
return self.result
class Delegate(QtGui.QItemDelegate):
"""Usage:
table = QtGui.QTableWidget()
table.setItemDelegate(Delegate(table))
"""
def __init__(self, parent=None):
QtGui.QItemDelegate.__init__(self, parent)
def sizeHint(self, option, index):
table = self.parent()
widget = table.cellWidget(index.row(), index.column())
if not widget:
widget = table.itemAt(index.row(), index.column())
size = widget.sizeHint()
return size
if __name__ == "__main__":
import sys
from taurus.qt.qtgui.application import TaurusApplication
app = TaurusApplication(
app_name="TaurusDevice property table", cmd_line_parser=None
)
widget = TaurusPropTable()
args = sys.argv
if len(args) == 1:
model = "sys/tg_test/1"
else:
model = str(args[1])
widget.setModel(model)
widget.show()
app.exec_()