class TaurusGrid(QtGui.QFrame, TaurusBaseWidget): """ TaurusGrid is a Taurus widget designed to represent a set of attributes distributed in columns and rows. The Model will be a list with attributes or device names (for devices the State attribute will be shown). Each setModel(*) execution will be able to modify the attribute list. An example of execution:<pre> /usr/bin/python taurusgrid.py "model=lt.*/VC.*/.*/((C*)|(P*)|(I*))" cols=IP,CCG,PNV rows=LT01,LT02 </pre> @author originally developed by gcuni, extended by srubio and sblanch @todo Future releases should allow a list of filters as argument @todo names/widgets should be accessible as a caselessdict dictionary (e.g. for adding custom context menus) @todo refactoring to have methods that add/remove new widgets one by one, not only the whole dictionary @todo _TAGS property should allow to change row/columns meaning and also add new Custom tags based on regexp """ # ------------------------------------------------------------------------- # Write your own code here to define the signals generated by this widget # itemSelected = Qt.pyqtSignal('QString') itemClicked = Qt.pyqtSignal('QString') _TAGS = [ 'DOMAIN', 'FAMILY', 'HOST', 'LEVEL', 'CLASS', 'ATTRIBUTE', 'DEVICE' ] class _TaurusGridCell(Qt.QFrame): itemClicked = Qt.pyqtSignal('QString') # Done in this way as TaurusValue.mousePressEvent is never called def mousePressEvent(self, event): # print 'In cell clicked' targets = set( str(child.getModelName()) for child in self.children() if hasattr(child, 'underMouse') and child.underMouse() and hasattr(child, 'getModelName')) for t in targets: self.itemClicked.emit(t) def __init__(self, parent=None, designMode=False): name = self.__class__.__name__ self.call__init__wo_kw(QtGui.QFrame, parent) # self.call__init__(TaurusBaseWidget, name, parent, # designMode=designMode) # It was needed to avoid exceptions in TaurusDesigner! if isinstance(parent, TaurusBaseWidget): self.call__init__(TaurusBaseWidget, name, parent, designMode=designMode) else: self.call__init__(TaurusBaseWidget, name, designMode=designMode) self.title = '' self.showLabels = True self.filter = '' self._modelNames = [] self.row_labels = [] self.column_labels = [] self._widgets_list = [] self._last_selected = None self._show_frames = True self._show_row_frame = True self._show_column_frame = True self._show_others = False self._show_attr_labels = True self._show_attr_units = True self.hideLabels = False self.defineStyle() self.modelsQueue = Queue() self.__modelsThread = None if not designMode: self.modelsThread @property def modelsThread(self): modelsThread = self.__modelsThread if modelsThread is None: modelsThread = SingletonWorker(parent=self, name='TaurusGrid', queue=self.modelsQueue, method=modelSetter, cursor=True) self.__modelsThread = modelsThread return modelsThread def save(self, filename): import pickle d = { 'model': self.filter, 'row_labels': self.row_labels, 'column_labels': self.column_labels, 'frames': self._show_row_frame or self._show_column_frame, 'labels': self._show_attr_labels, 'units': self._show_attr_units, 'others': self._show_others } f = open(filename, 'wb') pickle.dump(d, f) f.close() def load(self, filename, delayed=False): self.trace('In TauGrid.load(%s,%s)' % (filename, delayed)) if not isinstance(filename, dict): manual = False import pickle f = open(filename, 'rb') d = pickle.load(f) f.close() else: manual = True d = filename self.setRowLabels(d['row_labels']) self.setColumnLabels(d['column_labels']) self.showAttributeLabels(d.get('labels', True)) self.showAttributeUnits(d.get('units', True)) self.showOthers(d.get('others', True)) self.showRowFrame(d.get('frames', True)) if manual: self.showColumnFrame(d.get('frames', True)) self.setModel(d['model'], delayed=d.get('delayed', delayed)) return self._modelNames def defineStyle(self): """ Defines the initial style for the widget """ # ---------------------------------------------------------------------- # Write your own code here to set the initial style of your widget # self.setLayout(QtGui.QGridLayout()) # self.layout().setContentsMargins(0,0,0,0) self.updateStyle() def sizeHint(self): return QtGui.QFrame.sizeHint(self) def minimumSizeHint(self): return QtGui.QFrame.minimumSizeHint(self) # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusBaseWidget over writing # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def getModelClass(self): # ---------------------------------------------------------------------- # [MANDATORY] # Replace your own code here # ex.: return taurus.core.taurusattribute.Attribute raise RuntimeError("Forgot to overwrite %s.getModelClass" % str(self)) return list def attach(self): """Attaches the widget to the model""" if self.isAttached(): return True # ---------------------------------------------------------------------- # Write your own code here before attaching widget to attribute connect # the proper signal so that the first event is correctly received by the # widget ret = TaurusBaseWidget.attach(self) # by default enable/disable widget according to attach state self.setEnabled(ret) return ret def detach(self): """Detaches the widget from the model""" TaurusBaseWidget.detach(self) # ---------------------------------------------------------------------- # Write your own code here after detaching the widget from the model # by default disable widget when dettached self.setEnabled(False) # ------------------------------------------------------------------------- # [MANDATORY] # Uncomment the following method if your superclass does not provide with a # isReadOnly() method or if you need to change its behavior # def isReadOnly(self): # return True def updateStyle(self): # ---------------------------------------------------------------------- # Write your own code here to update your widget style self.trace('@' * 80) self.trace( 'In TaurusGrid.updateStyle() ....... It seems never called!!!!') self.trace('@' * 80) # It was showing an annoying "True" in the widget # value = self.getShowText() or '' # if self._setText: self._setText(value) ##It must be included # update tooltip self.setToolTip(self.getFormatedToolTip()) # It must be included # send a repaint in the end if hasattr(self, 'title_widget'): if self.title: self.title_widget.show() else: self.title_widget.hide() self.update() # ------------------------------------------------------------------------- # Write your own code here for your own widget properties def setModel(self, model, devsInRows=False, delayed=False, append=False, load=True): '''The model can be initialized as a list of devices or hosts or dictionary or ...''' # self.setModelCheck(model) ##It must be included # differenciate if the model is a RegExp if isinstance(model, dict): self.load(model) else: model = isinstance(model, string_types) and [model] or list(model) self.trace('#' * 80) self.trace('In TaurusGrid.setModel(%s)' % str(model)[:100]) self.delayed = delayed self.filter = model if any('*' in m for m in model): model = get_all_models(model) self.debug( 'model was a RegExp, done the query and converted to an attr list' ) if not self._modelNames == []: # clean to start from scratch for widget in self._widgets_list: del widget # here we always have the reals model list, even if it comes from a # regexp if append: self._modelNames = self._modelNames + model else: self._modelNames = model self.debug(('In TaurusGrid.setModel(...): modelNames are %s' % (self._modelNames))[:100] + '...') if load: self.trace( 'In TaurusGrid.setModel(%s,load=True): modelNames are %d' % (str(model)[:100] + '...', len( self._modelNames))) # ,self._modelNames)) if devsInRows: self.setRowLabels(','.join( set(d.rsplit('/', 1)[0] for d in self._modelNames))) self.create_widgets_table(self._modelNames) self.modelsQueue.put( (MethodModel(self.showRowFrame), self._show_row_frame)) self.modelsQueue.put((MethodModel(self.showColumnFrame), self._show_column_frame)) self.modelsQueue.put( (MethodModel(self.showOthers), self._show_others)) self.modelsQueue.put((MethodModel(self.showAttributeLabels), self._show_attr_labels)) self.modelsQueue.put((MethodModel(self.showAttributeUnits), self._show_attr_units)) self.updateStyle() if not self.delayed: self.trace('In setModel(): not delayed loading of models') if not self.modelsThread.isRunning(): # print 'In setModel(): Starting Thread! (%d objs in # queue)'%(self.modelsThread.queue.qsize()) self.trace('<' * 80) # self.modelsThread.IdlePriority) self.modelsThread.start() else: # print 'In setModel(): Thread already started! (%d # objs in queue)'%(self.modelsThread.queue.qsize()) self.modelsThread.next() else: self.trace('In setModel(): models loading delayed!') pass self.trace('Out of TaurusGrid.setModel(%s)' % str(model)[:100]) self.updateStyle() return def getModel(self): return self._modelNames def resetModel(self): self._modelNames = [] self.updateFromList(self._modelNames) return def setTitle(self, title): self.title = str(title) if hasattr(self, 'title_widget'): if title: self.title_widget.setText(self.title) self.title_widget.show() else: self.title_widget.hide() def parse_labels(self, text): if any( text.startswith(c[0]) and text.endswith(c[1]) for c in [('{', '}'), ('(', ')'), ('[', ']')]): try: labels = eval(text) return labels except Exception as e: self.warning('ERROR! Unable to parse labels property: %s' % str(e)) return [] else: exprs = [t.strip() for t in text.split(',')] labels = [ (':' in e and (e.split(':', 1)[0].strip(), e.split(':', 1)[-1].strip()) or (e, e)) for e in exprs ] return labels def setRowLabels(self, rows): '''The model can be initialized as a list of devices or hosts or ...''' # self.setModelCheck(model) ##It must be included self.row_labels = self.parse_labels(str(rows)) try: self.rows = [r[0] for r in self.row_labels] for i in range(len(self.rows)): section = self.rows[i] self.table.setVerticalHeaderItem( i, QtGui.QTableWidgetItem(section)) except Exception as e: self.debug("setRowLabels(): Exception! %s" % e) # self.create_widgets_table(self._columnsNames) def getRowLabels(self): return ','.join(':'.join(c) for c in self.row_labels) def resetRowLabels(self): self.row_labels = [] return def setColumnLabels(self, columns): '''The model can be initialized as a list of devices or hosts or ...''' # self.setModelCheck(model) ##It must be included self.column_labels = self.parse_labels(str(columns)) try: self.columns = [c[0] for c in self.column_labels] for i in range(len(self.columns)): equipment = self.columns[i] self.table.setHorizontalHeaderItem( i, QtGui.QTableWidgetItem(equipment)) except Exception as e: self.debug("setColumnLabels(): Exception! %s" % e) # self.create_widgets_table(self._columnsNames) def getColumnLabels(self): return ','.join(':'.join(c) for c in self.column_labels) def resetColumnLabels(self): self.column_labels = [] return # FIXME: when they are called before setModel they fails because # frames are not yet created, and it doesn't has memoty about this. def showRowFrame(self, boolean): self._show_row_frame = boolean if hasattr(self, 'rows_frame'): if boolean: self.rows_frame.show() else: self.rows_frame.hide() def showColumnFrame(self, boolean): self._show_column_frame = boolean if hasattr(self, 'columns_frame'): if boolean: self.columns_frame.show() else: self.columns_frame.hide() def showAttributeLabels(self, boolean): self.trace('In showAttributeLabels(%s)' % boolean) self._show_attr_labels = boolean for tv in self._widgets_list: try: if tv and tv.labelWidget: if boolean: tv.labelWidget().show() else: tv.labelWidget().hide() except: pass return self._show_attr_labels def showAttributeUnits(self, boolean): self.trace('In showAttributeUnits(%s)' % boolean) self._show_attr_units = boolean for tv in self._widgets_list: try: if tv and tv.unitsWidget: if boolean: tv.unitsWidget().show() else: tv.unitsWidget().hide() except: pass return self._show_attr_units # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- model = QtCore.pyqtProperty("QStringList", getModel, setModel, resetModel) rowlabels = QtCore.pyqtProperty("QString", getRowLabels, setRowLabels, resetRowLabels) columnlabels = QtCore.pyqtProperty("QString", getColumnLabels, setColumnLabels, resetColumnLabels) useParentModel = QtCore.pyqtProperty("bool", TaurusBaseWidget.getUseParentModel, TaurusBaseWidget.setUseParentModel, TaurusBaseWidget.resetUseParentModel) # ------------------------------------------------------------------------- # Write your own code here for your own widget properties def create_widgets_dict(self, models): from collections import defaultdict # recursive dictionary with 2 levels values = defaultdict(lambda: defaultdict(list)) # domains = list(set(m.split('/')[0].upper())) # families = list(set(m.split('/')[1].upper())) if not self.row_labels: # Domains used by default self.row_labels = sorted( list( set( m.split('/')[0].upper() for m in models if m.count('/') >= 2))) self.row_labels = list(zip(self.row_labels, self.row_labels)) if not self.column_labels: # Families used by default self.column_labels = sorted( list( set( m.split('/')[1].upper() for m in models if m.count('/') >= 2))) self.column_labels = list( zip(self.column_labels, self.column_labels)) # for m in models: # if m.count('/')<2: # self.warning('Wrong model cannot be added: %s'%m) # else: # domain,family = m.upper().split('/')[:2] # values[domain][family].append(m) row_not_found, col_not_found = False, False for m in models: row, column = 'Others', 'Others' for label, rexp in self.row_labels: if '*' in rexp and '.*' not in rexp: rexp = rexp.replace('*', '.*') if re_search_low(rexp, m): row = label break for label, rexp in self.column_labels: if '*' in rexp and '.*' not in rexp: rexp = rexp.replace('*', '.*') if re_search_low(rexp, m): column = label break if 'Others' == row: row_not_found = True if 'Others' == column: col_not_found = True self.debug('Model %s added to row %s , column %s' % (m, row, column)) values[row][column].append(m) if row_not_found: self.row_labels.append(('Others', '.*')) if col_not_found: self.column_labels.append(('Others', '.*')) return values def create_frame_with_gridlayout(self): """ Just a 'macro' to create the layouts that seem to fit better. """ frame = TaurusGrid._TaurusGridCell() frame.setLayout(QtGui.QGridLayout()) frame.layout().setContentsMargins(2, 2, 2, 2) frame.layout().setSpacing(0) frame.layout().setSpacing(0) return frame def create_widgets_table(self, models): # Added a title to the panel self.title_widget = QtGui.QLabel() self.layout().addWidget(self.title_widget, 0, 0) self.setTitle(self.title) dct = self.create_widgets_dict(models) # Assignments modified to keep the order of labels as inserted in # properties self.rows = [r[0] for r in self.row_labels] # dct.keys() # list(set(reduce(operator.add,v.keys()) for v in dct.values())) self.columns = [c[0] for c in self.column_labels] values = [] for row in self.rows: line = [] for col in self.columns: # line.append(dct[row][col] if col in dct[row] else []) if col in dct[row]: line.append(dct[row][col]) else: line.append([]) values.append(line) # Here is where the table is created! self.table = self.build_table(values) # SET COLUMN HEADERS (self.columns) for i in range(len(self.columns)): equipment = self.columns[i] self.table.setHorizontalHeaderItem( i, QtGui.QTableWidgetItem(equipment)) # SOMEDAY THIS WILL BE ICONS # SET ROW HEADERS (self.rows) for i in range(len(self.rows)): section = self.rows[i] self.table.setVerticalHeaderItem(i, QtGui.QTableWidgetItem(section)) # table.setAutoScroll(True) # resize_mode = QtGui.QHeaderView.Stretch # table.horizontalHeader().setSectionResizeMode(resize_mode) # table.verticalHeader().setSectionResizeMode(resize_mode) # for row in range(len(self.rows)): # table.setRowHeight(row,5+25*sum(len(dct[self.rows[row]][col]) for col in self.columns)) # for col in range(len(self.columns)): # table.setColumnWidth(col,300) use_scroll = False # It didn't work ... it doesn't allow the table widget to resize if use_scroll: scrollable = QtGui.QScrollArea(self) scrollable.setWidget(self.table) self.layout().addWidget(scrollable, 1, 0) else: self.layout().addWidget(self.table, 1, 0) # ---------------------------------------------------------------------- # SECTION CHECKBOXES self.checkboxes_frame = self.create_frame_with_gridlayout() self.rows_frame = self.create_frame_with_gridlayout() self.rows_frame.setFrameStyle(QtGui.QFrame.Box) if not self._show_row_frame: self.rows_frame.hide() self.checkboxes_frame.layout().addWidget(self.rows_frame, 0, 0) self.columns_frame = self.create_frame_with_gridlayout() self.columns_frame.setFrameStyle(QtGui.QFrame.Box) if not self._show_column_frame: self.columns_frame.hide() self.checkboxes_frame.layout().addWidget(self.columns_frame, 0, 1) layout_row = 0 layout_col = 0 # For all rows, create rows of three checkboxes in order to # show or hide the corresponding rows in the table for i in range(len(self.rows)): section = self.rows[i] checkbox = QtGui.QCheckBox(section) # ------------------------------------------------------- # Work around for https://bugs.kde.org/show_bug.cgi?id=345023 # TODO: make better solution for this checkbox._id = section # <-- ugly monkey-patch! # ------------------------------------------------------- if section == 'Others': checkbox.setChecked(False) if not self._show_others: checkbox.hide() else: checkbox.setChecked(True) self.rows_frame.layout().addWidget(checkbox, layout_row, layout_col) layout_col += 1 if layout_col == 3: layout_col = 0 layout_row += 1 checkbox.toggled.connect(self.show_hide_rows) self.show_hide_rows() layout_row = 0 layout_col = 0 # For all self.columns, create rows of three checkboxes in order to # show or hide the corresponding columns in the table for i in range(len(self.columns)): column = self.columns[i] checkbox = QtGui.QCheckBox(column) # ------------------------------------------------------- # Work around for https://bugs.kde.org/show_bug.cgi?id=345023 # TODO: make better solution for this checkbox._id = column # <-- ugly monkey-patch! # ------------------------------------------------------- if column == 'Others': checkbox.setChecked(False) if not self._show_others: checkbox.hide() else: checkbox.setChecked(True) self.columns_frame.layout().addWidget(checkbox, layout_row, layout_col) layout_col += 1 if layout_col == 3: layout_col = 0 layout_row += 1 checkbox.toggled.connect(self.show_hide_columns) self.show_hide_columns() self.layout().addWidget(self.checkboxes_frame, 2, 0) # self.resize(800,600) def show_hide_rows(self): """ This needs refactoring to be together with the show_hide_columns method """ for checkbox in self.rows_frame.children(): if isinstance(checkbox, QtGui.QCheckBox): # ------------------------------------------------------- # Work around for https://bugs.kde.org/show_bug.cgi?id=345023 # TODO: make better solution for this # checkbox.text() <-- fails due to added "& table_row = self.rows.index(checkbox._id) # ------------------------------------------------------- if checkbox.isChecked(): self.table.showRow(table_row) else: self.table.hideRow(table_row) def show_hide_columns(self): """ This needs refactoring to be together with the show_hide_rows method """ for checkbox in self.columns_frame.children(): if isinstance(checkbox, QtGui.QCheckBox): # ------------------------------------------------------- # Work around for https://bugs.kde.org/show_bug.cgi?id=345023 # TODO: make better solution for this # checkbox.text() <-- fails due to added "& table_col = self.columns.index(checkbox._id) # ------------------------------------------------------- if checkbox.isChecked(): self.table.showColumn(table_col) else: self.table.hideColumn(table_col) def showOthers(self, boolean): self._show_others = boolean if hasattr(self, 'rows_frame'): for checkbox in self.rows_frame.children(): if (isinstance(checkbox, QtGui.QCheckBox) # ------------------------------------------------------- # Work around for https://bugs.kde.org/show_bug.cgi?id=345023 # TODO: make better solution for this # checkbox.text() <-- fails due to added "& and checkbox._id == 'Others'): # ------------------------------------------------------- if self._show_others: checkbox.show() else: checkbox.hide() if hasattr(self, 'columns_frame'): for checkbox in self.columns_frame.children(): if (isinstance(checkbox, QtGui.QCheckBox) # ------------------------------------------------------- # Work around for https://bugs.kde.org/show_bug.cgi?id=345023 # TODO: make better solution for this # checkbox.text() <-- fails due to added "& and checkbox._id == 'Others'): # ------------------------------------------------------- if self._show_others: checkbox.show() else: checkbox.hide() def build_table(self, values): """ This is a builder. For all the elements in widgets matrix, just set the corresponding cells of the QTableWidget. """ self.trace('In TaurusGrid.build_table(%s)' % values) widgets_matrix = self.build_widgets(values, self.showLabels) rows = len(widgets_matrix) cols = rows and len(widgets_matrix[0]) or 0 table = QtGui.QTableWidget() table.setItemDelegate(Delegate(table)) # This example replaces the blue background of selected cells in tables palette = Qt.QPalette() palette.setBrush(palette.Active, palette.Highlight, Qt.QBrush(Qt.Qt.white)) table.setPalette(palette) table.setRowCount(rows) table.setColumnCount(cols) for row in range(len(widgets_matrix)): for col in range(len(widgets_matrix[row])): table.setCellWidget(row, col, widgets_matrix[row][col]) # table.resizeColumnsToContents() # table.resizeRowsToContents() hh = table.horizontalHeader() if hh.length() > 0: try: hh.setSectionResizeMode(hh.Stretch) except AttributeError: # PyQt4 hh.setResizeMode(hh.Stretch) # table.verticalHeader().setSectionResizeMode(QtGui.QHeaderView.Stretch) # table.horizontalHeader().setSectionResizeMode(QtGui.QHeaderView.ResizeToContents) vh = table.verticalHeader() if vh.length() > 0: try: vh.setSectionResizeMode(vh.ResizeToContents) except AttributeError: # PyQt4 hh.setResizeMode(vh.ResizeToContents) return table def build_widgets(self, values, show_labels=False, width=240, height=20, value_width=120): widgets_matrix = [] for row in values: widgets_row = [] for cell in row: cell_frame = self.create_frame_with_gridlayout() cell_frame.itemClicked.connect(self.onItemClicked) count = 0 for synoptic in sorted(cell): self.debug("processing synoptic %s" % synoptic) name = model = synoptic self.debug('Creating TaurusValue with model = %s' % model) synoptic_value = TaurusValue(cell_frame) self.modelsQueue.put((synoptic_value, model)) if self.hideLabels: synoptic_value.setLabelWidgetClass(None) else: # DO NOT DELETE THIS LINE!!! synoptic_value.setLabelConfig('label') cell_frame.layout().addWidget(synoptic_value, count, 0) self._widgets_list.append(synoptic_value) count += 1 widgets_row.append(cell_frame) widgets_matrix.append(widgets_row) return widgets_matrix def onItemClicked(self, item_name): self.trace('In TaurusGrid.itemClicked(%s)' % item_name) self.setItemSelected(item_name) self.itemClicked.emit(str(item_name)) def setItemSelected(self, item_name='', selected=True): """ it adds a blue frame around a clicked item. """ if isinstance(item_name, TaurusValue): self.trace('In TaurusGrid.setItemSelected(%s,%s)' % (str(item_name.getModel()), selected)) item = item_name else: self.trace('In TaurusGrid.setItemSelected(%s,%s)' % (str(item_name), selected)) if item_name: item = self.getItemByModel(item_name) else: item = self._last_selected if item: if selected: item._labelWidget.setStyleSheet( 'border-style: solid ; border-width: 1px; border-color: blue; color: blue; border-radius:4px;' ) if self._last_selected and self._last_selected != item: self.setItemSelected(self._last_selected, False) self._last_selected = item else: item._labelWidget.setStyleSheet( 'border-style: solid; border-width: 1px; border-color: transparent; color: black; border-radius:4px;' ) self._last_selected = None else: return None def getItemByModel(self, model, index=0): # a particular model can be many times, index means which one of them model = str(model).lower() for widget in self._widgets_list: if str(widget.getModel()).lower() == model: if index <= 0: return widget else: index -= 1 @classmethod def getQtDesignerPluginInfo(cls): ret = TaurusBaseWidget.getQtDesignerPluginInfo() ret['module'] = 'taurus.qt.qtgui.table' ret['group'] = 'Taurus Views' ret['icon'] = "designer:grid.png" return ret
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 as e: self.traceback() #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusBaseWidget over writing methods #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def setModel(self, model): 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) def sizeHint(self): return QtGui.QTableWidget.sizeHint(self) def minimumSizeHint(self): return QtGui.QTableWidget.minimumSizeHint(self) def getModelClass(self): return TaurusDevice @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) useParentModel = QtCore.pyqtProperty("bool", TaurusBaseWidget.getUseParentModel, TaurusBaseWidget.setUseParentModel, TaurusBaseWidget.resetUseParentModel) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # My methods #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @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: 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, string_types): # 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() # Signals @todo # Commented as it didn't work really well (many pop-ups open!) # QtCore.QObject.connect(self,QtCore.SIGNAL("cellDoubleClicked(int,int)"),self.valueDoubleClicked) # QtCore.QObject.connect(self,QtCore.SIGNAL("cellChanged(int,int)"),self.valueChanged) 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: try: hh.setSectionResizeMode(hh.ResizeToContents) except AttributeError: # PyQt4 hh.setResizeMode(hh.ResizeToContents) def updateStyle(self): self.resizeRowsToContents() hh = self.horizontalHeader() if hh.length() > 0: try: hh.setSectionResizeMode(hh.ResizeToContents) except AttributeError: # PyQt4 hh.setResizeMode(hh.ResizeToContents) # self.resizeColumnsToContents() def contextMenuEvent(self, event): ''' This function is called when right clicking on qwt plot area. A pop up menu will be shown with the available options. ''' self.info('TaurusPropTable.contextMenuEvent()') menu = Qt.QMenu(self) configDialogAction = menu.addAction("Add new property") configDialogAction.triggered.connect(self.addProperty) configDialogAction = menu.addAction("Delete property") configDialogAction.triggered.connect(self.deleteProperty) configDialogAction = menu.addAction("Edit property") configDialogAction.triggered.connect(self.editProperty) menu.addSeparator() menu.exec_(event.globalPos()) del menu 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. def valueDoubleClicked(self, x, y): self.info('TaurusPropTable.valueDoubleClicked(%s,%s)' % (x, y)) # opens a dialog for multiline edition self.editProperty() #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # @name Property Edition # @{ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- 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) 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) 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) 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 #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def get_device_property_names(self, dev_name, wildcard='*'): return self.db.get_device_property_list(dev_name, wildcard) def put_device_property(self, dev_name, dict): return self.db.put_device_property(dev_name, dict) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # @name DEPRECATED METHODS # @{ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- 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) 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], string_types): value = value[0] if isinstance(value, string_types): # 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
return TaurusDevice @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) useParentModel = QtCore.pyqtProperty("bool", TaurusBaseWidget.getUseParentModel, TaurusBaseWidget.setUseParentModel, TaurusBaseWidget.resetUseParentModel) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # My methods #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @QtCore.pyqtSlot('QString') def setTable(self, dev_name): """ Fills the table with the names of properties and their values for the
try: if tv and tv.unitsWidget: if boolean: tv.unitsWidget().show() else: tv.unitsWidget().hide() except: pass return self._show_attr_units #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- model = QtCore.pyqtProperty("QStringList", getModel, setModel, resetModel) rowlabels = QtCore.pyqtProperty("QString", getRowLabels, setRowLabels, resetRowLabels) columnlabels = QtCore.pyqtProperty("QString", getColumnLabels, setColumnLabels, resetColumnLabels) useParentModel = QtCore.pyqtProperty("bool", TaurusBaseWidget.getUseParentModel, TaurusBaseWidget.setUseParentModel, TaurusBaseWidget.resetUseParentModel)
return QtCore.QSize(300, 150) def getCommand(self): return self._command @QtCore.pyqtSignature("setCommand(QString)") def setCommand(self, value): self._command = value self._restartTheProcess() def resetCommand(self): self.setCommand("") command = QtCore.pyqtProperty( "QString", getCommand, setCommand, resetCommand, doc='The command to be executed within the XTerm') def getFontSize(self): return self._fontSize @QtCore.pyqtSignature("setFontSize(int)") def setFontSize(self, value): self._fontSize = value self._restartTheProcess() def resetFontSize(self): self.setFontSize(7) def destroy(self, destroyWindow=True, destroySubWindows=True):
def getModelClass(self): return TaurusDevice @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) useParentModel = QtCore.pyqtProperty("bool", TaurusBaseWidget.getUseParentModel, TaurusBaseWidget.setUseParentModel, TaurusBaseWidget.resetUseParentModel) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # My methods #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @QtCore.pyqtSlot('QString') def setTable(self, dev_name): """ Fills the table with the names of properties and their values for the given device.