Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
        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
Ejemplo n.º 4
0
            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)
Ejemplo n.º 5
0
        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):
Ejemplo n.º 6
0
    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.