def setData(self, index, qvalue): taurus_role = index.model().role(index.column()) str_value = Qt.from_qvariant(qvalue, str) if taurus_role in (ChannelView.Channel, ChannelView.Conditioning, ChannelView.NXPath, ChannelView.DataType) : data = str_value elif taurus_role in (ChannelView.Enabled, ChannelView.Output) : data = Qt.from_qvariant(qvalue, bool) elif taurus_role == ChannelView.PlotType: data = PlotType[str_value] elif taurus_role == ChannelView.Normalization: data = Normalization[str_value] elif taurus_role == ChannelView.PlotAxes: data = [a for a in str_value.split(':')] elif taurus_role == ChannelView.Shape: s = str_value try: data = eval(s, {}, {}) if not isinstance(data, (tuple, list)): raise ValueError except: from taurus.core.util.log import Logger Logger(self.__class__.__name__).error('Invalid shape %s', s) data = () else: raise NotImplementedError('Unknown role') ch_name, ch_data = self.itemData() key = self.itemdata_keys_map[taurus_role] ch_data[key] = data
def _onEditDisplay(self): selected = self.selectionModel().selectedIndexes() if len(selected) == 1: idx = selected[0] else: return value = Qt.from_qvariant(self._model.data( idx, role=Qt.Qt.DisplayRole), str) src = Qt.from_qvariant(self._model.data(idx, role=SRC_ROLE), str) value, ok = Qt.QInputDialog.getText( self, "Display Value", "Display value for %s?" % src, Qt.QLineEdit.Normal, value) if not ok: return self._model.setData(idx, Qt.QVariant(value), role=Qt.Qt.DisplayRole)
def setData(self, index, value, role=Qt.Qt.DisplayRole): '''see :meth:`Qt.QAbstractTableModel.setData`''' idx_data_str = Qt.from_qvariant(index.data(), str) value_str = Qt.from_qvariant(value, str) if idx_data_str == value_str: return False #self.itemFromIndex(index).setData(value, role) try: self.valueChanged(value_str, index) except: self.showError.emit('Wrong value!', 'The value you entered is wrong. The old value will be restored.') return Qt.QStandardItemModel.setData(self, index, index.data(), role) return Qt.QStandardItemModel.setData(self, index, value, role)
def setEditorData(self, editor, index): if index.column() == 1: text = Qt.from_qvariant(index.model().data(index, Qt.Qt.DisplayRole), str) if text in ["None", "", None]: Qt.QItemDelegate.setEditorData(self, editor, index) else: node = index.model().mapToSource(index).internalPointer() paramType = node.type() if paramType in globals.EDITOR_COMBOBOX_PARAMS : i = editor.findText(text) if i == -1: i = 0 else: editor.previous = text editor.setCurrentIndex(i) elif paramType in globals.EDITOR_SPINBOX_PARAMS: editor.setValue(int(text)) elif paramType in globals.EDITOR_DOUBLESPINBOX_PARAMS: editor.setValue(float(text)) elif paramType in globals.EDITOR_LINEEDIT_PARAMS: editor.setText(text) elif paramType in globals.EDITOR_FILEDIALOG_PARAMS: editor.filePath.setText(text) else: Qt.QItemDelegate.setEditorData(self, editor, index)
def setData(self, index, qvalue, role=Qt.Qt.EditRole): #For those things which are at the unit level, we handle them here taurus_role = self.role(index.column()) if taurus_role in (ChannelView.Timer, ChannelView.Monitor, ChannelView.Trigger): ch_name, ch_data = index.internalPointer().itemData() ch_info = self.getAvailableChannels()[ch_name] unit_data = self.getPyData(ctrlname=ch_data['_controller_name'], unitid=ch_data['_unit_id']) key = self.data_keys_map[taurus_role] data = Qt.from_qvariant(qvalue, str) self._dirty = True self.beginResetModel() is_settable = ch_info['type'] in ('CTExpChannel', 'OneDExpChannel', 'TwoDExpChannel') if taurus_role == ChannelView.Trigger: data = AcqTriggerType[data] if is_settable: unit_data[key] = data else: if is_settable: if unit_data[key] == self._mgconfig[key]: self._mgconfig[key] = data unit_data[key] = data else: self._mgconfig[key] = data self.endResetModel() return True #for the rest, we use the regular TaurusBaseModel item-oriented approach #ret = self._setData(index, qvalue, role) #@todo we do not use _setData because it is not Qt4.4-compatible item = index.internalPointer() item.setData(index, qvalue) self._dirty = True self.emit(Qt.SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"), index, index) return True
def getModifiedWriteData(self): ''' returns an array for the write data that includes the user modifications :return: (numpy.array) The write values including user modifications. ''' table = self._wtabledata kind = table.dtype.kind if kind in 'SU': table = table.tolist() # we want to allow the strings to be larger than the original ones for (r, c), v in self._modifiedDict.items(): table[r][c] = Qt.from_qvariant(v, str) table = numpy.array(table, dtype=str) else: for k, v in self._modifiedDict.items(): if kind in ['f', 'i', 'u']: units = self._parent.getCurrentUnits() q = _value2Quantity(v, units) table[k] = q elif kind == 'b': # TODO: This does not work Qt.from_qvariant(v, bool) if str(v) == "true": table[k] = True else: table[k] = False else: raise TypeError('Unknown data type "%s"' % kind) # reshape if needed if self._attr.data_format == DataFormat._1D: table = table.flatten() return table
def _create_multi_selection_panel(self, input_data): panel = self._create_group_panel(input_data) layout = panel.layout() items = input_data['data_type'] default_value = input_data.get('default_value') if default_value is None: default_value = () dft_is_seq = not isinstance(default_value, (str, unicode)) and \ isinstance(default_value, collections.Sequence) if not dft_is_seq: default_value = default_value, self._ui.inputWidget = listwidget = Qt.QListWidget() listwidget.setSelectionMode(Qt.QAbstractItemView.MultiSelection) for item in items: is_seq = not isinstance(item, (str, unicode)) and \ isinstance(item, collections.Sequence) if is_seq: text, userData = item else: text, userData = str(item), item item_widget = Qt.QListWidgetItem(text, listwidget) item_widget.setData(Qt.Qt.UserRole, Qt.to_qvariant(userData)) if userData in default_value: item_widget.setSelected(True) layout.addWidget(listwidget) return panel, self._get_multi_selection_value
def getValue(self): """ Get the value that the widget is displaying now, not the value of the attribute. """ model = self.getModelObj() if model is None: return None dtype = model.type new_value = self.itemData(self.currentIndex()) if new_value is None: return None if dtype == DataType.Integer: func = int elif dtype == DataType.Float: func = float elif dtype == DataType.String: func = str elif dtype == DataType.Boolean: func = bool else: return None new_value = Qt.from_qvariant(new_value, func) return new_value
def valueChanged(self, value, index): ''' Modifies value in the temporary settings file and the model internal dictionary. Invoked by :meth:`Qt.QAbstractTableModel.setData`, when user make changes to the value in the settings tree. :param value: (str) the new value (a string that will be python-evaluated) :param index: (QModelIndex) index of the model ''' changedItem = self.itemFromIndex(index) path = Qt.from_qvariant(changedItem.data(Qt.Qt.UserRole), str) self._configurationDictionaries = self.changeTreeValue( self._configurationDictionaries, path, value) try: group = eval(str(path).split(';', 1)[0]) except: group = str(path).split(';', 1)[0] itemToMark = self.itemFromIndex(index.sibling(index.row(), 0)) self.markedItems.append(itemToMark.index()) self.itemFromIndex(index.sibling(index.row(), 1) ).setText(str(type(eval(value)))) changedItem.setData(Qt.QVariant( 'Value has been changed. Old value: ' + str(changedItem.text())), Qt.Qt.ToolTipRole) itemToMark.setData(Qt.QVariant(Qt.QIcon.fromTheme('emblem-important')), Qt.Qt.DecorationRole) while(itemToMark is not None): itemToMark.setData(Qt.QVariant( Qt.QFont("Arial", 10, Qt.QFont.Bold)), Qt.Qt.FontRole) itemToMark = self.itemFromIndex(itemToMark.index().parent()) self.saveSettings(group)
def deleteBranch(self): ''' Deletes selected branch from the settings tree. Also updates the temporary configuration file. ''' tmpindex = self._toDeleteIndex item = self.itemFromIndex(tmpindex) path = Qt.from_qvariant(item.data(Qt.Qt.UserRole), str) self._delete = False self._configurationDictionaries = self.removeBranch( self._configurationDictionaries, path) try: group = eval(str(path).split(';', 1)[0]) except: group = str(path).split(';', 1)[0] itemToMark = self.itemFromIndex(tmpindex.parent()) while(itemToMark is not None): itemToMark.setData(Qt.QVariant( Qt.QFont("Arial", 10, Qt.QFont.Bold)), Qt.Qt.FontRole) itemToMark = self.itemFromIndex(itemToMark.index().parent()) self.markedItems.append(self._toDeleteIndex.parent()) self.removeRow(tmpindex.row(), tmpindex.parent()) self.saveSettings(group)
def set_property_methods(obj, name, type_="QString", default=None, getter=None, setter=None, reset=None, get_callback=None, set_callback=None, reset_callback=None, qt=False, config=False): """ This method allows to add QProperties dynamically with calls like: <pre> set_property_methods(self,'Filters','QString',default='', set_callback=lambda s=self:s.loadTree(s.getFilters(),clear=True), reset_callback=lambda s=self:s.loadTree('',clear=True) ) </pre> @TODO: This method should be refactored using python descriptors/properties and types.MethodType """ klass = obj.__class__ mname = '%s%s' % (name[0].upper(), name[1:]) lname = '%s%s' % (name[0].lower(), name[1:]) getter = getter or (lambda o=obj, n=name, c=get_callback: get_property( o, n, c)) # partial(get_property,name=name,callback=get_callback) setter = setter or (lambda x, y=None, o=obj, d=default, n=name, c=set_callback: set_property( o, n, x if x is not obj else y, c)) # partial(set_property),name=name,callback=set_callback) reset = reset or (lambda o=obj, n=name, d=default, c=reset_callback: reset_property( o, n, d, c)) # partial(reset_property,name=name,default=default,callback=reset_callback) setattr(obj, 'set%s' % mname, setter) setattr(obj, 'get%s' % mname, getter) setattr(obj, 'reset%s' % mname, reset) if qt: setattr(klass, lname, Qt.pyqtProperty( "QString", getter, setter, reset)) if config: obj.registerConfigProperty(getter, setter, name) reset()
def mimeData(self, indexes): mimedata = Qt.QAbstractTableModel.mimeData(self, indexes) if len(indexes) == 1: # txt = Qt.from_qvariant(self.data(indexes[0], str) # mimedata.setData(TAURUS_ATTR_MIME_TYPE, txt) txt = Qt.from_qvariant(self.data(indexes[0], role=SRC_ROLE), str) mimedata.setText(txt) return mimedata
def _setData(self, index, qvalue, role=QtQt.EditRole): item = index.internalPointer() pyobj = Qt.from_qvariant(qvalue) if pyobj is NotImplemented: self.warning( "Failed attempt to convert a QValue. Maybe it is due to Qt<4.6") item.setData(index, pyobj) return True
def onItemChanged(self, item): """slot used when an item data has changed""" name = Qt.from_qvariant(item.data(self.NAME_ROLE), str) previousTitle = self.curvePropDict[name].title currentTitle = item.text() if previousTitle != currentTitle: self.curvePropDict[name].title = currentTitle self.CurveTitleEdited.emit(name, currentTitle)
def setData (self, index, value, role=Qt.Qt.EditRole): node = self.nodeFromIndex(index) # if index.isValid() and 0 <= index.row() < len(node.parent()): if index.column() == 1: node.setValue(Qt.from_qvariant(value, str)) self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) return True return False
def mimeData(self, indexes): '''reimplemented from :class:`Qt.QAbstractListModel`''' mimedata = Qt.QAbstractListModel.mimeData(self, indexes) if len(indexes) == 1: # mimedata.setData(TAURUS_ATTR_MIME_TYPE, # Qt.from_qvariant(self.data(indexes[0]), str))) txt = Qt.from_qvariant(self.data(indexes[0], role=SRC_ROLE), str) mimedata.setText(txt) return mimedata
def setEditorData(self, editor, index): ''' see :meth:`Qt.QStyledItemDelegate.setEditorData` ''' if index.model().editedIndex == (index.row(), index.column()): return index.model().editedIndex = (index.row(), index.column()) self._initialText = None if index.model().getType() == bool: editor.addItems(['true', 'false']) a = str(Qt.from_qvariant(index.data(), bool)).lower() self._initialText = a editor.setCurrentIndex(editor.findText(a)) else: data = index.model().data(index, Qt.Qt.EditRole) self._initialText = Qt.from_qvariant(data, str) editor.setText(str(self._initialText))
def setEditorData(self, editor, index): model = index.model() dataSource = model.dataSource() taurus_role = model.role(index.column()) if taurus_role == ChannelView.PlotType: editor.addItems(PlotType.keys()) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentIndex(editor.findText(current)) elif taurus_role == ChannelView.Normalization: editor.addItems(Normalization.keys()) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentIndex(editor.findText(current)) elif taurus_role in (ChannelView.Timer, ChannelView.Monitor): key = taurus_role == ChannelView.Timer and 'timer' or 'monitor' ch_name, ch_data = index.internalPointer().itemData() ctrl_filterlist = [ch_data['_controller_name']] ctrl_dict = getChannelConfigs(dataSource, ctrls=ctrl_filterlist) all_channels = model.getAvailableChannels() # if it is a timer capable type of element if all_channels[ch_name]['type'] in ('CTExpChannel', 'OneDExpChannel', 'TwoDExpChannel'): for full_name, channel_data in ctrl_dict: editor.addItem(channel_data['name'], Qt.QVariant(full_name)) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentIndex(editor.findText(current)) else: for ctrl_data in dataSource['controllers'].values(): for unit_data in ctrl_data['units'].values(): if key in unit_data: channel = all_channels[unit_data[key]] editor.addItem(channel['name'], Qt.QVariant(channel['full_name'])) current = dataSource.get(key) # current global timer/monitor editor.setCurrentIndex(editor.findData(Qt.QVariant(current))) elif taurus_role == ChannelView.Trigger: editor.addItems(AcqTriggerType.keys()) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentIndex(editor.findText(current)) elif taurus_role == ChannelView.PlotAxes: selectables = ['<idx>', '<mov>'] + [n for n, d in getChannelConfigs(dataSource)] editor.setChoices(selectables) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentChoices(current) else: Qt.QStyledItemDelegate.setEditorData(self, editor, index)
def getSelectedCurveNames(self): """Returns the curve names for the curves selected at the curves list. *Note*: The names may differ from the displayed text, which corresponds to the curve titles (this method is what you likely need if you want to get keys to use in curves or curveProp dicts). :return: (string_list) the names of the selected curves """ return [Qt.from_qvariant(item.data(self.NAME_ROLE), str) for item in self.curvesLW.selectedItems()]
def setData(self, index, value=None, role=Qt.Qt.EditRole): if index.isValid() and (0 <= index.row() < self.rowCount()): row = index.row() column = index.column() value = Qt.from_qvariant(value, str) if column == 0: self.__columns[row]['label'] = value elif column == 1: self.__columns[row]['model'] = value elif column == 2: self.__columns[row]['instrument'] = value self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) return True return False
def setData (self, index, value, role=Qt.Qt.EditRole): node = self.nodeFromIndex(index) if index.column() == 1: if isinstance(node, macro.SingleParamNode): node.setValue(Qt.from_qvariant(value, str)) self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) while True: index = index.parent() node = self.nodeFromIndex(index) if isinstance(node, macro.MacroNode): self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index.sibling(index.row(), self.columnCount(index) - 1)) break elif index.column() == 2: progress = Qt.from_qvariant(value, float) node.setProgress(progress) self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) elif index.column() == 3: node.setPause(Qt.from_qvariant(value, bool)) self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) return True
def setData(self, index, value=None, role=Qt.Qt.EditRole): '''reimplemented from :class:`Qt.QAbstractListModel`''' if index.isValid() and (0 <= index.row() < self.rowCount()): row = index.row() item = self.items[row] value = Qt.from_qvariant(value, unicode) if role == Qt.Qt.EditRole: item.src = value elif role == Qt.Qt.DisplayRole: item.display = value self.dataChanged.emit(index, index) return True return False
def contextMenuEvent(self, event): '''Reimplemented from :meth:`QWidget.contextMenuEvent`''' self.tree._toDeleteIndex = self.treeview.selectedIndexes()[0] text = Qt.from_qvariant(self.tree._toDeleteIndex.data(), str) if self.tree._toDeleteIndex.column() in [1, 2] or text in ['LAST', '[custom]'] or text in self.tree.perspectives: return menu = Qt.QMenu() menu.addAction(Qt.QIcon.fromTheme('process-stop'), "Delete branch: " + text, self.tree.deleteBranch) menu.addSeparator() menu.addAction(Qt.QIcon.fromTheme('help-browser'), "Help") menu.exec_(event.globalPos()) event.accept()
def _onReportTriggered(self, index): report_handlers = get_report_handlers() combo = self.reportComboBox() name = Qt.from_qvariant(combo.itemData(index), str) report_handler = report_handlers[name] report = report_handler(self) app = Qt.QApplication.instance() txt = _REPORT.format( appName=app.applicationName(), appVersion=app.applicationVersion(), time=datetime.datetime.now().ctime(), text=self.getText(), detail=self.getDetailedText(), origin=self.getOriginText(), ) report.report(txt)
def getTaurusConfigFromSettings(self, key='TaurusConfig'): ''' Loads and returns the configuration dictionary from the settings file using pickle module. :param key: (str) :returns (dict) ''' result = None qstate = Qt.from_qvariant(self._settings.value(key), 'toByteArray') if qstate is not None and not qstate.isNull(): try: result = pickle.loads(qstate.data()) except Exception, e: msg = 'problems loading TaurusConfig: \n%s' % repr(e) Qt.QMessageBox.critical(None, 'Error loading settings', msg)
def setData(self, index, value=None, role=Qt.Qt.EditRole): if index.isValid() and (0 <= index.row() < self.rowCount()): row = index.row() curve = self.curves[row] column = index.column() value = Qt.from_qvariant(value, str) if column == X: curve.taurusparam.xModel = value curve.x.processSrc(value) elif column == Y: curve.taurusparam.yModel = value curve.y.processSrc(value) elif column == TITLE: curve.curveparam.label = value self.dataChanged.emit(index, index) return True return False
def sizeHint(self, option, index): if index.column() == 0: fm = option.fontMetrics text = Qt.from_qvariant(index.model().data(index, Qt.Qt.DisplayRole), str) document = Qt.QTextDocument() document.setDefaultFont(option.font) document.setHtml(text) size = Qt.QSize(document.idealWidth() + 5, fm.height()) elif index.column() == 1: editor = self.createEditor(self.parent(), option, index) if editor is None: size = Qt.QItemDelegate.sizeHint(self, option, index) else: size = editor.sizeHint() editor.hide() editor.setParent(None) # editor.destroy() else: size = Qt.QItemDelegate.sizeHint(self, option, index) return size
def setEditorData(self, editor, index): if index.column() == 1: text = Qt.from_qvariant(index.model().data(index, Qt.Qt.DisplayRole), str) if text == "None" or text == "" or text is None: Qt.QStyledItemDelegate.setEditorData(self, editor, index) else: editor.setValue(text) # node = index.model().nodeFromIndex(index) # paramType = node.type() # if paramType in globals.EDITOR_COMBOBOX_PARAMS : # editor.setValue(text) # elif paramType in globals.EDITOR_SPINBOX_PARAMS: # editor.setValue(int(text)) # elif paramType in globals.EDITOR_DOUBLESPINBOX_PARAMS: # editor.setValue(float(text)) # elif paramType in globals.EDITOR_LINEEDIT_PARAMS: # editor.setText(text) # elif paramType in globals.EDITOR_FILEDIALOG_PARAMS: # editor.filePath.setText(text) else: Qt.QStyledItemDelegate.setEditorData(self, editor, index)
def calculate(self): db = self.getModelObj() if db is None: return g_layout = self.layout() filters = [] for i in xrange(1, g_layout.count() - 1): field_layout = g_layout.itemAt(i).widget().layout() comboBox = field_layout.itemAt(1).widget() edit = field_layout.itemAt(2).widget() type = Qt.from_qvariant(comboBox.itemData(comboBox.currentIndex())) expr = str(edit.text()) f = getFilter(type, expr) filters.append(f) finalType = self.getHeaderType() filters.append(getFilter(finalType)) return filters
def setData(self, index, value=None, role=Qt.Qt.EditRole): if index.isValid() and (0 <= index.row() < self.rowCount()): row = index.row() curve = self.curves[row] if role == PROPS_ROLE: self.curves[row].properties = value self.dataChanged.emit(self.index( row, 0), self.index(row, self.ncolumns - 1)) else: column = index.column() value = Qt.from_qvariant(value, unicode) if column == X: curve.x.setSrc(value) elif column == Y: curve.y.setSrc(value) elif column == TITLE: curve.title = value elif column == VIS: curve.vis = value self.dataChanged.emit(index, index) return True return False
def data(self, index, role=Qt.Qt.DisplayRole): if not index.isValid() or not (0 <= index.row() < self.rowCount()): return Qt.QVariant() row = index.row() column = index.column() # Display Role if role == Qt.Qt.DisplayRole: if column == X: return Qt.QVariant(str(self.curves[row].x.display)) elif column == Y: return Qt.QVariant(str(self.curves[row].y.display)) elif column == TITLE: return Qt.QVariant(str(self.curves[row].curveparam.label)) else: return Qt.QVariant() elif role == Qt.Qt.DecorationRole: if column == X: return Qt.QVariant(self.curves[row].x.icon) elif column == Y: return Qt.QVariant(self.curves[row].y.icon) else: return Qt.QVariant() elif role == Qt.Qt.TextColorRole: if column == X: Qt.QVariant( Qt.QColor(self.curves[row].x.ok and 'green' or 'red')) elif column == Y: Qt.QVariant( Qt.QColor(self.curves[row].y.ok and 'green' or 'red')) else: return Qt.QVariant() elif role == SRC_ROLE: if column == X: return Qt.QVariant(str(self.curves[row].taurusparam.xModel)) elif column == Y: return Qt.QVariant(str(self.curves[row].taurusparam.yModel)) else: return Qt.QVariant() elif role == Qt.Qt.ToolTipRole: if column == X: return Qt.QVariant(str(self.curves[row].taurusparam.xModel)) elif column == Y: return Qt.QVariant(str(self.curves[row].taurusparam.yModel)) else: return Qt.QVariant() if role == Qt.Qt.EditRole: if column == X: return Qt.QVariant(str(self.curves[row].taurusparam.xModel)) elif column == Y: return Qt.QVariant(str(self.curves[row].taurusparam.yModel)) elif column == TITLE: return Qt.QVariant(str(self.curves[row].curveparam.label)) else: return Qt.QVariant() return Qt.QVariant()
Qt.QWidget.__init__(self, parent) self.loadUi() self.ui.comboBox_begin.addItem(str2localtime("-1d")) self.ui.comboBox_end.addItem(str2localtime(time.time())) def getTimes(self): t0 = str2localtime(self.ui.comboBox_begin.currentText()) t1s = self.ui.comboBox_end.currentText() # if not absolute time if self._ts_re.match(t1s) is None: t1s = t1s.replace('now', '{}'.format(time.time() - str2time(t0))) t1s = str2time(t0) + str2time(t1s) t1 = str2localtime(t1s) return t0, t1 if __name__ == '__main__': from taurus.qt.qtgui.application import TaurusApplication import sys app = TaurusApplication() button = Qt.QPushButton("Press me") w = TangoArchivingTimeSelector() def p_getTimes(): print(w.getTimes()) button.pressed.connect(p_getTimes) w.ui.horizontalLayout.addWidget(button) w.show() sys.exit(app.exec_())
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, 'w') 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) 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
def validateAllExpresion(self, secValidation=False): # This method is responsible for full validation of the macro. It is executed whenever the text is changed (when user edits values). # Validation starts with checking if the macro (name) is valid. # Next steps: # 1. Validates every SingleParamNode and counts how many there are in the macro. # 2. If there are more SingleParamNodes than entered values it will check if there is RepeatParamNode. # If there is RepeatParamNode it will check if its RepeatNodes can be deleted. # 3. If there are more values entered than SingleParamNodes in macro it will check if there is RepeatParamNode. # If there is it will try to add new RepeatNode. if self.model() is None: raise RuntimeError( 'Door must be set in order to use the macroexecutor.') self.currentIndex = Qt.QModelIndex() mlist = str(self.text()).split() problems = [] try: if str(mlist[0]) != str(self.model().root().name()): try: self.getModelObj().validateMacroName(str(mlist[0])) self.validateMacro(mlist[0]) self.updateMacroEditor(mlist[0]) if not secValidation: self.validateAllExpresion(True) except Exception as e: if self.disableEditMode: self.updateMacroEditor(mlist[0]) raise Exception(e) message = e.args[0] #raise Exception(e) problems.append(message) except IndexError: problems.append("<b>Macro<\b> is missing!") self.setStyleSheet("") self.setToolTip('<br>'.join(problems)) return self.currentIndex = Qt.QModelIndex() ix = self.getIndex() self.currentIndex = ix counter = 1 while not ix == Qt.QModelIndex(): try: propValue = mlist[counter] try: self.validateOneValue(propValue) self.model().setData(self.currentIndex, propValue) except Exception as e: self.model().setData(self.currentIndex, 'None') txt = str(ix.sibling(ix.row(), 0).data()) message = "<b>" + txt + "</b> " + e.args[0] problems.append(message) except IndexError: txt = str(ix.sibling(ix.row(), 0).data()) problems.append("<b>" + txt + "</b> is missing!") data = str(ix.data()) if data != 'None': self.model().setData(self.currentIndex, 'None') else: self.model().setData(self.currentIndex, None) counter += 1 ix = self.getIndex() self.currentIndex = ix if len(mlist) > counter: # if there are more values than parameters repeatNode = None for i in self.model().root().params(): repeatNode = i if isinstance(repeatNode, macro.RepeatParamNode): index = self.findParamRepeat(i) self.currentIndex = self.model()._insertRow(index) nn = self.model().nodeFromIndex(self.currentIndex) self.expandTree.emit() ix = self.getIndex() if not secValidation: self.validateAllExpresion(True) return repeatNode = None if repeatNode is None: problems.append("Too many values.") elif counter - len(mlist) >= 1: repeatNode = None node = None for i in self.model().root().params(): repeatNode = i if isinstance(repeatNode, macro.RepeatParamNode): index = self.findParamRepeat(i) node = self.model().nodeFromIndex(index) sub = len(node.child(0)) break repeatNode = None if repeatNode is not None: while counter - len(mlist) > sub - 1: if len(node.children()) == 1 and node.isReachedMin(): break self.model()._removeRow(index.child(len(node.children()) - 1, 0)) counter -= sub if not secValidation: self.validateAllExpresion(True) return if len(problems) == 0: self.setStyleSheet('SpockCommandWidget {background-color: %s; color: %s; border: %s; border-radius: %s}' % ( 'yellow', 'black', '3px solid green', '5px')) self.setToolTip("") else: self.setStyleSheet("") self.setToolTip('<br>'.join(problems)) return
def _colorIcon(self, color, w=10, h=10): # to do: create a border pixmap = Qt.QPixmap(w, h) pixmap.fill(Qt.QColor(color)) return Qt.QIcon(pixmap)
class TaurusSequencerWidget(TaurusWidget): doorChanged = Qt.pyqtSignal('QString') macroStarted = Qt.pyqtSignal('QString') plotablesFilterChanged = Qt.pyqtSignal(compat.PY_OBJECT) currentMacroChanged = Qt.pyqtSignal(compat.PY_OBJECT) macroNameChanged = Qt.pyqtSignal('QString') shortMessageEmitted = Qt.pyqtSignal('QString') sequenceEmpty = Qt.pyqtSignal() comment_characters = ('#',) def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) # list representing all macros ids (all from sequence) currently # executed self._macroIds = [] self._sequencesPath = str(Qt.QDir.homePath()) self._sequenceModel = MacroSequenceTreeModel() self.registerConfigProperty( "sequencesPath", "setSequencesPath", "sequencesPath") self.setLayout(Qt.QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) splitter = Qt.QSplitter() self.layout().addWidget(splitter) splitter.setOrientation(Qt.Qt.Vertical) self.sequenceEditor = TaurusWidget() splitter.addWidget(self.sequenceEditor) self.sequenceEditor.setLayout(Qt.QVBoxLayout()) self.sequenceEditor.layout().setContentsMargins(0, 0, 0, 0) self.tree = MacroSequenceTree(self.sequenceEditor) self.sequenceProxyModel = MacroSequenceProxyModel() self.sequenceProxyModel.setSourceModel(self._sequenceModel) self.tree.setModel(self.sequenceProxyModel) self.tree.setItemDelegate(SequenceEditorDelegate(self.tree)) actionsLayout = Qt.QHBoxLayout() actionsLayout.setContentsMargins(0, 0, 0, 0) self.newSequenceAction = Qt.QAction( Qt.QIcon.fromTheme("document-new"), "New", self) self.newSequenceAction.triggered.connect(self.onNewSequence) self.newSequenceAction.setToolTip("New sequence") self.newSequenceAction.setEnabled(False) newSequenceButton = Qt.QToolButton() newSequenceButton.setDefaultAction(self.newSequenceAction) actionsLayout.addWidget(newSequenceButton) self.openSequenceAction = Qt.QAction( Qt.QIcon.fromTheme("document-open"), "Open...", self) self.openSequenceAction.triggered.connect(self.onOpenSequence) self.openSequenceAction.setToolTip("Open sequence...") openSequenceButton = Qt.QToolButton() openSequenceButton.setDefaultAction(self.openSequenceAction) actionsLayout.addWidget(openSequenceButton) self.saveSequenceAction = Qt.QAction( Qt.QIcon.fromTheme("document-save"), "Save...", self) self.saveSequenceAction.triggered.connect(self.onSaveSequence) self.saveSequenceAction.setToolTip("Save sequence...") self.saveSequenceAction.setEnabled(False) saveSequenceButton = Qt.QToolButton() saveSequenceButton.setDefaultAction(self.saveSequenceAction) actionsLayout.addWidget(saveSequenceButton) self.stopSequenceAction = Qt.QAction( Qt.QIcon("actions:media_playback_stop.svg"), "Stop", self) self.stopSequenceAction.triggered.connect(self.onStopSequence) self.stopSequenceAction.setToolTip("Stop sequence") stopSequenceButton = Qt.QToolButton() stopSequenceButton.setDefaultAction(self.stopSequenceAction) actionsLayout.addWidget(stopSequenceButton) self.pauseSequenceAction = Qt.QAction( Qt.QIcon("actions:media_playback_pause.svg"), "Pause", self) self.pauseSequenceAction.triggered.connect(self.onPauseSequence) self.pauseSequenceAction.setToolTip("Pause sequence") pauseSequenceButton = Qt.QToolButton() pauseSequenceButton.setDefaultAction(self.pauseSequenceAction) actionsLayout.addWidget(pauseSequenceButton) self.playSequenceAction = Qt.QAction( Qt.QIcon("actions:media_playback_start.svg"), "Play", self) self.playSequenceAction.triggered.connect(self.onPlaySequence) self.playSequenceAction.setToolTip("Play sequence") playSequenceButton = Qt.QToolButton() playSequenceButton.setDefaultAction(self.playSequenceAction) actionsLayout.addWidget(playSequenceButton) self.doorStateLed = TaurusLed(self) actionsLayout.addWidget(self.doorStateLed) #@todo this feature will be replaced by checkboxes in the # sequence tree view indicating clearing of the plot after execution self.fullSequencePlotCheckBox = Qt.QCheckBox( "Full sequence plot", self) self.fullSequencePlotCheckBox.toggled.connect(self.setFullSequencePlot) self.fullSequencePlotCheckBox.setChecked(True) actionsLayout.addWidget(self.fullSequencePlotCheckBox) spacerItem = Qt.QSpacerItem( 0, 0, Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Fixed) actionsLayout.addItem(spacerItem) self.sequenceEditor.layout().addLayout(actionsLayout) macroLayout = Qt.QHBoxLayout() macroLayout.setContentsMargins(0, 0, 0, 0) macroLabel = Qt.QLabel("Macro:") macroLayout.addWidget(macroLabel) self.macroComboBox = MacroComboBox(self) self.macroComboBox.setModelColumn(0) self.macroComboBox.setSizePolicy( Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum) macroLayout.addWidget(self.macroComboBox) self.addMacroAction = Qt.QAction( Qt.QIcon.fromTheme("list-add"), "Add macro...", self) self.addMacroAction.triggered.connect(self.onAdd) self.addMacroAction.setToolTip( "Clicking this button will add selected macro") self.addMacroAction.setEnabled(False) addButton = Qt.QToolButton() addButton.setDefaultAction(self.addMacroAction) macroLayout.addWidget(addButton) self.sequenceEditor.layout().addLayout(macroLayout) sequenceLayout = Qt.QHBoxLayout() sequenceLayout.addWidget(self.tree) layout = Qt.QVBoxLayout() delButton = Qt.QToolButton() delButton.setDefaultAction(self.tree.deleteAction) delButton.setEnabled(False) layout.addWidget(delButton) upButton = Qt.QToolButton() upButton.setDefaultAction(self.tree.moveUpAction) upButton.setEnabled(False) layout.addWidget(upButton) downButton = Qt.QToolButton() downButton.setDefaultAction(self.tree.moveDownAction) downButton.setEnabled(False) layout.addWidget(downButton) leftButton = Qt.QToolButton() leftButton.setDefaultAction(self.tree.moveLeftAction) leftButton.setEnabled(False) layout.addWidget(leftButton) rightButton = Qt.QToolButton() rightButton.setDefaultAction(self.tree.moveRightAction) rightButton.setEnabled(False) layout.addWidget(rightButton) spacerItem = Qt.QSpacerItem( 0, 40, Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Expanding) layout.addItem(spacerItem) sequenceLayout.addLayout(layout) self.sequenceEditor.layout().addLayout(sequenceLayout) self.parametersProxyModel = MacroParametersProxyModel() self.parametersProxyModel.setSourceModel(self._sequenceModel) self.stackedWidget = Qt.QStackedWidget() splitter.addWidget(self.stackedWidget) self.standardMacroParametersEditor = StandardMacroParametersEditor( self.stackedWidget) self.standardMacroParametersEditor.setModel(self.parametersProxyModel) self.standardMacroParametersEditor.tree.setItemDelegate( ParamEditorDelegate(self.standardMacroParametersEditor.tree)) self.stackedWidget.addWidget(self.standardMacroParametersEditor) self.customMacroParametersEditor = None self.macroComboBox.currentIndexChanged.connect( self.onMacroComboBoxChanged) self.tree.macroChanged.connect(self.setMacroParametersRootIndex) def contextMenuEvent(self, event): menu = Qt.QMenu() menu.addAction(Qt.QIcon.fromTheme("view-refresh"), "Check door state", self.checkDoorState) menu.exec_(event.globalPos()) def checkDoorState(self): """Method used by "Check door state" action (available in the context menu). It is a workaround for situations when the event notification about the macro status does not reach the sequencer widget.""" door = Device(self.doorName()) doorState = door.getState() if doorState == PyTango.DevState.RUNNING: self.playSequenceAction.setEnabled(False) self.pauseSequenceAction.setEnabled(True) self.stopSequenceAction.setEnabled(True) elif doorState in (PyTango.DevState.ON, PyTango.DevState.ALARM): self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(False) elif doorState == PyTango.DevState.STANDBY: self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(True) def doorName(self): return self._doorName def setDoorName(self, doorName): self._doorName = doorName def firstMacroId(self): return self._firstMacroId def setFirstMacroId(self, firstMacroId): self._firstMacroId = firstMacroId def lastMacroId(self): return self._lastMacroId def setLastMacroId(self, lastMacroId): self._lastMacroId = lastMacroId def macroIds(self): return self._macroIds def setMacroIds(self, macroIds): self._macroIds = macroIds def emitExecutionStarted(self): return self._emitExecutionStarted def setEmitExecutionStarted(self, yesNo): self._emitExecutionStarted = yesNo def sequencesPath(self): return self._sequencesPath def setSequencesPath(self, sequencesPath): self._sequencesPath = sequencesPath def isFullSequencePlot(self): return self._fullSequencePlot def setFullSequencePlot(self, fullSequencePlot): self._fullSequencePlot = fullSequencePlot def onNewSequence(self): if Qt.QMessageBox.question(self, "New sequence", "Do you want to save existing sequence?", Qt.QMessageBox.Yes, Qt.QMessageBox.No) == Qt.QMessageBox.Yes: self.onSaveSequence() self.tree.clearTree() self.newSequenceAction.setEnabled(False) self.saveSequenceAction.setEnabled(False) self.currentMacroChanged.emit(None) def loadFile(self, fileName): if fileName == "": return #@todo: reset macroComboBox to index 0 try: file = open(fileName, 'r') string = file.read() if fileName.endswith('.xml'): root = self.fromXmlString(string) else: root = self.fromPlainText(string) self._sequenceModel.setRoot(root) self.sequenceProxyModel.invalidateFilter() self.tree.expandAll() self.tree.expanded() self.parametersProxyModel.setMacroIndex(None) self.parametersProxyModel.invalidateFilter() if not self._sequenceModel.isEmpty(): self.newSequenceAction.setEnabled(True) self.saveSequenceAction.setEnabled(True) self.playSequenceAction.setEnabled(True) except IOError: Qt.QMessageBox.warning( self, "Error while loading macros sequence", "There was a problem while reading from file: %s" % fileName) file = None self.tree.clearTree() self.newSequenceAction.setEnabled(False) self.saveSequenceAction.setEnabled(False) except: self.tree.clearTree() self.playSequenceAction.setEnabled(False) self.newSequenceAction.setEnabled(False) self.saveSequenceAction.setEnabled(False) raise finally: if not file is None: file.close() self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1])) self.currentMacroChanged.emit(None) def onOpenSequence(self): if not self._sequenceModel.isEmpty(): if Qt.QMessageBox.question( self, "Open sequence", "Do you want to save existing sequence?", Qt.QMessageBox.Yes, Qt.QMessageBox.No) == Qt.QMessageBox.Yes: self.onSaveSequence() self.tree.clearTree() sequencesPath = self.sequencesPath() fileName, _ = compat.getOpenFileName( self, "Choose a sequence to open...", sequencesPath, "*") self.loadFile(fileName) def onSaveSequence(self): sequencesPath = self.sequencesPath() if sequencesPath == "": sequencesPath = str(Qt.QDir.homePath()) sequencesPath = os.path.join(sequencesPath, "Untitled.xml") fileName, _ = compat.getSaveFileName( self, "Choose a sequence file name...", sequencesPath, "*.xml") if fileName == "": return try: file = open(fileName, "w") file.write(self.tree.toXmlString(pretty=True, withId=False)) self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1])) except Exception as e: Qt.QMessageBox.warning( self, "Error while saving macros sequence", "There was a problem while writing to the file: %s" % fileName) print(e) finally: if not file is None: file.close() def onPlaySequence(self): door = Device(self.doorName()) doorState = door.getState() if (doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM): first, last, ids = self.tree.prepareMacroIds() self.setFirstMacroId(first) self.setLastMacroId(last) self.setMacroIds(ids) self.tree.prepareMacroProgresses() self.setEmitExecutionStarted(True) door.runMacro(self.tree.toXmlString()) elif doorState == PyTango.DevState.STANDBY: door.command_inout("ResumeMacro") else: Qt.QMessageBox.warning( self, "Error while starting/resuming sequence", "It was not possible to start/resume sequence, " "because state of the door was different than ON/STANDBY") def onStopSequence(self): door = Device(self.doorName()) doorState = door.getState() if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY): door.command_inout("StopMacro") else: Qt.QMessageBox.warning( self, "Error while stopping sequence", "It was not possible to stop sequence, " "because state of the door was different than " "RUNNING or STANDBY") def onPauseSequence(self): door = Device(self.doorName()) doorState = door.getState() if doorState == PyTango.DevState.RUNNING: door.command_inout("PauseMacro") else: Qt.QMessageBox.warning( self, "Error while pausing sequence", "It was not possible to pause sequence, " "because state of the door was different than RUNNING") def onMacroStatusUpdated(self, data): macro = data[0] if macro is None: return data = data[1][0] state, range, step, id = str(data["state"]), data[ "range"], data["step"], data["id"] if id is None: return id = int(id) if not id in self.macroIds(): return macroName = macro.name shortMessage = "" if state == "start": #@todo: Check this signal because it doesn't work, # emitExecutionStarted is not set!!! if self.emitExecutionStarted(): self.macroStarted.emit("DoorOutput") self.tree.setRangeForMacro(id, range) self.playSequenceAction.setEnabled(False) self.pauseSequenceAction.setEnabled(True) self.stopSequenceAction.setEnabled(True) if id == self.firstMacroId(): self.plotablesFilterChanged.emit(None) self.plotablesFilterChanged.emit(standardPlotablesFilter) shortMessage = "Sequence started." elif not self.isFullSequencePlot(): self.plotablesFilterChanged.emit(None) shortMessage += " Macro %s started." % macroName elif state == "pause": self.playSequenceAction.setText("Resume sequence") self.playSequenceAction.setToolTip("Resume sequence") self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) shortMessage = "Macro %s paused." % macroName elif state == "resume": self.playSequenceAction.setText("Start sequence") self.playSequenceAction.setToolTip("Start sequence") self.playSequenceAction.setEnabled(False) self.pauseSequenceAction.setEnabled(True) shortMessage = "Macro %s resumed." % macroName elif state == "stop" or state == "finish": shortMessage = "Macro %s finished." % macroName if id == self.lastMacroId(): self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(False) shortMessage += " Sequence finished." elif state == 'exception': self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(False) shortMessage = "Macro %s error." % macroName exc_value, exc_stack = data['exc_value'], data['exc_stack'] exceptionDialog = TaurusMessageBox( MacroRunException, exc_value, exc_stack) exceptionDialog.exec_() elif state == 'abort': self.playSequenceAction.setText("Start sequence") self.playSequenceAction.setToolTip("Start sequence") self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(False) shortMessage = "Macro %s stopped." % macroName elif state == "step": shortMessage = "Macro %s at %d %% of progress." % (macroName, step) self.shortMessageEmitted.emit(shortMessage) self.tree.setProgressForMacro(id, step) def onDoorChanged(self, doorName): self.setDoorName(doorName) if self.doorName() == "": self.doorStateLed.setModel(None) return self.doorStateLed.setModel(self.doorName() + "/State") door = Device(doorName) doorState = door.stateObj.rvalue if doorState == PyTango.DevState.ON: self.playSequenceAction.setText("Start sequence") self.playSequenceAction.setToolTip("Start sequence") self.playSequenceAction.setEnabled(False) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(False) elif doorState == PyTango.DevState.STANDBY: self.playSequenceAction.setText("Resume sequence") self.playSequenceAction.setToolTip("Resume sequence") self.playSequenceAction.setEnabled(True) self.pauseSequenceAction.setEnabled(False) self.stopSequenceAction.setEnabled(True) def setMacroParametersRootIndex(self, sourceIndex): parametersModel = self.standardMacroParametersEditor.tree.model() parametersModel.setMacroIndex(sourceIndex) parametersModel.invalidateFilter() proxyIndex = parametersModel.mapFromSource(sourceIndex) macroNode = sourceIndex.internalPointer() macroName = macroNode.name() if self.stackedWidget.count() == 2: self.stackedWidget.removeWidget(self.customMacroParametersEditor) self.customMacroParametersEditor.setParent(None) self.customMacroParametersEditor = \ ParamEditorManager().getMacroEditor(macroName) if self.customMacroParametersEditor: self.customMacroParametersEditor.setModel(parametersModel) self.customMacroParametersEditor.setRootIndex(proxyIndex) self.stackedWidget.addWidget(self.customMacroParametersEditor) self.stackedWidget.setCurrentWidget( self.customMacroParametersEditor) else: self.standardMacroParametersEditor.tree.setRootIndex(proxyIndex) self.standardMacroParametersEditor.tree.expandAll() def onMacroComboBoxChanged(self): macroName = str(self.macroComboBox.currentText()) if macroName == "": self.addMacroAction.setEnabled(False) else: self.addMacroAction.setEnabled(True) self.macroNameChanged.emit(macroName) def onAdd(self): macroName = str(self.macroComboBox.currentText()) macroNode = self.getModelObj().getMacroNodeObj(macroName) self.tree.addMacro(macroNode) self.saveSequenceAction.setEnabled(True) self.playSequenceAction.setEnabled(True) def isEmptySequence(self): return len(self.tree.root()) == 0 def isMacroSelected(self): return len(self.tree.selectedIndexes()) == 2 def emptySequence(self): self.tree.clearTree() self.disableButtons() self.currentMacroChanged.emit(None) self.sequenceEmpty.emit() def fromXmlString(self, xmlString): newRoot = self.tree.fromXmlString(xmlString) macroServerObj = self.getModelObj() for macroNode in newRoot.allMacros(): macroServerObj.fillMacroNodeAdditionalInfos(macroNode) return newRoot def fromPlainText(self, plainText): plainTextMacros = [] macroInfos = [] macroServerObj = self.getModelObj() unknownMacros = [] for plainTextMacro in plainText.split('\n'): # stripping the whitespace characters plainTextMacro = plainTextMacro.strip() # ignoring the empty lines if len(plainTextMacro) == 0: continue # ignoring the commented lines if plainTextMacro[0] in self.comment_characters: continue macroName = plainTextMacro.split()[0] macroInfo = macroServerObj.getMacroInfoObj(macroName) if macroInfo is None: unknownMacros.append(macroName) plainTextMacros.append(plainTextMacro) macroInfos.append(macroInfo) if len(unknownMacros) > 0: msg = ("{0} macro(s) are not loaded in the " "MacroServer".format(", ".join(unknownMacros))) Qt.QMessageBox.warning(self, "Error while parsing the sequence", msg) raise ValueError(msg) newRoot = self.tree.fromPlainText(plainTextMacros, macroInfos) return newRoot def setModel(self, model): oldModelObj = self.getModelObj() if oldModelObj is not None: oldModelObj.macrosUpdated.disconnect( self.macroComboBox.onMacrosUpdated) TaurusWidget.setModel(self, model) newModelObj = self.getModelObj() newModelObj.macrosUpdated.connect(self.macroComboBox.onMacrosUpdated) self.sequenceEditor.setModel(model) self.macroComboBox.setModel(model) @classmethod def getQtDesignerPluginInfo(cls): return {'container': False, 'group': 'Taurus Sardana', 'module': 'taurus.qt.qtgui.extra_macroexecutor', 'icon': ':/designer/frame.png'}
def expanded(self): for column in range(self.model().columnCount(Qt.QModelIndex())): self.resizeColumnToContents(column)
def onContextChanged(self, idx=None): try: cid = self.getCurrentContext(idx) print "onContextChanged(%s,(%s,%s,%s))" % ( cid, self.filterComboBox.currentText(), self.filterComboBox2.currentText(), self.contextComboBox.currentText()) try: self.context = self.snapapi.get_context(cid) except: msg = QExceptionMessage('\n'.join(("Tango Archiving Problem", "Could not retrieve context with following ID: %s.<br>" % cid + \ "Please check if SnapManagerDS is running.<br>" + \ "Also check if this context exists."))) return self.infoLabel1_2.setText("<b>%s</b>" % self.context.author) self.infoLabel2_2.setText("<b>%s</b>" % self.context.reason) if len(self.context.description) > 80: self.infoLabel3_2.setText( "<b>%s</b>" % (self.context.description[:75] + ' ...')) else: #self.infoLabel3_2.setWordWrap(True) self.infoLabel3_2.setText("<b>%s</b>" % (self.context.description)) self.infoLabel3_2.setToolTip( fandango.str2lines(self.context.description)) if self.defaultContextID(): self.defaultContextLabel.setText( "<b>%s</b> [%d]" % (self.context.name, self.context.ID)) self.listWidget.clear() print "onContextChanged(%s): get_snapshots()" % (cid) self.snapshots = self.context.get_snapshots() print '[%d]' % len(self.snapshots) for id, snapshot in self.snapshots.items(): item = Qt.QListWidgetItem() item.setText("%s - %s [ID: %d]" % (snapshot[0], snapshot[1].split('\n')[0], id)) item.setData(Qt.Qt.UserRole, Qt.QVariant(id)) item.setToolTip(snapshot[1]) self.listWidget.addItem(item) self.listWidget.model().sort(0, Qt.Qt.DescendingOrder) self.buttonTake.show() self.buttonImport.show() self.infoLabel1_1.show() self.infoLabel1_2.show() self.infoLabel2_1.show() self.infoLabel2_2.show() self.infoLabel3_1.show() self.infoLabel3_2.show() self.infoLabel4_1.show() self.tableWidget.clear() self.tableWidget.setColumnCount(0) self.tableWidget.setRowCount(0) self.tableWidget.setHorizontalHeaderLabels([""]) self.comp._wi.tableWidget.clear() self.comp._wi.tableWidget.setColumnCount(0) self.comp._wi.tableWidget.setRowCount(0) self.comp._wi.tableWidget.setHorizontalHeaderLabels([""]) self.attributes = [] self.comp._wi.diffComboBox.clear() self.tableView() except: msg = QExceptionMessage("Error")
class FavouritesMacrosList(Qt.QListView, BaseConfigurableClass): favouriteSelected = Qt.pyqtSignal(object) def __init__(self, parent=None): Qt.QListView.__init__(self, parent) self.setSelectionMode(Qt.QListView.ExtendedSelection) self.removeAction = Qt.QAction(getIcon(":/actions/list-remove.svg"), "Remove from favourites", self) self.removeAction.triggered.connect(self.removeMacros) self.removeAction.setToolTip( "Clicking this button will remove selected macros " "from favourites.") self.removeAllAction = Qt.QAction(getIcon(":/places/user-trash.svg"), "Remove all from favourites", self) self.removeAllAction.triggered.connect(self.removeAllMacros) self.removeAllAction.setToolTip( "Clicking this button will remove all macros from favourites.") self.moveUpAction = Qt.QAction(getIcon(":/actions/go-up.svg"), "Move up", self) self.moveUpAction.triggered.connect(self.upMacro) self.moveUpAction.setToolTip( "Clicking this button will move the macro up " "in the favourites hierarchy.") self.moveDownAction = Qt.QAction(getIcon(":/actions/go-down.svg"), "Move down", self) self.moveDownAction.triggered.connect(self.downMacro) self.moveDownAction.setToolTip( "Clicking this button will move the macro down " "in the favourites hierarchy.") self.disableActions() def currentChanged(self, current, previous): macro = copy.deepcopy(self.currentIndex().internalPointer()) self.favouriteSelected.emit(macro) Qt.QListView.currentChanged(self, current, previous) def selectionChanged(self, old, new): macro = None if self.currentIndex().isValid(): self.removeAllAction.setEnabled(True) self.isIndexSelected() else: self.disableActions() Qt.QListView.selectionChanged(self, old, new) if len(self.selectedIndexes()) > 1: self.moveUpAction.setEnabled(False) self.moveDownAction.setEnabled(False) def isIndexSelected(self): if len(self.selectedIndexes()) > 0: self.removeAction.setEnabled(True) self.moveUpAction.setEnabled(self.model().isUpRowAllowed( self.currentIndex())) self.moveDownAction.setEnabled(self.model().isDownRowAllowed( self.currentIndex())) else: self.removeAction.setEnabled(False) self.moveUpAction.setEnabled(False) self.moveDownAction.setEnabled(False) def mousePressEvent(self, e): clickedIndex = self.indexAt(e.pos()) if clickedIndex.isValid(): macro = copy.deepcopy(self.currentIndex().internalPointer()) self.favouriteSelected.emit(macro) Qt.QListView.mousePressEvent(self, e) def disableActions(self): self.removeAction.setEnabled(False) self.removeAllAction.setEnabled(False) self.moveUpAction.setEnabled(False) self.moveDownAction.setEnabled(False) def insertMacro(self, macroNode): idx = self.model().insertRow(macroNode) self.setCurrentIndex(idx) def removeMacros(self): slist = sorted(self.selectedIndexes(), key=lambda index: index.row(), reverse=True) for index in slist: row = index.row() idx = self.model().removeRow(row) self.setCurrentIndex(idx) def removeAllMacros(self): self.selectAll() slist = sorted(self.selectedIndexes(), key=lambda index: index.row(), reverse=True) for index in slist: self.model().removeRow(index.row()) def upMacro(self): row = self.currentIndex().row() idx = self.model().upRow(row) self.setCurrentIndex(idx) def downMacro(self): row = self.currentIndex().row() idx = self.model().downRow(row) self.setCurrentIndex(idx) def toXmlString(self): return self.model().toXmlString() def fromXmlString(self, xmlString): self.model().fromXmlString(xmlString)
class TaurusMacroExecutorWidget(TaurusWidget): doorChanged = Qt.pyqtSignal('QString') macroNameChanged = Qt.pyqtSignal('QString') macroStarted = Qt.pyqtSignal('QString') plotablesFilterChanged = Qt.pyqtSignal(compat.PY_OBJECT) shortMessageEmitted = Qt.pyqtSignal('QString') def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.setObjectName(self.__class__.__name__) self._doorName = "" self._macroId = None self.setLayout(Qt.QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.addToFavouritesAction = Qt.QAction( Qt.QIcon("status:software-update-available.svg"), "Add to favourites", self) self.addToFavouritesAction.triggered.connect(self.onAddToFavourites) self.addToFavouritesAction.setToolTip("Add to favourites") self.stopMacroAction = Qt.QAction( Qt.QIcon("actions:media_playback_stop.svg"), "Stop macro", self) self.stopMacroAction.triggered.connect(self.onStopMacro) self.stopMacroAction.setToolTip("Stop macro") self.pauseMacroAction = Qt.QAction( Qt.QIcon("actions:media_playback_pause.svg"), "Pause macro", self) self.pauseMacroAction.triggered.connect(self.onPauseMacro) self.pauseMacroAction.setToolTip("Pause macro") self.playMacroAction = Qt.QAction( Qt.QIcon("actions:media_playback_start.svg"), "Start macro", self) self.playMacroAction.triggered.connect(self.onPlayMacro) self.playMacroAction.setToolTip("Start macro") actionsLayout = Qt.QHBoxLayout() actionsLayout.setContentsMargins(0, 0, 0, 0) addToFavouritsButton = Qt.QToolButton() addToFavouritsButton.setDefaultAction(self.addToFavouritesAction) self.addToFavouritesAction.setEnabled(False) actionsLayout.addWidget(addToFavouritsButton) self.macroComboBox = MacroComboBox(self) self.macroComboBox.setModelColumn(0) actionsLayout.addWidget(self.macroComboBox) stopMacroButton = Qt.QToolButton() stopMacroButton.setDefaultAction(self.stopMacroAction) actionsLayout.addWidget(stopMacroButton) pauseMacroButton = Qt.QToolButton() pauseMacroButton.setDefaultAction(self.pauseMacroAction) actionsLayout.addWidget(pauseMacroButton) self.playMacroButton = Qt.QToolButton() self.playMacroButton.setDefaultAction(self.playMacroAction) actionsLayout.addWidget(self.playMacroButton) self.disableControlActions() self.doorStateLed = TaurusLed(self) actionsLayout.addWidget(self.doorStateLed) self.layout().addLayout(actionsLayout) splitter = Qt.QSplitter(self) self.layout().addWidget(splitter) splitter.setOrientation(Qt.Qt.Vertical) self._paramEditorModel = ParamEditorModel() self.stackedWidget = Qt.QStackedWidget() self.standardMacroParametersEditor = StandardMacroParametersEditor( self.stackedWidget) self.stackedWidget.addWidget(self.standardMacroParametersEditor) self.customMacroParametersEditor = None splitter.addWidget(self.stackedWidget) self._favouritesBuffer = None self.favouritesMacrosEditor = FavouritesMacrosEditor(self) self.registerConfigDelegate(self.favouritesMacrosEditor) self.favouritesMacrosEditor.setFocusPolicy(Qt.Qt.NoFocus) self._historyBuffer = None self.historyMacrosViewer = HistoryMacrosViewer(self) self.registerConfigDelegate(self.historyMacrosViewer) self.historyMacrosViewer.setFocusPolicy(Qt.Qt.NoFocus) self.tabMacroListsWidget = Qt.QTabWidget(self) self.tabMacroListsWidget.addTab( self.favouritesMacrosEditor, "Favourite list") self.tabMacroListsWidget.addTab( self.historyMacrosViewer, "History Viewer") splitter.addWidget(self.tabMacroListsWidget) # Due to a limitation in the useParentModel architecture of Taurus, # the parent of historyMacrosViewer and favouritesMacrosEditor # must be recalculated. See more details in the taurus snippet code [1] # [1] https://raw.githubusercontent.com/taurus-org/taurus/develop/doc/source/devel/examples/parentmodel_issue_demo.py self.historyMacrosViewer.recheckTaurusParent() self.favouritesMacrosEditor.recheckTaurusParent() self._isHistoryMacro = False self.macroProgressBar = MacroProgressBar(self) self.layout().addWidget(self.macroProgressBar) #spockCommandLabel = Qt.QLabel("Spock command:", self) # spockCommandLabel.setFont(Qt.QFont("Courier",9)) self.spockCommand = SpockCommandWidget("Spock", self) self.spockCommand.setSizePolicy( Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum) spockCommandLayout = Qt.QHBoxLayout() spockCommandLayout.setContentsMargins(0, 0, 0, 0) # spockCommandLayout.addWidget(spockCommandLabel) spockCommandLayout.addWidget(self.spockCommand) self.layout().addLayout(spockCommandLayout) self.macroComboBox.currentIndexChanged['QString'].connect( self.onMacroComboBoxChanged) self.favouritesMacrosEditor.list.favouriteSelected.connect( self.onFavouriteSelected) self.historyMacrosViewer.list.historySelected.connect( self.onHistorySelected) self.spockCommand.pressedReturn.connect(self.onPlayMacro) self.spockCommand.spockComboBox.connect(self.setComboBoxItem) self.spockCommand.elementUp.connect(self.setHistoryUp) self.spockCommand.elementDown.connect(self.setHistoryDown) self.spockCommand.expandTree.connect( self.standardMacroParametersEditor.tree.expandAll) def macroId(self): return self._macroId def contextMenuEvent(self, event): menu = Qt.QMenu() menu.addAction(Qt.QIcon.fromTheme("view-refresh"), "Check door state", self.checkDoorState) menu.exec_(event.globalPos()) def checkDoorState(self): door = Device(self.doorName()) doorState = door.getState() if doorState == PyTango.DevState.RUNNING: self.playMacroAction.setEnabled(False) self.pauseMacroAction.setEnabled(True) self.stopMacroAction.setEnabled(True) elif doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM: self.playMacroAction.setEnabled(True) self.pauseMacroAction.setEnabled(False) self.stopMacroAction.setEnabled(False) elif doorState == PyTango.DevState.STANDBY: self.playMacroAction.setEnabled(True) self.pauseMacroAction.setEnabled(False) self.stopMacroAction.setEnabled(True) def setMacroId(self, macroId): self._macroId = macroId def doorName(self): return self._doorName def setDoorName(self, doorName): self._doorName = doorName def setFavouritesBuffer(self, favouritesMacro): self._favouritesBuffer = favouritesMacro # History Widget def setHistoryUp(self): self.setHistoryFocus() self.historyMacrosViewer.listElementUp() def setHistoryDown(self): self.setHistoryFocus() self.historyMacrosViewer.listElementDown() def setHistoryFocus(self): self.tabMacroListsWidget.setCurrentWidget(self.historyMacrosViewer) # self.historyMacrosViewer.setFocus() def historyBuffer(self): return self._historyBuffer def setHistoryBuffer(self, favouritesMacro): self._historyBuffer = favouritesMacro def favouritesBuffer(self): return self._favouritesBuffer def paramEditorModel(self): return self._paramEditorModel def setParamEditorModel(self, paramEditorModel): self._paramEditorModel = paramEditorModel def setComboBoxItem(self, macroName): self.macroComboBox.selectMacro(macroName) @Qt.pyqtSlot('QString') def onMacroComboBoxChanged(self, macroName): macroName = str(macroName) if macroName == "": macroName, macroNode = None, None # macroNode = macro.MacroNode(name="") self.playMacroAction.setEnabled(False) self.addToFavouritesAction.setEnabled(False) else: if self._isHistoryMacro: macroNode = self.historyBuffer() self.setHistoryBuffer(None) self.favouritesMacrosEditor.list.clearSelection() else: macroNode = self.favouritesBuffer() self.setFavouritesBuffer(None) self.historyMacrosViewer.list.clearSelection() self._isHistoryMacro = False if macroNode is None: macroNode = self.getModelObj().getMacroNodeObj(macroName) self.playMacroAction.setEnabled(True) self.addToFavouritesAction.setEnabled(True) self.paramEditorModel().setRoot(macroNode) self.spockCommand.setModel(self.paramEditorModel()) if self.stackedWidget.count() == 2: self.stackedWidget.removeWidget(self.customMacroParametersEditor) self.customMacroParametersEditor.setParent(None) self.customMacroParametersEditor = ParamEditorManager( ).getMacroEditor(macroName, self.stackedWidget) if self.customMacroParametersEditor: self.customMacroParametersEditor.setModel(self.paramEditorModel()) self.stackedWidget.addWidget(self.customMacroParametersEditor) self.stackedWidget.setCurrentWidget( self.customMacroParametersEditor) else: self.standardMacroParametersEditor.setModel( self.paramEditorModel()) self.macroNameChanged.emit(macroName) def onFavouriteSelected(self, macroNode): self.setFavouritesBuffer(macroNode) name = "" if not macroNode is None: name = macroNode.name() self._isHistoryMacro = False self.macroComboBox.selectMacro(name) def onHistorySelected(self, macroNode): self.setHistoryBuffer(macroNode) name = "" if not macroNode is None: name = macroNode.name() self._isHistoryMacro = True self.macroComboBox.selectMacro(name) def onAddToFavourites(self): self.favouritesMacrosEditor.addMacro( deepcopy(self.paramEditorModel().root())) def addToHistory(self): self.historyMacrosViewer.addMacro( deepcopy(self.paramEditorModel().root())) def onDoorChanged(self, doorName): self.setDoorName(doorName) if self.doorName() == "": self.doorStateLed.setModel(None) return self.doorStateLed.setModel(self.doorName() + "/State") door = Device(doorName) doorState = door.stateObj.rvalue if doorState == PyTango.DevState.ON: self.playMacroAction.setText("Start macro") self.playMacroAction.setToolTip("Start macro") elif doorState == PyTango.DevState.STANDBY: self.playMacroAction.setText("Resume macro") self.playMacroAction.setToolTip("Resume macro") def onPlayMacro(self): door = Device(self.doorName()) doorState = door.getState() if doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM: self.setFocus() paramEditorModel = self.paramEditorModel() macroNode = paramEditorModel.root() id = macroNode.assignId() self.setMacroId(id) params, alerts = macroNode.toRun() xmlString = paramEditorModel.toXmlString() if len(alerts) > 0: Qt.QMessageBox.warning( self, "Macro parameters warning", alerts) return door.runMacro(xmlString) self.addToHistory() # door.runMacro(str(macroNode.name()), params) elif doorState == PyTango.DevState.STANDBY: door.command_inout("ResumeMacro") else: Qt.QMessageBox.warning(self, "Error while starting/resuming macro", "It was not possible to start/resume macro, because state of the door was different than ON/STANDBY") def onStopMacro(self): door = Device(self.doorName()) doorState = door.getState() if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY): door.command_inout("StopMacro") else: Qt.QMessageBox.warning(self, "Error while stopping macro", "It was not possible to stop macro, because state of the door was different than RUNNING or STANDBY") def onPauseMacro(self): door = Device(self.doorName()) doorState = door.getState() if doorState == PyTango.DevState.RUNNING: door.command_inout("PauseMacro") else: Qt.QMessageBox.warning(self, "Error while pausing macro", "It was not possible to pause macro, because state of the door was different than RUNNING") def onMacroStatusUpdated(self, data): macro = data[0] if macro is None: return data = data[1][0] state, range, step, id = data["state"], data[ "range"], data["step"], data["id"] if id is None: return if id != self.macroId(): return macroName = macro.name shortMessage = "" if state == "start": self.macroStarted.emit("DoorOutput") self.macroProgressBar.setRange(range[0], range[1]) self.playMacroAction.setEnabled(False) self.pauseMacroAction.setEnabled(True) self.stopMacroAction.setEnabled(True) self.plotablesFilterChanged.emit(None) self.plotablesFilterChanged.emit(standardPlotablesFilter) shortMessage = "Macro %s started." % macroName elif state == "pause": self.playMacroAction.setText("Resume macro") self.playMacroAction.setToolTip("Resume macro") self.playMacroAction.setEnabled(True) self.pauseMacroAction.setEnabled(False) shortMessage = "Macro %s paused." % macroName elif state == "resume": self.playMacroAction.setText("Start macro") self.playMacroAction.setToolTip("Start macro") self.playMacroAction.setEnabled(False) self.pauseMacroAction.setEnabled(True) shortMessage = "Macro %s resumed." % macroName elif state == "stop" or state == "finish": self.playMacroAction.setEnabled(True) self.pauseMacroAction.setEnabled(False) self.stopMacroAction.setEnabled(False) shortMessage = "Macro %s finished." % macroName elif state == "exception": self.playMacroAction.setEnabled(True) self.pauseMacroAction.setEnabled(False) self.stopMacroAction.setEnabled(False) shortMessage = "Macro %s error." % macroName exc_value, exc_stack = data['exc_value'], data['exc_stack'] exceptionDialog = TaurusMessageBox( MacroRunException, exc_value, exc_stack) exceptionDialog.exec_() elif state == "abort": self.playMacroAction.setText("Start macro") self.playMacroAction.setToolTip("Start macro") self.playMacroAction.setEnabled(True) self.pauseMacroAction.setEnabled(False) self.stopMacroAction.setEnabled(False) shortMessage = "Macro %s stopped." % macroName elif state == "step": shortMessage = "Macro %s at %d %% of progress." % (macroName, step) self.shortMessageEmitted.emit(shortMessage) self.macroProgressBar.setValue(step) def disableControlActions(self): self.pauseMacroAction.setEnabled(False) self.stopMacroAction.setEnabled(False) self.playMacroAction.setEnabled(False) def setModel(self, model): oldModelObj = self.getModelObj() if oldModelObj is not None: # TODO: check if macrosUpdated signal exists oldModelObj.macrosUpdated.disconnect( self.macroComboBox.onMacrosUpdated) TaurusWidget.setModel(self, model) newModelObj = self.getModelObj() newModelObj.macrosUpdated.connect( self.macroComboBox.onMacrosUpdated) self.macroComboBox.setModel(model) self.favouritesMacrosEditor.setModel(model) self.historyMacrosViewer.setModel(model) self.spockCommand.setModel(model) @classmethod def getQtDesignerPluginInfo(cls): return {'container': False, 'group': 'Taurus Sardana', 'module': 'taurus.qt.qtgui.extra_macroexecutor', 'icon': ':/designer/frame.png'}
def onApply(self): self.emit(Qt.SIGNAL('applied'))
def showProperties(self, prop=None): """Updates the dialog to show the given properties. :param prop: (CurveAppearanceProperties) the properties object containing what should be shown. If a given property is set to CONFLICT, the corresponding plot_item will show a "neutral" display """ if prop is None: prop = self._shownProp # set the Style comboboxes self.sStyleCB.setCurrentIndex( self.sStyleCB.findText(NamedSymbolStyles[prop.sStyle])) self.lStyleCB.setCurrentIndex( self.lStyleCB.findText(NamedLineStyles[prop.lStyle])) self.cStyleCB.setCurrentIndex( self.cStyleCB.findText(NamedCurveStyles[prop.cStyle])) if prop.y2 is CONFLICT: self.assignToY1BT.setChecked(False) self.assignToY2BT.setChecked(False) elif prop.y2: self.assignToY2BT.setChecked(True) else: self.assignToY1BT.setChecked(True) # set sSize and lWidth spinboxes. if prop.sSize is None, it puts -1 # (which is the special value for these switchhboxes) if prop.sSize is CONFLICT or prop.sStyle is None: self.sSizeSB.setValue(-1) else: self.sSizeSB.setValue(max(prop.sSize, -1)) if prop.lWidth is CONFLICT: self.lWidthSB.setValue(-1) else: self.lWidthSB.setValue(max(prop.lWidth, -1)) # Set the Color combo boxes. The item at index 0 is the empty one in # the comboboxes Manage unknown colors by including them if prop.sColor in (None, CONFLICT) or prop.sStyle is None: index = 0 else: index = self.sColorCB.findData(Qt.QColor(prop.sColor)) if index == -1: # if the color is not supported, add it to combobox index = self.sColorCB.count() self.sColorCB.addItem(self._colorIcon( Qt.QColor(prop.sColor)), "", Qt.QColor(prop.sColor)) self.sColorCB.setCurrentIndex(index) if prop.lColor is None or prop.lColor is CONFLICT: index = 0 else: index = self.lColorCB.findData(Qt.QColor(prop.lColor)) if index == -1: # if the color is not supported, add it to combobox index = self.lColorCB.count() self.lColorCB.addItem(self._colorIcon( Qt.QColor(prop.lColor)), "", Qt.QColor(prop.lColor)) self.lColorCB.setCurrentIndex(index) # set the Fill Checkbox. The prop.sFill value can be in 3 states: True, # False and None if prop.sFill is None or prop.sFill is CONFLICT: checkState = Qt.Qt.PartiallyChecked elif prop.sFill: checkState = Qt.Qt.Checked else: checkState = Qt.Qt.Unchecked self.sFillCB.setCheckState(checkState) # set the Area Fill Checkbox. The prop.cFill value can be in 3 states: # True, False and None if prop.cFill is CONFLICT: checkState = Qt.Qt.PartiallyChecked self.cAreaDSB.setValue(0.0) elif prop.cFill is None: checkState = Qt.Qt.Unchecked self.cAreaDSB.setValue(0.0) else: checkState = Qt.Qt.Checked self.cAreaDSB.setValue(prop.cFill) self.cFillCB.setCheckState(checkState)
def getShownProperties(self): """Returns a copy of the currently shown properties and updates self._shownProp :return: (CurveAppearanceProperties) """ prop = CurveAppearanceProperties() for name in self.getSelectedCurveNames(): prop.title = self.curvePropDict[name].title # get the values from the Style comboboxes. Note that the empty string # ("") translates into CONFLICT prop.sStyle = ReverseNamedSymbolStyles[ str(self.sStyleCB.currentText())] prop.lStyle = ReverseNamedLineStyles[str(self.lStyleCB.currentText())] prop.cStyle = ReverseNamedCurveStyles[str(self.cStyleCB.currentText())] # get sSize and lWidth from the spinboxes (-1 means conflict) v = self.sSizeSB.value() if v == -1: prop.sSize = CONFLICT else: prop.sSize = v v = self.lWidthSB.value() if v == -1: prop.lWidth = CONFLICT else: prop.lWidth = v # Get the Color combo boxes. The item at index 0 is the empty one in # the comboboxes index = self.sColorCB.currentIndex() if index == 0: prop.sColor = CONFLICT else: prop.sColor = Qt.QColor(self.sColorCB.itemData(index)) index = self.lColorCB.currentIndex() if index == 0: prop.lColor = CONFLICT else: prop.lColor = Qt.QColor(self.lColorCB.itemData(index)) # get the sFill from the Checkbox. checkState = self.sFillCB.checkState() if checkState == Qt.Qt.PartiallyChecked: prop.sFill = CONFLICT else: prop.sFill = bool(checkState) # get the cFill from the Checkbox. checkState = self.cFillCB.checkState() if checkState == Qt.Qt.PartiallyChecked: prop.cFill = CONFLICT elif checkState == Qt.Qt.Checked: prop.cFill = self.cAreaDSB.value() else: prop.cFill = None # get the y2 state from the buttons y1 = self.assignToY1BT.isChecked() y2 = self.assignToY2BT.isChecked() if not y1 and not y2: prop.y2 = CONFLICT elif y1: prop.y2 = False elif y2: prop.y2 = True else: # both buttons should never be checked simultaneously raise RuntimeError('Inconsistent state of Y-axis buttons') # store the props self._shownProp = copy.deepcopy(prop) return copy.deepcopy(prop)
def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) # list representing all macros ids (all from sequence) currently # executed self._macroIds = [] self._sequencesPath = str(Qt.QDir.homePath()) self._sequenceModel = MacroSequenceTreeModel() self.registerConfigProperty( "sequencesPath", "setSequencesPath", "sequencesPath") self.setLayout(Qt.QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) splitter = Qt.QSplitter() self.layout().addWidget(splitter) splitter.setOrientation(Qt.Qt.Vertical) self.sequenceEditor = TaurusWidget() splitter.addWidget(self.sequenceEditor) self.sequenceEditor.setLayout(Qt.QVBoxLayout()) self.sequenceEditor.layout().setContentsMargins(0, 0, 0, 0) self.tree = MacroSequenceTree(self.sequenceEditor) self.sequenceProxyModel = MacroSequenceProxyModel() self.sequenceProxyModel.setSourceModel(self._sequenceModel) self.tree.setModel(self.sequenceProxyModel) self.tree.setItemDelegate(SequenceEditorDelegate(self.tree)) actionsLayout = Qt.QHBoxLayout() actionsLayout.setContentsMargins(0, 0, 0, 0) self.newSequenceAction = Qt.QAction( Qt.QIcon.fromTheme("document-new"), "New", self) self.newSequenceAction.triggered.connect(self.onNewSequence) self.newSequenceAction.setToolTip("New sequence") self.newSequenceAction.setEnabled(False) newSequenceButton = Qt.QToolButton() newSequenceButton.setDefaultAction(self.newSequenceAction) actionsLayout.addWidget(newSequenceButton) self.openSequenceAction = Qt.QAction( Qt.QIcon.fromTheme("document-open"), "Open...", self) self.openSequenceAction.triggered.connect(self.onOpenSequence) self.openSequenceAction.setToolTip("Open sequence...") openSequenceButton = Qt.QToolButton() openSequenceButton.setDefaultAction(self.openSequenceAction) actionsLayout.addWidget(openSequenceButton) self.saveSequenceAction = Qt.QAction( Qt.QIcon.fromTheme("document-save"), "Save...", self) self.saveSequenceAction.triggered.connect(self.onSaveSequence) self.saveSequenceAction.setToolTip("Save sequence...") self.saveSequenceAction.setEnabled(False) saveSequenceButton = Qt.QToolButton() saveSequenceButton.setDefaultAction(self.saveSequenceAction) actionsLayout.addWidget(saveSequenceButton) self.stopSequenceAction = Qt.QAction( Qt.QIcon("actions:media_playback_stop.svg"), "Stop", self) self.stopSequenceAction.triggered.connect(self.onStopSequence) self.stopSequenceAction.setToolTip("Stop sequence") stopSequenceButton = Qt.QToolButton() stopSequenceButton.setDefaultAction(self.stopSequenceAction) actionsLayout.addWidget(stopSequenceButton) self.pauseSequenceAction = Qt.QAction( Qt.QIcon("actions:media_playback_pause.svg"), "Pause", self) self.pauseSequenceAction.triggered.connect(self.onPauseSequence) self.pauseSequenceAction.setToolTip("Pause sequence") pauseSequenceButton = Qt.QToolButton() pauseSequenceButton.setDefaultAction(self.pauseSequenceAction) actionsLayout.addWidget(pauseSequenceButton) self.playSequenceAction = Qt.QAction( Qt.QIcon("actions:media_playback_start.svg"), "Play", self) self.playSequenceAction.triggered.connect(self.onPlaySequence) self.playSequenceAction.setToolTip("Play sequence") playSequenceButton = Qt.QToolButton() playSequenceButton.setDefaultAction(self.playSequenceAction) actionsLayout.addWidget(playSequenceButton) self.doorStateLed = TaurusLed(self) actionsLayout.addWidget(self.doorStateLed) #@todo this feature will be replaced by checkboxes in the # sequence tree view indicating clearing of the plot after execution self.fullSequencePlotCheckBox = Qt.QCheckBox( "Full sequence plot", self) self.fullSequencePlotCheckBox.toggled.connect(self.setFullSequencePlot) self.fullSequencePlotCheckBox.setChecked(True) actionsLayout.addWidget(self.fullSequencePlotCheckBox) spacerItem = Qt.QSpacerItem( 0, 0, Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Fixed) actionsLayout.addItem(spacerItem) self.sequenceEditor.layout().addLayout(actionsLayout) macroLayout = Qt.QHBoxLayout() macroLayout.setContentsMargins(0, 0, 0, 0) macroLabel = Qt.QLabel("Macro:") macroLayout.addWidget(macroLabel) self.macroComboBox = MacroComboBox(self) self.macroComboBox.setModelColumn(0) self.macroComboBox.setSizePolicy( Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum) macroLayout.addWidget(self.macroComboBox) self.addMacroAction = Qt.QAction( Qt.QIcon.fromTheme("list-add"), "Add macro...", self) self.addMacroAction.triggered.connect(self.onAdd) self.addMacroAction.setToolTip( "Clicking this button will add selected macro") self.addMacroAction.setEnabled(False) addButton = Qt.QToolButton() addButton.setDefaultAction(self.addMacroAction) macroLayout.addWidget(addButton) self.sequenceEditor.layout().addLayout(macroLayout) sequenceLayout = Qt.QHBoxLayout() sequenceLayout.addWidget(self.tree) layout = Qt.QVBoxLayout() delButton = Qt.QToolButton() delButton.setDefaultAction(self.tree.deleteAction) delButton.setEnabled(False) layout.addWidget(delButton) upButton = Qt.QToolButton() upButton.setDefaultAction(self.tree.moveUpAction) upButton.setEnabled(False) layout.addWidget(upButton) downButton = Qt.QToolButton() downButton.setDefaultAction(self.tree.moveDownAction) downButton.setEnabled(False) layout.addWidget(downButton) leftButton = Qt.QToolButton() leftButton.setDefaultAction(self.tree.moveLeftAction) leftButton.setEnabled(False) layout.addWidget(leftButton) rightButton = Qt.QToolButton() rightButton.setDefaultAction(self.tree.moveRightAction) rightButton.setEnabled(False) layout.addWidget(rightButton) spacerItem = Qt.QSpacerItem( 0, 40, Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Expanding) layout.addItem(spacerItem) sequenceLayout.addLayout(layout) self.sequenceEditor.layout().addLayout(sequenceLayout) self.parametersProxyModel = MacroParametersProxyModel() self.parametersProxyModel.setSourceModel(self._sequenceModel) self.stackedWidget = Qt.QStackedWidget() splitter.addWidget(self.stackedWidget) self.standardMacroParametersEditor = StandardMacroParametersEditor( self.stackedWidget) self.standardMacroParametersEditor.setModel(self.parametersProxyModel) self.standardMacroParametersEditor.tree.setItemDelegate( ParamEditorDelegate(self.standardMacroParametersEditor.tree)) self.stackedWidget.addWidget(self.standardMacroParametersEditor) self.customMacroParametersEditor = None self.macroComboBox.currentIndexChanged.connect( self.onMacroComboBoxChanged) self.tree.macroChanged.connect(self.setMacroParametersRootIndex)
## # 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/>. ## ########################################################################### '''An example of usage of TaurusGui in which no configuration file is used (everything is done programmatically) This can be launched directly as a stand-alone python script''' if __name__ == '__main__': from taurus.qt.qtgui.application import TaurusApplication from taurus.qt.qtgui.taurusgui import TaurusGui from taurus.external.qt import Qt # if app_name name not given, it uses the file name app = TaurusApplication(app_name='MyGui', cmd_line_parser=None) gui = TaurusGui() panel = Qt.QWidget() gui.createPanel(panel, 'Foo') gui.show() app.exec_()
def contextMenuEvent(self, event): menu = Qt.QMenu() menu.addAction(Qt.QIcon.fromTheme("view-refresh"), "Check door state", self.checkDoorState) menu.exec_(event.globalPos())
class SpockCommandWidget(Qt.QLineEdit, TaurusBaseContainer): pressedReturn = Qt.pyqtSignal() spockComboBox = Qt.pyqtSignal('QString') elementUp = Qt.pyqtSignal() elementDown = Qt.pyqtSignal() setHistoryFocus = Qt.pyqtSignal() expandTree = Qt.pyqtSignal() def __init__(self, name='', parent=None, designMode=False): # self.newValue - is used as a flag to indicate whether a controlUp controlDown actions are used to iterate existing element or put new one # self.disableEditMode - flag, used to disable edition, when user enters name of the macro which is not valid (not allowed to edit in the yellow line) # switches off validation # disableSpockCommandUpdate - flag, it disables updates of the model # when macro is edited by macroEditor Qt.QLineEdit.__init__(self, parent) TaurusBaseContainer.__init__(self, name, parent, designMode) self._model = None self.setFont(Qt.QFont("Courier", 9)) palette = Qt.QPalette() palette.setColor(Qt.QPalette.Base, Qt.QColor('yellow')) self.setPalette(palette) self.currentIndex = Qt.QModelIndex() self.newValue = False self.disableSpockCommandUpdate = False self.disableEditMode = True self.setEnabled(False) self.setActions() self.textChanged.connect(self.onTextChanged) self.returnPressed.connect(self.onReturnPressed) def setActions(self): self._downAction = Qt.QAction("downAction", self) self._upAction = Qt.QAction("upAction", self) self._ctrlDownAction = Qt.QAction("controlDownAction", self) self._ctrlUpAction = Qt.QAction("controlUpAction", self) self._ctrlDownAction.setShortcut( Qt.QKeySequence(Qt.Qt.CTRL + Qt.Qt.Key_Down)) self._ctrlUpAction.setShortcut( Qt.QKeySequence(Qt.Qt.CTRL + Qt.Qt.Key_Up)) self._downAction.setShortcuts([Qt.Qt.Key_Down]) self._upAction.setShortcuts([Qt.Qt.Key_Up]) self._ctrlDownAction.setShortcutContext(Qt.Qt.WidgetShortcut) self._ctrlUpAction.setShortcutContext(Qt.Qt.WidgetShortcut) self._downAction.setShortcutContext(Qt.Qt.WidgetShortcut) self._upAction.setShortcutContext(Qt.Qt.WidgetShortcut) self.addAction(self._ctrlDownAction) self.addAction(self._ctrlUpAction) self.addAction(self._downAction) self.addAction(self._upAction) self._downAction.triggered.connect(self.downAction) self._upAction.triggered.connect(self.upAction) self._ctrlDownAction.triggered.connect(self.controlDownAction) self._ctrlUpAction.triggered.connect(self.controlUpAction) def setCommand(self): command = self._model.toSpockCommand().strip() if not self.disableSpockCommandUpdate: self.setText(command) def onDataChanged(self, idx): """ If data is changed to nothing set it to the default value. Otherwise update the spock command and check the validation. This is a workaround for bug-451 that clear all input parameters when an empty string parameter is deselected. """ if idx.data() == "": defaultvalue = self._model.nodeFromIndex(idx).defValue() if defaultvalue != "": self._model.setData(idx, defaultvalue) else: self.setCommand() def setModel(self, model): if isinstance(model, Qt.QAbstractItemModel): enable = bool(model) self.disableEditMode = not enable self.setEnabled(enable) self._model = model self._model.dataChanged.connect(self.onDataChanged) self._model.modelReset.connect(self.setCommand) else: TaurusBaseContainer.setModel(self, model) def model(self): return self._model def getIndex(self, elementNumber=-1): # Returns QModelIndex of the required element (number of single # parameter). If the elementNumber == -1 next single parameter index is # returned. if elementNumber == -1: ix = self.currentIndex elementNumber = 1 elif elementNumber == 0: return Qt.QModelIndex() else: ix = Qt.QModelIndex() (col, row, parentIdx) = (ix.column(), ix.row(), ix.parent()) # to start from second column if col == -1 and row == -1: ix = self.forwardIdx(0, 1, ix) for i in range(0, elementNumber): # This condition in case we start tabbing with cursor on first # column if col == 0: currentNode = self.model().nodeFromIndex(ix) if isinstance(currentNode, macro.SingleParamNode): nextIdx = self.forwardIdx(row, 1, parentIdx) else: nextIdx = self.forwardIdx(0, 1, ix) else: nextIdx = self.forwardIdx(row + 1, 1, parentIdx) # this condition in case there is no next index and we want to pass focus # to next widget in parent obj if nextIdx == "term": return Qt.QModelIndex() ix = nextIdx (col, row, parentIdx) = (ix.column(), ix.row(), ix.parent()) return ix def forwardIdx(self, row, col, parentIdx): # This method is moving down the tree to get next SingleParamNode # index. try: proposalIdx = self.model().index(row, col, parentIdx) except AssertionError: if parentIdx.row() == -1: return Qt.QModelIndex() grandParentIdx = parentIdx.parent() return self.forwardIdx(parentIdx.row() + 1, col, grandParentIdx) proposalNode = self.model().nodeFromIndex(proposalIdx) if isinstance(proposalNode, macro.SingleParamNode): return proposalIdx elif isinstance(proposalNode, macro.RepeatNode): return self.forwardIdx(0, 1, proposalIdx) elif isinstance(proposalNode, macro.RepeatParamNode): if len(proposalNode) > 0: return self.forwardIdx(0, 1, proposalIdx) else: return self.forwardIdx(row + 1, col, proposalIdx) elif not proposalIdx.isValid(): proposalIdx = parentIdx.sibling(parentIdx.row() + 1, 0) if proposalIdx.isValid(): proposalIdx = proposalIdx.child(0, 1) else: while not proposalIdx.isValid(): parentIdx = parentIdx.parent() if not parentIdx.isValid(): return Qt.QModelIndex() proposalIdx = parentIdx.sibling(parentIdx.row() + 1, 1) return proposalIdx def validateAllExpresion(self, secValidation=False): # This method is responsible for full validation of the macro. It is executed whenever the text is changed (when user edits values). # Validation starts with checking if the macro (name) is valid. # Next steps: # 1. Validates every SingleParamNode and counts how many there are in the macro. # 2. If there are more SingleParamNodes than entered values it will check if there is RepeatParamNode. # If there is RepeatParamNode it will check if its RepeatNodes can be deleted. # 3. If there are more values entered than SingleParamNodes in macro it will check if there is RepeatParamNode. # If there is it will try to add new RepeatNode. if self.model() is None: raise RuntimeError( 'Door must be set in order to use the macroexecutor.') self.currentIndex = Qt.QModelIndex() mlist = str(self.text()).split() problems = [] try: if str(mlist[0]) != str(self.model().root().name()): try: self.getModelObj().validateMacroName(str(mlist[0])) self.validateMacro(mlist[0]) self.updateMacroEditor(mlist[0]) if not secValidation: self.validateAllExpresion(True) except Exception as e: if self.disableEditMode: self.updateMacroEditor(mlist[0]) raise Exception(e) message = e.args[0] #raise Exception(e) problems.append(message) except IndexError: problems.append("<b>Macro<\b> is missing!") self.setStyleSheet("") self.setToolTip('<br>'.join(problems)) return self.currentIndex = Qt.QModelIndex() ix = self.getIndex() self.currentIndex = ix counter = 1 while not ix == Qt.QModelIndex(): try: propValue = mlist[counter] try: self.validateOneValue(propValue) self.model().setData(self.currentIndex, propValue) except Exception as e: self.model().setData(self.currentIndex, 'None') txt = str(ix.sibling(ix.row(), 0).data()) message = "<b>" + txt + "</b> " + e.args[0] problems.append(message) except IndexError: txt = str(ix.sibling(ix.row(), 0).data()) problems.append("<b>" + txt + "</b> is missing!") data = str(ix.data()) if data != 'None': self.model().setData(self.currentIndex, 'None') else: self.model().setData(self.currentIndex, None) counter += 1 ix = self.getIndex() self.currentIndex = ix if len(mlist) > counter: # if there are more values than parameters repeatNode = None for i in self.model().root().params(): repeatNode = i if isinstance(repeatNode, macro.RepeatParamNode): index = self.findParamRepeat(i) self.currentIndex = self.model()._insertRow(index) nn = self.model().nodeFromIndex(self.currentIndex) self.expandTree.emit() ix = self.getIndex() if not secValidation: self.validateAllExpresion(True) return repeatNode = None if repeatNode is None: problems.append("Too many values.") elif counter - len(mlist) >= 1: repeatNode = None node = None for i in self.model().root().params(): repeatNode = i if isinstance(repeatNode, macro.RepeatParamNode): index = self.findParamRepeat(i) node = self.model().nodeFromIndex(index) sub = len(node.child(0)) break repeatNode = None if repeatNode is not None: while counter - len(mlist) > sub - 1: if len(node.children()) == 1 and node.isReachedMin(): break self.model()._removeRow(index.child(len(node.children()) - 1, 0)) counter -= sub if not secValidation: self.validateAllExpresion(True) return if len(problems) == 0: self.setStyleSheet('SpockCommandWidget {background-color: %s; color: %s; border: %s; border-radius: %s}' % ( 'yellow', 'black', '3px solid green', '5px')) self.setToolTip("") else: self.setStyleSheet("") self.setToolTip('<br>'.join(problems)) return def findParamRepeat(self, repeatNode): # Method which finds index of given ParamRepeatNode in the macro. children = self.model().root().children() occ = children.count(repeatNode) idx = 0 for i in range(0, occ): idx = children.index(repeatNode, idx) index = self.model().index(idx, 0, Qt.QModelIndex()) return index def validateOneValue(self, value): # Validates value of a SingleParamNode of a currentIndex paramNode = deepcopy(self.model().nodeFromIndex(self.currentIndex)) paramNode.setValue(value) return self.getModelObj().validateSingleParam(paramNode) def onReturnPressed(self): # SLOT called when return is pressed if self.toolTip() == "": self.pressedReturn.emit() else: raise Exception( "Cannot start macro. Please correct following mistakes: <br>" + self.toolTip()) def onTextChanged(self, strs): # SLOT called when QLineEdit text is changed if strs == "": self.updateMacroEditor("") if not self.disableEditMode and self.disableSpockCommandUpdate: self.validateAllExpresion() else: txt_parts = str(self.text()).split() if len(txt_parts) == 0: return try: if self.validateMacro(txt_parts[0]): self.validateAllExpresion() except: self.setToolTip("Read Mode") def validateMacro(self, value): # Method which ivestigates if the macro can be edited using yellow line. # It cannot be executed when: 1. there are more than 1 ParamRepeatNodes, # 2. There is a ParamRepeatNode inside ParamRepeatNodem # 3. After ParamRepeatNode there are other nodes macroNode = self.getModelObj().getMacroNodeObj(str(value)) if macroNode is None: return False t = [child for child in macroNode.children() if isinstance(child, macro.RepeatParamNode)] if len(t) > 1: self.disableEditMode = True raise Exception( 'Macro <b> %s </b> cannot be edited using yellow line.<br>It contains more than 1 paramRepeat node. <br>Please use Macro Editor Widget to edit and execute this macro.' % str(value)) elif len(t) == 1: if len([child for child in t[0].children() if isinstance(child, macro.RepeatParamNode)]) > 0: self.disableEditMode = True raise Exception( 'Macro <b> %s </b> cannot be edited using yellow line.<br>It contains paramRepeat node inside paramRepeat node. <br>Please use Macro Editor Widget to edit and execute this macro.' % str(value)) else: if macroNode.children().index(t[0]) != len(macroNode.children()) - 1: self.disableEditMode = True raise Exception( 'Macro <b> %s </b> cannot be edited using yellow line.<br>It contains paramRepeat node but not as a last parameter. <br>Please use Macro Editor Widget to edit and execute this macro.' % str(value)) self.disableEditMode = False return True def downAction(self): # Goes down in the history list of executed macros. # self.disableSpockCommandUpdate flag is used to allow updating yellow # line when model is changed. (when new row in history is chosen) self.disableSpockCommandUpdate = False self.elementDown.emit() text = str(self.text()).split() if len(text) > 0: self.validateMacro(text[0]) self.disableSpockCommandUpdate = True def upAction(self): self.disableSpockCommandUpdate = False self.elementUp.emit() text = str(self.text()).split() if len(text) > 0: self.validateMacro(text[0]) self.disableSpockCommandUpdate = True def controlDownAction(self): c = self.cursorPosition() newValue = False try: if self.text()[c] == " " and self.text()[c - 1] == " ": newValue = True except IndexError: if c == 0: newValue = True elif len(self.text()) == self.cursorPosition() and self.text()[c - 1] == " ": newValue = True try: txt = str(self.text()) txt = txt[:txt.find(" ", c)] except IndexError: txt = str(self.text())[:c] elementsNum = txt.split() if newValue: self.insert("0") self.currentIndex = self.getIndex(len(elementsNum)) if not self.currentIndex.isValid(): if len(elementsNum) > 0: self.backspace() return value = self.prevValue("") self.backspace() self.insert(value) self.model().setData(self.currentIndex, value) else: self.currentIndex = self.getIndex(len(elementsNum) - 1) if not self.currentIndex.isValid(): if len(elementsNum) > 1: return value = self.prevValue(elementsNum[len(elementsNum) - 1]) sel = self.measureSelection(self.cursorPosition()) self.setSelection(sel[0], sel[1]) c = c - (sel[1] - len(str(value))) self.insert(value) self.setCursorPosition(c) self.model().setData(self.currentIndex, value) def controlUpAction(self): c = self.cursorPosition() newValue = False try: if self.text()[c] == " " and self.text()[c - 1] == " ": newValue = True except IndexError: if c == 0: newValue = True elif len(self.text()) == self.cursorPosition() and self.text()[c - 1] == " ": newValue = True try: txt = str(self.text()) txt = txt[:txt.find(" ", c)] except IndexError: txt = str(self.text())[:c] elementsNum = txt.split() if newValue: self.insert("0") self.currentIndex = self.getIndex(len(elementsNum)) if not self.currentIndex.isValid(): if len(elementsNum) > 0: self.backspace() return value = self.nextValue("") self.backspace() self.insert(value) self.model().setData(self.currentIndex, value) else: self.currentIndex = self.getIndex(len(elementsNum) - 1) if not self.currentIndex.isValid(): if len(elementsNum) > 1: return value = self.nextValue(elementsNum[len(elementsNum) - 1]) sel = self.measureSelection(self.cursorPosition()) self.setSelection(sel[0], sel[1]) c = c - (sel[1] - len(str(value))) self.insert(value) self.setCursorPosition(c) self.model().setData(self.currentIndex, value) def getParamItems(self, index): # Returns list of items that can be chosen for the node corresponding # to the given index. Used by {next,prev}Value methods node = self.model().nodeFromIndex(index) if isinstance(node, macro.MacroNode): return None type = node.type() ms = self.getParentModelObj() items = list(ms.getElementsWithInterface(type).keys()) return items, type def nextValue(self, current): current = str(current) if self.currentIndex.isValid(): items, type = self.getParamItems(self.currentIndex) items = sorted(items) else: items = self.getParentModelObj().getMacroStrList() items = sorted(items) type = "Macro" if type == "Float": value = float(current) + 0.1 elif type == "Integer": value = int(current) + 1 elif type == "Boolean": value = True else: try: textindex = items.index(current) value = items[textindex - 1] except: tmpitems = [s for s in items if s.startswith(current)] if len(tmpitems) > 0: value = tmpitems[0] else: value = items[0] return str(value) def prevValue(self, current): current = str(current) if self.currentIndex.isValid(): items, type = self.getParamItems(self.currentIndex) items = sorted(items) else: items = self.getParentModelObj().getMacroStrList() items = sorted(items) type = "Macro" if type == "Float": value = float(current) - 0.1 elif type == "Integer": value = int(current) - 1 elif type == "Boolean": value = True else: try: textindex = items.index(current) value = items[textindex + 1] except: tmpitems = [s for s in items if s.startswith(current)] if len(tmpitems) > 0: value = tmpitems[0] else: value = items[0] return str(value) def updateMacroEditor(self, macroName): # I had to make the macroname lowered as macros in comboBox (with macros), has names with all letter low. # Because of that sometimes it was not loading macros in MacroEditor # TO FIX self.spockComboBox.emit(str(macroName).lower()) def measureSelection(self, position): s = str(self.text()) + " " try: if s[position] == " ": position -= 1 except IndexError: position -= 1 end = s.find(' ', position) beg = s.rfind(' ', 0, position + 1) if end == -1: end = s.length() - 1 return beg + 1, end - beg - 1 # returns the start and length of the value def focusInEvent(self, event): self.disableSpockCommandUpdate = True Qt.QLineEdit.focusInEvent(self, event) def focusOutEvent(self, event): self.disableSpockCommandUpdate = False Qt.QLineEdit.focusOutEvent(self, event)
def rowCount(self, index=Qt.QModelIndex()): return len(self.curves)
def setModel(self, model): self._model = model if isinstance(model, ParamEditorModel): self.setRootIndex(Qt.QModelIndex())
def showCalendar(self, target): return self.qcalendar = Qt.QCalendarWidget() self.qcalendar.show()
def setTable(self, model, filters=[]): ''' This method overrides TaurusPropTable.setTable(), which connects with TaurusClassTable This method fill the table with the names of properties and values for the device selected ''' try: model = model and fandango.tango.parse_tango_model(str(model)) if model is None: self.warning( 'VaccaPropTable.setTable(%s(%s)): MODEL NOT PARSABLE!' % (type(model), model)) return else: try: model = model['device'] except: model = str(model) self.debug('VaccaPropTable.setTable(%s(%s))' % (type(model), model)) #TaurusPropTable.setTable(self,model) Qt.QObject.disconnect(self, Qt.SIGNAL("cellChanged(int,int)"), self.valueChanged) self.db = fandango.get_database() dev_name = str(model) self.list_prop = list( self.db.get_device_property_list(dev_name, '*')) neg = ['polled_attr' ] + [f[1:] for f in filters if f.startswith('!')] pos = [f for f in filters if not f.startswith('!')] self.list_prop = [ p for p in self.list_prop if (not pos or fandango.matchAny(pos, p)) and not fandango.matchAny(neg, p) ] 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('VaccaPropTable: 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 #if isinstance(value,list):#type(value) is list: heigh1 = len(value) value = '\n'.join( str(v) for v in value ) # adding new lines in between elements in the list self.setText(str(value), i, 1) self.updateStyle() self.dev_name = dev_name #self.dev_obj = taurus.Device(dev_name) self.setWindowTitle('%s Properties' % dev_name) self.resizeColumnsToContents() self.resizeRowsToContents() except: traceback.print_exc()
class CurvesAppearanceChooser(Qt.QWidget): """ A plot_item for choosing plot appearance for one or more curves. The current curves properties are passed using the setCurves() method using a dictionary with the following structure:: curvePropDict={name1:prop1, name2:prop2,...} where propX is an instance of :class:`CurveAppearanceProperties` When applying, a signal is emitted and the chosen properties are made available in a similar dictionary. """ NAME_ROLE = Qt.Qt.UserRole controlChanged = Qt.pyqtSignal() curveAppearanceChanged = Qt.pyqtSignal(object, list) CurveTitleEdited = Qt.pyqtSignal('QString', 'QString') def __init__(self, parent=None, curvePropDict={}, showButtons=False, autoApply=False, Y2Axis=None, curvePropAdapter=None): # try: super(CurvesAppearanceChooser, self).__init__(parent) self.loadUi() self.autoApply = autoApply self.sStyleCB.insertItems(0, sorted(NamedSymbolStyles.values())) self.lStyleCB.insertItems(0, list(NamedLineStyles.values())) self.cStyleCB.insertItems(0, list(NamedCurveStyles.values())) self.sColorCB.addItem("") self.lColorCB.addItem("") if not showButtons: self.applyBT.hide() self.resetBT.hide() for color in NamedColors: icon = self._colorIcon(color) self.sColorCB.addItem(icon, "", Qt.QColor(color)) self.lColorCB.addItem(icon, "", Qt.QColor(color)) self.__itemsDict = CaselessDict() self.setCurves(curvePropDict) # set the icon for the background button (stupid designer limitations # forces to do it programatically) self.bckgndBT.setIcon(Qt.QIcon(":color-fill.svg")) # connections. self.curvesLW.itemSelectionChanged.connect(self._onSelectedCurveChanged) self.curvesLW.itemChanged.connect(self._onItemChanged) self.applyBT.clicked.connect(self.onApply) self.resetBT.clicked.connect(self.onReset) self.sStyleCB.currentIndexChanged.connect(self._onSymbolStyleChanged) self.sStyleCB.currentIndexChanged.connect(self._onControlChanged) self.lStyleCB.currentIndexChanged.connect(self._onControlChanged) self.sColorCB.currentIndexChanged.connect(self._onControlChanged) self.lColorCB.currentIndexChanged.connect(self._onControlChanged) self.cStyleCB.currentIndexChanged.connect(self._onControlChanged) self.sSizeSB.valueChanged.connect(self._onControlChanged) self.lWidthSB.valueChanged.connect(self._onControlChanged) self.cAreaDSB.valueChanged.connect(self._onControlChanged) self.sFillCB.stateChanged.connect(self._onControlChanged) self.cFillCB.stateChanged.connect(self._onControlChanged) self.assignToY1BT.toggled[bool].connect(self.__onY1Toggled) self.assignToY2BT.toggled[bool].connect(self.__onY2Toggled) # self.bckgndBT.clicked.connect(self.changeBackgroundColor) # Disabled buttons until future implementations # (set background color and set curve labels) self.changeTitlesBT.setEnabled(False) self.bckgndBT.setEnabled(False) # disable the group box with the options for swap curves between Y axes if Y2Axis is None: self.groupBox.setEnabled(False) # set properties from curves for first launch of config dialog and # keeps a curvePropAdapter object self._onSelectedCurveChanged() self.curvePropAdapter = curvePropAdapter self.axis = None def __onY1Toggled(self, checked): if checked: self.assignToY2BT.setChecked(False) def __onY2Toggled(self, checked): if checked: self.assignToY1BT.setChecked(False) def changeBackgroundColor(self): """Launches a dialog for choosing the parent's canvas background color """ color = Qt.QColorDialog.getColor( self.curvePropAdapter.getBackgroundColor(), self) if Qt.QColor.isValid(color): self.curvePropAdapter.setBackgroundColor(color) def setCurves(self, curvePropDict): """Populates the list of curves from the properties dictionary. It uses the curve title for display, and stores the curve name as the item data (with role=CurvesAppearanceChooser.NAME_ROLE) :param curvePropDict: (dict) a dictionary whith keys=curvenames and values= :class:`CurveAppearanceProperties` object """ self.curvePropDict = curvePropDict self._curvePropDictOrig = copy.deepcopy(curvePropDict) self.curvesLW.clear() self.__itemsDict = CaselessDict() for name, prop in self.curvePropDict.items(): # create and insert the item item = Qt.QListWidgetItem(prop.title, self.curvesLW) self.__itemsDict[name] = item item.setData(self.NAME_ROLE, name) item.setToolTip("<b>Curve Name:</b> %s" % name) item.setFlags(Qt.Qt.ItemIsEnabled | Qt.Qt.ItemIsSelectable | Qt.Qt.ItemIsUserCheckable | Qt.Qt.ItemIsDragEnabled | Qt.Qt.ItemIsEditable) self.curvesLW.setCurrentRow(0) def _onItemChanged(self, item): """slot used when an item data has changed""" name = item.data(self.NAME_ROLE) previousTitle = self.curvePropDict[name].title currentTitle = item.text() if previousTitle != currentTitle: self.curvePropDict[name].title = currentTitle self.CurveTitleEdited.emit(name, currentTitle) def updateTitles(self, newTitlesDict=None): """ Updates the titles of the curves that are displayed in the curves list. :param newTitlesDict: (dict<str,str>) dictionary with key=curve_name and value=title """ if newTitlesDict is None: return for name, title in newTitlesDict.items(): self.curvePropDict[name].title = title self.__itemsDict[name].setText(title) def getSelectedCurveNames(self): """Returns the curve names for the curves selected at the curves list. *Note*: The names may differ from the displayed text, which corresponds to the curve titles (this method is what you likely need if you want to get keys to use in curves or curveProp dicts). :return: (string_list) the names of the selected curves """ return [item.data(self.NAME_ROLE) for item in self.curvesLW.selectedItems()] def showProperties(self, prop=None): """Updates the dialog to show the given properties. :param prop: (CurveAppearanceProperties) the properties object containing what should be shown. If a given property is set to CONFLICT, the corresponding plot_item will show a "neutral" display """ if prop is None: prop = self._shownProp # set the Style comboboxes self.sStyleCB.setCurrentIndex( self.sStyleCB.findText(NamedSymbolStyles[prop.sStyle])) self.lStyleCB.setCurrentIndex( self.lStyleCB.findText(NamedLineStyles[prop.lStyle])) self.cStyleCB.setCurrentIndex( self.cStyleCB.findText(NamedCurveStyles[prop.cStyle])) if prop.y2 is CONFLICT: self.assignToY1BT.setChecked(False) self.assignToY2BT.setChecked(False) elif prop.y2: self.assignToY2BT.setChecked(True) else: self.assignToY1BT.setChecked(True) # set sSize and lWidth spinboxes. if prop.sSize is None, it puts -1 # (which is the special value for these switchhboxes) if prop.sSize is CONFLICT or prop.sStyle is None: self.sSizeSB.setValue(-1) else: self.sSizeSB.setValue(max(prop.sSize, -1)) if prop.lWidth is CONFLICT: self.lWidthSB.setValue(-1) else: self.lWidthSB.setValue(max(prop.lWidth, -1)) # Set the Color combo boxes. The item at index 0 is the empty one in # the comboboxes Manage unknown colors by including them if prop.sColor in (None, CONFLICT) or prop.sStyle is None: index = 0 else: index = self.sColorCB.findData(Qt.QColor(prop.sColor)) if index == -1: # if the color is not supported, add it to combobox index = self.sColorCB.count() self.sColorCB.addItem(self._colorIcon( Qt.QColor(prop.sColor)), "", Qt.QColor(prop.sColor)) self.sColorCB.setCurrentIndex(index) if prop.lColor is None or prop.lColor is CONFLICT: index = 0 else: index = self.lColorCB.findData(Qt.QColor(prop.lColor)) if index == -1: # if the color is not supported, add it to combobox index = self.lColorCB.count() self.lColorCB.addItem(self._colorIcon( Qt.QColor(prop.lColor)), "", Qt.QColor(prop.lColor)) self.lColorCB.setCurrentIndex(index) # set the Fill Checkbox. The prop.sFill value can be in 3 states: True, # False and None if prop.sFill is None or prop.sFill is CONFLICT: checkState = Qt.Qt.PartiallyChecked elif prop.sFill: checkState = Qt.Qt.Checked else: checkState = Qt.Qt.Unchecked self.sFillCB.setCheckState(checkState) # set the Area Fill Checkbox. The prop.cFill value can be in 3 states: # True, False and None if prop.cFill is CONFLICT: checkState = Qt.Qt.PartiallyChecked self.cAreaDSB.setValue(0.0) elif prop.cFill is None: checkState = Qt.Qt.Unchecked self.cAreaDSB.setValue(0.0) else: checkState = Qt.Qt.Checked self.cAreaDSB.setValue(prop.cFill) self.cFillCB.setCheckState(checkState) def _onControlChanged(self, *args): """ Slot to be called whenever a control plot_item is changed. It emits a `controlChanged` signal and applies the change if in autoapply mode. It ignores any arguments passed """ self.controlChanged.emit() if self.autoApply: self.onApply() def _onSelectedCurveChanged(self): """Updates the shown properties when the curve selection changes""" plist = [self.curvePropDict[name] for name in self.getSelectedCurveNames()] if len(plist) == 0: plist = [CurveAppearanceProperties()] self.lineGB.setEnabled(False) self.symbolGB.setEnabled(False) self.otherGB.setEnabled(False) else: self.lineGB.setEnabled(True) self.symbolGB.setEnabled(True) self.otherGB.setEnabled(True) self._shownProp = CurveAppearanceProperties.merge(plist) self.showProperties(self._shownProp) def _onSymbolStyleChanged(self, text): """Slot called when the Symbol style is changed, to ensure that symbols are visible if you choose them :param text: (str) the new symbol style label """ text = str(text) if self.sSizeSB.value() < 2 and not text in ["", "No symbol"]: # a symbol size of 0 is invisible and 1 means you should use # cStyle=dots self.sSizeSB.setValue(3) def getShownProperties(self): """Returns a copy of the currently shown properties and updates self._shownProp :return: (CurveAppearanceProperties) """ prop = CurveAppearanceProperties() for name in self.getSelectedCurveNames(): prop.title = self.curvePropDict[name].title # get the values from the Style comboboxes. Note that the empty string # ("") translates into CONFLICT prop.sStyle = ReverseNamedSymbolStyles[ str(self.sStyleCB.currentText())] prop.lStyle = ReverseNamedLineStyles[str(self.lStyleCB.currentText())] prop.cStyle = ReverseNamedCurveStyles[str(self.cStyleCB.currentText())] # get sSize and lWidth from the spinboxes (-1 means conflict) v = self.sSizeSB.value() if v == -1: prop.sSize = CONFLICT else: prop.sSize = v v = self.lWidthSB.value() if v == -1: prop.lWidth = CONFLICT else: prop.lWidth = v # Get the Color combo boxes. The item at index 0 is the empty one in # the comboboxes index = self.sColorCB.currentIndex() if index == 0: prop.sColor = CONFLICT else: prop.sColor = Qt.QColor(self.sColorCB.itemData(index)) index = self.lColorCB.currentIndex() if index == 0: prop.lColor = CONFLICT else: prop.lColor = Qt.QColor(self.lColorCB.itemData(index)) # get the sFill from the Checkbox. checkState = self.sFillCB.checkState() if checkState == Qt.Qt.PartiallyChecked: prop.sFill = CONFLICT else: prop.sFill = bool(checkState) # get the cFill from the Checkbox. checkState = self.cFillCB.checkState() if checkState == Qt.Qt.PartiallyChecked: prop.cFill = CONFLICT elif checkState == Qt.Qt.Checked: prop.cFill = self.cAreaDSB.value() else: prop.cFill = None # get the y2 state from the buttons y1 = self.assignToY1BT.isChecked() y2 = self.assignToY2BT.isChecked() if not y1 and not y2: prop.y2 = CONFLICT elif y1: prop.y2 = False elif y2: prop.y2 = True else: # both buttons should never be checked simultaneously raise RuntimeError('Inconsistent state of Y-axis buttons') # store the props self._shownProp = copy.deepcopy(prop) return copy.deepcopy(prop) def onApply(self): """Apply does 2 things: - It updates `self.curvePropDict` using the current values chosen in the dialog - It emits a curveAppearanceChanged signal that indicates the names of the curves that changed and the new properties. (TODO) :return: (tuple<CurveAppearanceProperties,list>) a tuple containing the curve properties and a list of the selected curve names (as a list<str>) """ names = self.getSelectedCurveNames() prop = self.getShownProperties() # Update self.curvePropDict for selected properties for n in names: self.curvePropDict[n] = CurveAppearanceProperties.merge( [self.curvePropDict[n], prop], conflict=CurveAppearanceProperties.inConflict_update_a) # emit a (PyQt) signal telling what properties (first argument) need to # be applied to which curves (second argument) # self.curveAppearanceChanged.emit(prop, names) # return both values self.curvePropAdapter.setCurveProperties(self.curvePropDict, names) return prop, names def onReset(self): """slot to be called when the reset action is triggered. It reverts to the original situation""" self.setCurves(self._curvePropDictOrig) self.curvesLW.clearSelection() def _colorIcon(self, color, w=10, h=10): # to do: create a border pixmap = Qt.QPixmap(w, h) pixmap.fill(Qt.QColor(color)) return Qt.QIcon(pixmap)
def __init__(self, parent=None, flags=Qt.Qt.WindowFlags()): self.parent = parent # if parent==None or not isinstance(parent, TaurusPlotConfigCapable): # raise NotImplementedError, "Parent object doesn't implement TaurusPlotConfigCapable class" # call qt designer generated functions to initialize GUI Qt.QDialog.__init__(self, parent, flags) self.loadUi() # insert the CurvesAppearanceWidget #(@TODO:must be changed to be done directly in the ui, but I couldn't make the widget available to TaurusDesigner) from curvesAppearanceChooserDlg import CurvesAppearanceChooser layout = Qt.QVBoxLayout() self.curvesAppearanceChooser = CurvesAppearanceChooser(None) layout.addWidget(self.curvesAppearanceChooser) self.ui.curveAppearanceGB.setLayout(layout) # set the values for the CurvesAppearanceChooser self.curvesAppearanceChooser.setCurves( self.parent.getCurveAppearancePropertiesDict()) # insert valid values into mode combobox (linear or logarihtmic) and # set selected one in combobox self.ui.xModeComboBox.insertItem(0, "Linear") self.ui.xModeComboBox.insertItem(1, "Logarithmic") self.ui.y1ModeComboBox.insertItem(0, "Linear") self.ui.y1ModeComboBox.insertItem(1, "Logarithmic") self.ui.y2ModeComboBox.insertItem(0, "Linear") self.ui.y2ModeComboBox.insertItem(1, "Logarithmic") # insert valid values into peaks combobox (max, min or both) and set # selected one in combobox self.ui.peaksComboBox.insertItem(0, "Both") self.ui.peaksComboBox.insertItem(1, "Max") self.ui.peaksComboBox.insertItem(2, "Min") self.ui.peaksComboBox.insertItem(3, "None") # Init X axis group self.ui.xRangeCB.setVisible(False) self.ui.xLabelRange.setVisible(False) if self.parent.getXIsTime(): # adapt the X axis group for time-based measurements self.ui.xRangeCB.addItems( ["", "1 m", "1 h", "1 d", "1 w", "30 d", "1 y"]) self.ui.xGroupBox.setTitle("Time") self.ui.xLabelMin.setText("Start") self.ui.xLabelMax.setText("End") timetooltip = """It accepts both absolute data-times (e.g. "25/10/1917 21:45:01") \n"""\ """or relative ones with format <+|-><number><s|m|h|d|w|y> (e.g. "-12h").\n"""\ """The keyword "now" is also accepted.""" self.ui.xEditMin.setToolTip(timetooltip) self.ui.xEditMax.setToolTip(timetooltip) else: # The default settings are ok for non-time plots self.ui.xEditMin.setValidator(Qt.QDoubleValidator(self)) self.ui.xEditMax.setValidator(Qt.QDoubleValidator(self)) self.ui.xRangeCB.setValidator(Qt.QDoubleValidator(self)) self.ui.xRangeCB.addItems( ["", "10", "100", "1000", "10000", "100000", "1000000"]) self.ui.xDynScaleCheckBox.setChecked(self.parent.getXDynScale()) auto = self.parent.axisAutoScale(Qwt5.QwtPlot.xBottom) self.ui.xAutoGroupBox.setChecked(not auto) # this call already initialises the edit boxes of the X axis self.setXDynScale(self.parent.getXDynScale()) self.ui.xDynScaleCheckBox.setVisible( self.parent.isXDynScaleSupported()) # Init Y axes groups self._populateYAxisScales() self.ui.y1AutoGroupBox.setChecked( not self.parent.axisAutoScale(Qwt5.QwtPlot.yLeft)) self.ui.y2AutoGroupBox.setChecked( not self.parent.axisAutoScale(Qwt5.QwtPlot.yRight)) # set validators for Y min/max edits self.ui.y1EditMin.setValidator(Qt.QDoubleValidator(self)) self.ui.y1EditMax.setValidator(Qt.QDoubleValidator(self)) self.ui.y2EditMin.setValidator(Qt.QDoubleValidator(self)) self.ui.y2EditMax.setValidator(Qt.QDoubleValidator(self)) # populate initial axis mode (linear or logarithmic) values from plot. Warning!: we're using # qwt QwtPlot.axis enum type to relate our GUI combo name and qwt axis # name (enum type). axes = [ self.ui.y1ModeComboBox, self.ui.y2ModeComboBox, self.ui.xModeComboBox ] for axis in range(len(axes)): scaleType = self.parent.getAxisTransformationType(axis) if scaleType == Qwt5.QwtScaleTransformation.Linear: axes[axis].setCurrentIndex(0) elif scaleType == Qwt5.QwtScaleTransformation.Log10: axes[axis].setCurrentIndex(1) else: raise TypeError, "TaurusPlotConfigDialog::__init__(): unexpected axis scale type (linear or logarihtmic expected)" self.ui.xModeComboBox.setEnabled(not self.parent.getXIsTime()) # determine which axes are visible if not self.parent.axisEnabled(Qwt5.QwtPlot.xBottom): self.ui.xGroupBox.setVisible(False) # populate initial peaks from parent if self.parent._showMaxPeaks and self.parent._showMinPeaks: self.ui.peaksComboBox.setCurrentIndex(0) elif self.parent._showMaxPeaks: self.ui.peaksComboBox.setCurrentIndex(1) elif self.parent._showMinPeaks: self.ui.peaksComboBox.setCurrentIndex(2) else: self.ui.peaksComboBox.setCurrentIndex(3) # connect signals self.ui.buttonBox.button(Qt.QDialogButtonBox.Close).clicked.connect( self.hide) self.ui.buttonBox.button(Qt.QDialogButtonBox.Apply).clicked.connect( self.apply) self.ui.xAutoGroupBox.toggled.connect(self.toggledAutoScale) self.ui.y1AutoGroupBox.toggled.connect(self.toggledAutoScale) self.ui.y2AutoGroupBox.toggled.connect(self.toggledAutoScale) # self.connect(self.ui.xEditMin, Qt.SIGNAL("returnPressed()"),self.apply) # self.connect(self.ui.xEditMax, Qt.SIGNAL("returnPressed()"),self.apply) # self.connect(self.ui.y1EditMin, Qt.SIGNAL("returnPressed()"),self.apply) # self.connect(self.ui.y1EditMax, Qt.SIGNAL("returnPressed()"),self.apply) # self.connect(self.ui.y2EditMin, Qt.SIGNAL("returnPressed()"),self.apply) # self.connect(self.ui.y2EditMax, Qt.SIGNAL("returnPressed()"),self.apply) self.ui.xModeComboBox.currentIndexChanged.connect( self.modeComboChanged) self.ui.xDynScaleCheckBox.toggled.connect(self.setXDynScale) #self.connect(self.ui.xRangeCB, Qt.SIGNAL("currentIndexChanged(const QString&)"),self.apply) self.ui.y1ModeComboBox.currentIndexChanged.connect( self.modeComboChanged) self.ui.y2ModeComboBox.currentIndexChanged.connect( self.modeComboChanged) self.ui.peaksComboBox.currentIndexChanged.connect( self.peaksComboChanged) # self.connect(self.curvesAppearanceChooser, # Qt.SIGNAL("controlChanged"),self.apply) #"autoapply" mode for *all* # the curve appearance controls self.curvesAppearanceChooser.assignToY1BT.clicked[()].connect( self.setCurvesYAxis) self.curvesAppearanceChooser.assignToY2BT.clicked[()].connect( self.setCurvesYAxis) self.curvesAppearanceChooser.bckgndBT.clicked.connect( self.changeBackgroundColor) self.curvesAppearanceChooser.changeTitlesBT.clicked.connect( self.onChangeTitles) self.curvesAppearanceChooser.CurveTitleEdited.connect( self.onCurveTitleEdited) # finally adjust size self.adjustSize()
def __init__(self, parent=None, curvePropDict={}, showButtons=False, autoApply=False, Y2Axis=None, curvePropAdapter=None): # try: super(CurvesAppearanceChooser, self).__init__(parent) self.loadUi() self.autoApply = autoApply self.sStyleCB.insertItems(0, sorted(NamedSymbolStyles.values())) self.lStyleCB.insertItems(0, list(NamedLineStyles.values())) self.cStyleCB.insertItems(0, list(NamedCurveStyles.values())) self.sColorCB.addItem("") self.lColorCB.addItem("") if not showButtons: self.applyBT.hide() self.resetBT.hide() for color in NamedColors: icon = self._colorIcon(color) self.sColorCB.addItem(icon, "", Qt.QColor(color)) self.lColorCB.addItem(icon, "", Qt.QColor(color)) self.__itemsDict = CaselessDict() self.setCurves(curvePropDict) # set the icon for the background button (stupid designer limitations # forces to do it programatically) self.bckgndBT.setIcon(Qt.QIcon(":color-fill.svg")) # connections. self.curvesLW.itemSelectionChanged.connect(self._onSelectedCurveChanged) self.curvesLW.itemChanged.connect(self._onItemChanged) self.applyBT.clicked.connect(self.onApply) self.resetBT.clicked.connect(self.onReset) self.sStyleCB.currentIndexChanged.connect(self._onSymbolStyleChanged) self.sStyleCB.currentIndexChanged.connect(self._onControlChanged) self.lStyleCB.currentIndexChanged.connect(self._onControlChanged) self.sColorCB.currentIndexChanged.connect(self._onControlChanged) self.lColorCB.currentIndexChanged.connect(self._onControlChanged) self.cStyleCB.currentIndexChanged.connect(self._onControlChanged) self.sSizeSB.valueChanged.connect(self._onControlChanged) self.lWidthSB.valueChanged.connect(self._onControlChanged) self.cAreaDSB.valueChanged.connect(self._onControlChanged) self.sFillCB.stateChanged.connect(self._onControlChanged) self.cFillCB.stateChanged.connect(self._onControlChanged) self.assignToY1BT.toggled[bool].connect(self.__onY1Toggled) self.assignToY2BT.toggled[bool].connect(self.__onY2Toggled) # self.bckgndBT.clicked.connect(self.changeBackgroundColor) # Disabled buttons until future implementations # (set background color and set curve labels) self.changeTitlesBT.setEnabled(False) self.bckgndBT.setEnabled(False) # disable the group box with the options for swap curves between Y axes if Y2Axis is None: self.groupBox.setEnabled(False) # set properties from curves for first launch of config dialog and # keeps a curvePropAdapter object self._onSelectedCurveChanged() self.curvePropAdapter = curvePropAdapter self.axis = None
class MacroSequenceTree(Qt.QTreeView, BaseConfigurableClass): macroNameChanged = Qt.pyqtSignal('QString') macroChanged = Qt.pyqtSignal(compat.PY_OBJECT) def __init__(self, parent=None): Qt.QTreeView.__init__(self, parent) BaseConfigurableClass.__init__(self) self._idIndexDict = {} self.setSelectionBehavior(Qt.QTreeView.SelectRows) self.setSelectionMode(Qt.QTreeView.SingleSelection) self.setRootIsDecorated(False) # self.setItemsExpandable(False) self.setDragEnabled(True) self.setAcceptDrops(True) self.setTabKeyNavigation(True) self.setEditTriggers(Qt.QAbstractItemView.EditKeyPressed | Qt.QAbstractItemView.CurrentChanged) self.setDropIndicatorShown(True) self.deleteAction = Qt.QAction( Qt.QIcon.fromTheme("list-remove"), "Remove macro", self) self.deleteAction.triggered.connect(self.deleteMacro) self.deleteAction.setToolTip( "Clicking this button will remove current macro.") self.moveUpAction = Qt.QAction(Qt.QIcon.fromTheme("go-up"), "Move up", self) self.moveUpAction.triggered.connect(self.upMacro) self.moveUpAction.setToolTip( "Clicking this button will move current macro up.") self.moveDownAction = Qt.QAction( Qt.QIcon.fromTheme("go-down"), "Move down", self) self.moveDownAction.triggered.connect(self.downMacro) self.moveDownAction.setToolTip( "Clicking this button will move current macro down.") self.moveLeftAction = Qt.QAction( Qt.QIcon.fromTheme("go-previous"), "Move left", self) self.moveLeftAction.triggered.connect(self.leftMacro) self.moveLeftAction.setToolTip( "Clicking this button will move current macro to the left.") self.moveRightAction = Qt.QAction( Qt.QIcon.fromTheme("go-next"), "Move right", self) self.moveRightAction.triggered.connect(self.rightMacro) self.moveRightAction.setToolTip( "Clicking this button will move current macro to the right.") def disableActions(self): self.deleteAction.setEnabled(False) self.moveUpAction.setEnabled(False) self.moveDownAction.setEnabled(False) self.moveLeftAction.setEnabled(False) self.moveRightAction.setEnabled(False) def contextMenuEvent(self, event): contextMenu = Qt.QMenu() proxyIndex = self.indexAt(event.pos()) node = self.model().nodeFromIndex(proxyIndex) # this is in case if we right click on an empty field of tree if not isinstance(node, MacroNode): return parentNode = node.parent() # this is in case if we right click on a top level macro if not isinstance(parentNode, MacroNode): return allowedHooks = parentNode.allowedHookPlaces() if allowedHooks: hookPlacesSubmenu = contextMenu.addMenu("Hook places") for allowedHook in allowedHooks: action = HookAction(allowedHook, self, node) hookPlacesSubmenu.addAction(action) contextMenu.exec_(event.globalPos()) # def setHint(self, add): # action = self.sender() # hookText = action.text() # macroNode = action.macroNode() # if add: # macroNode.addHook(hookText) # else: # macroNode.removeHook(hookText) # pass def selectionChanged(self, selected, deselected): self.disableActions() macroName = None node, proxyIndex = self.selectedNodeAndIndex() if node is not None: macroName = node.name() self.deleteAction.setEnabled(True) self.moveUpAction.setEnabled(node.isAllowedMoveUp()) self.moveDownAction.setEnabled(node.isAllowedMoveDown()) self.moveLeftAction.setEnabled(node.isAllowedMoveLeft()) self.moveRightAction.setEnabled(node.isAllowedMoveRight()) sourceIndex = self.model().mapToSource(proxyIndex) self.macroChanged.emit(sourceIndex) self.macroNameChanged.emit(macroName) def expanded(self): for column in range(self.model().columnCount(Qt.QModelIndex())): self.resizeColumnToContents(column) def clearTree(self): self.model().clearSequence() def toXmlString(self, pretty=False, withId=True): return self.model().toXmlString(pretty=pretty, withId=withId) def fromXmlString(self, xmlString): newRoot = self.model().fromXmlString(xmlString) self.expandAll() self.expanded() return newRoot def fromPlainText(self, plainTextMacros, macroInfos): newRoot = self.model().fromPlainText(plainTextMacros, macroInfos) self.expandAll() self.expanded() return newRoot def root(self): return self.model().root() def setRoot(self, root): self.model().beginResetModel() self.model().setRoot(root) self.model().endResetModel() def addMacro(self, macroNode): node, proxyIndex = self.selectedNodeAndIndex() if node is None or not node.isAllowedHooks(): proxyIndex = self.rootIndex() sourceIndex = self.model().mapToSource(proxyIndex) newSourceIndex = self.model()._insertRow(sourceIndex, macroNode) newProxyIndex = self.model().mapFromSource(newSourceIndex) # persistentProxyIndex = Qt.QPersistentModelIndex(newProxyIndex) # self._idIndexDict[macroNode.id()] = persistentProxyIndex self.setCurrentIndex(newProxyIndex) self.expandAll() self.expanded() def deleteMacro(self): node, proxyIndex = self.selectedNodeAndIndex() sourceIndex = self.model().mapToSource(proxyIndex) self.model()._removeRow(sourceIndex) # self._idIndexDict.pop(node.id()) self.expandAll() self.expanded() def upMacro(self): node, proxyIndex = self.selectedNodeAndIndex() sourceIndex = self.model().mapToSource(proxyIndex) newSourceIndex = self.model()._upRow(sourceIndex) newProxyIndex = self.model().mapFromSource(newSourceIndex) # persistentProxyIndex = Qt.QPersistentModelIndex(newProxyIndex) # self._idIndexDict[node.id()] = persistentProxyIndex self.setCurrentIndex(newProxyIndex) self.expandAll() # self.expanded() def downMacro(self): node, proxyIndex = self.selectedNodeAndIndex() sourceIndex = self.model().mapToSource(proxyIndex) newSourceIndex = self.model()._downRow(sourceIndex) newProxyIndex = self.model().mapFromSource(newSourceIndex) # persistentProxyIndex = Qt.QPersistentModelIndex(newProxyIndex) # self._idIndexDict[node.id()] = persistentProxyIndex self.setCurrentIndex(newProxyIndex) self.expandAll() # self.expanded() def leftMacro(self): node, proxyIndex = self.selectedNodeAndIndex() sourceIndex = self.model().mapToSource(proxyIndex) newSourceIndex = self.model()._leftRow(sourceIndex) newProxyIndex = self.model().mapFromSource(newSourceIndex) # persistentProxyIndex = Qt.QPersistentModelIndex(newProxyIndex) # self._idIndexDict[node.id()] = persistentProxyIndex self.setCurrentIndex(newProxyIndex) self.expandAll() self.expanded() def rightMacro(self): node, proxyIndex = self.selectedNodeAndIndex() sourceIndex = self.model().mapToSource(proxyIndex) newSourceIndex = self.model()._rightRow(sourceIndex) newProxyIndex = self.model().mapFromSource(newSourceIndex) # persistentProxyIndex = Qt.QPersistentModelIndex(newProxyIndex) # self._idIndexDict[node.id()] = persistentProxyIndex self.setCurrentIndex(newProxyIndex) self.expandAll() self.expanded() def prepareMacroIds(self): model = self.model() ids = model.assignIds() firstId = model.firstMacroId() lastId = model.lastMacroId() return firstId, lastId, ids def prepareMacroProgresses(self): self._idIndexDict = self.model().createIdIndexDictionary() for macroId in self._idIndexDict.keys(): self.setProgressForMacro(macroId, 0) def setProgressForMacro(self, macroId, progress): persistentIndex = self._idIndexDict.get(macroId, None) if persistentIndex is None: return progressIndex = persistentIndex.sibling(persistentIndex.row(), 2) index = Qt.QModelIndex(progressIndex) self.model().setData(index, progress) def setRangeForMacro(self, macroId, range): persistentIndex = self._idIndexDict.get(macroId, None) if persistentIndex is None: return index = Qt.QModelIndex(persistentIndex) node = self.model().nodeFromIndex(index) node.setRange(range) def selectedNodeAndIndex(self): """Returns a tuple with selected internal model node object and QModelIndex from current model.""" for idx in self.selectedIndexes(): if idx.column() == 0: node = self.model().nodeFromIndex(idx) break else: node, idx = None, None return node, idx def dropEvent(self, event): Qt.QTreeView.dropEvent(self, event) self.expandAll()
def columnCount(self, index=Qt.QModelIndex()): return self.ncolumns
class TaurusJDrawSynopticsView(Qt.QGraphicsView, TaurusBaseWidget): ''' Taurus Class that visualizes Synoptics drawn with the JDraw tool (by ESRF). It is equivalent to ATK Synoptic Player (Java). After initialization call setModel('/your/file.jdw') to parse the synoptic file and connect to controlled objects. Arguments to TaurusJDrawSynopticsView() creator are: - designMode; used by Qt Designer - updateMode; controls Qt Viewport refresh (disabled by default) - alias; a dictionary of name replacements to be applied on graphical objects - resizable: whether to allow resizing or not - panelClass: class object, class name or shell command to be shown when an object is clicked (None will show default panel, '' or 'noPanel' will disable it) TaurusJDrawSynopticsView and TaurusGraphicsScene signals/slots External events:: Slot selectGraphicItem(const QString &) displays a selection mark around the TaurusGraphicsItem that matches the argument passed. Mouse Left-button events:: Signal graphicItemSelected(QString) is triggered, passing the selected TaurusGraphicsItem.name() as argument. Mouse Right-button events:: TaurusGraphicsItem.setContextMenu([(ActionName,ActionMethod(device_name))] allows to configure custom context menus for graphic items using a list of tuples. Empty tuples will insert separators in the menu. ''' itemsChanged = Qt.pyqtSignal(str, dict) modelsChanged = Qt.pyqtSignal(list) graphicItemSelected = Qt.pyqtSignal('QString') graphicSceneClicked = Qt.pyqtSignal('QPoint') def __init__(self, parent=None, designMode=False, updateMode=None, alias=None, resizable=True, panelClass=None): name = self.__class__.__name__ self.call__init__wo_kw(Qt.QGraphicsView, parent) self.call__init__(TaurusBaseWidget, name, designMode=designMode) self._currF = self.modelName self.path = '' self.w_scene = None self.h_scene = None self._fileName = "Root" self._mousePos = (0, 0) self._selectionStyle = SynopticSelectionStyle.OUTLINE self.setResizable(resizable) self.setInteractive(True) self.setAlias(alias) self.setDragEnabled(True) self.setPanelClass(panelClass) # By default the items will update the view when necessary. # This default value is much more efficient then the QQraphicsView default # value, so if you decide to change then expect a lot of processor to be # used by your application. if updateMode is None: self.setViewportUpdateMode(Qt.QGraphicsView.NoViewportUpdate) else: self.setViewportUpdateMode(updateMode) def defineStyle(self): self.updateStyle() #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusBaseWidget over writing #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def isReadOnly(self): return True def update(self): # self.emit_signal() self.emitColors() def openJDraw(self): ifile = unicode(Qt.QFileDialog.getOpenFileName( self, 'Load JDraw File', '', 'JDraw File (*.jdw)')) if not ifile: return fileName = ifile.split("/") self._fileName = fileName[-1] self.setModel(ifile) return fileName[-1] def setAlias(self, alias): """ Assigning a dictionary like {'Tag':'Value'} with tags to be replaced in object names while parsing. """ if (isinstance(alias, dict) or hasattr(alias, 'items')) and alias: self.alias = alias else: self.alias = None return def get_item_list(self): return [item._name for item in self.scene().items() if hasattr(item, '_name') and item._name] def get_device_list(self): items = [(item, parseTangoUri(item)) for item in self.get_item_list()] return list(set(v['_devslashname'] for k, v in items if v)) def get_item_colors(self, emit=False): item_colors = {} try: for item in self.scene().items(): if not getattr(item, '_name', '') or not getattr(item, '_currBgBrush', None): continue item_colors[item._name] = item._currBgBrush.color().name() if emit: self.itemsChanged.emit(self.modelName.split( '/')[-1].split('.')[0], item_colors) except: self.warning('Unable to emitColors: %s' % traceback.format_exc()) return item_colors @Qt.pyqtSlot('QString') def selectGraphicItem(self, item_name): self.scene().selectGraphicItem(item_name) return False def _graphicItemSelected(self, item_name): self.debug(' => graphicItemSelected(QString)(%s)' % item_name) self.graphicItemSelected.emit(item_name) def _graphicSceneClicked(self, point): self.debug('In TaurusJDrawSynopticsView.graphicSceneClicked(%s,%s)' % ( point.x(), point.y())) self.graphicSceneClicked.emit(point) def __modelsChanged(self): items = self.get_item_list() self.debug('modelsChanged(%s)' % len(items)) self.modelsChanged.emit(items) def emitColors(self): '''emit signal which is used to refresh the tree and colors of icons depend of the current status in jdrawSynoptic''' self.get_item_colors(True) def get_sizes(self): srect = self.scene().sceneRect() sizes = [x for s in (self.size(), self.sizeHint(), srect.size()) for x in (s.width(), s.height())] try: s = self.parent().size() sizes.extend([s.width(), s.height()]) except: sizes.extend([0, 0]) return tuple(sizes) def fitting(self, ADJUST_FRAME=False): """ Parent size is the size of the bigger panel (desn't keep ratio) Rect size never changes (fixed by the graphics objects) Size and SizeHint move one around the other the method works well until an object is clicked, then the whole reference changes and doesn't work again. """ srect = self.scene().sceneRect() w, h = (srect.width(), srect.height()) offset = self.mapToGlobal(Qt.QPoint(srect.x(), srect.y())) x0, y0 = (offset.x(), offset.y()) self.debug('\n\nIn TauJDrawSynopticsView.fitting()') self.debug(self.get_sizes()) self.debug( '\tAdjusting SizeHint: size(%s,%s),hint(%s,%s),srect(%s,%s),parent(%s,%s)' % self.get_sizes()) self.debug('\toffset = %s,%s ; size = %s,%s' % (x0, y0, w, h)) self.fitInView(x0, y0, w, h, Qt.Qt.KeepAspectRatio) # ------------------------------------------------------------------- # This block seems to be a poorly executed workaround to some # issue, but it is itself causing bugs (see # https://github.com/taurus-org/taurus/issues/484 ). # We are not removing it yet to preserve bck-compat # TODO: Deprecate the ADJUST_FRAME kwarg? if ADJUST_FRAME: # This additional resizing adjust the "white" frame around the synoptic self.debug( '\tResizing: size(%s,%s),hint(%s,%s),srect(%s,%s),parent(%s,%s)' % self.get_sizes()) self.resize(self.sizeHint() + Qt.QSize(5, 5)) # ------------------------------------------------------------------- # THIS LINE MUST BE ALWAYS EXECUTED, It prevents the UP/DOWN resize BUG!!! # apparently Qt needs this 2 fitInView calls to be aware of it, maybe # first offset was not good self.debug( '\tFitting:: size(%s,%s),hint(%s,%s),srect(%s,%s),parent(%s,%s)' % self.get_sizes()) self.fitInView(x0, y0, w, h, Qt.Qt.KeepAspectRatio) self.debug( 'Done: size(%s,%s),hint(%s,%s),srect(%s,%s),parent(%s,%s)\n\n' % self.get_sizes()) def resizeEvent(self, event): """ It has been needed to reimplent size policies """ if not self.resizable() or not self.scene() or isinstance(self.parent(), Qt.QScrollArea) or not self.isVisible(): self.debug('In TaurusJDrawSynopticsView(' + self._fileName + ').resizeEvent(): Disabled') return try: self.debug('In TaurusJDrawSynopticsView(' + self._fileName + ').resizeEvent()') if self.size() == self.sizeHint(): self.debug('\tSize already fits: %s' % self.size()) return self.setVerticalScrollBarPolicy(Qt.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.Qt.ScrollBarAlwaysOff) self.fitting() self.emitColors() except Exception: self.warning('Exception in JDrawView(' + self._fileName + ').resizeEvent: %s' % traceback.format_exc()) pass def refreshModel(self): self.setModel(self.getModelName()) def updateStyle(self): self.repaint() def repaint(self): Qt.QGraphicsView.repaint(self) # self.fitting() def getGraphicsFactory(self, delayed=False): import jdraw # self.parent()) return jdraw.TaurusJDrawGraphicsFactory(self, alias=(self.alias or None), delayed=delayed) ########################################################################### def getFramed(self): try: parent = self.parent() except: parent = None frame = Qt.QFrame(parent) self.setFrameStyle(self.StyledPanel | self.Raised) self.setLineWidth(2) self.setParent(frame) return frame def setResizable(self, resizable): self._resizable = resizable def resizable(self): return self._resizable def mousePressEvent(self, event): """ Records last event position to use it for DragEvents """ try: self.mousePos = event.scenePos().x(), event.scenePos().y() except: self.mousePos = event.x(), event.y() self.debug('MouseEvent received is not a GraphicsScene event, using raw position %s' % str( self.mousePos)) TaurusBaseWidget.mousePressEvent(self, event) def getModelMimeData(self): """ Used for drag events """ model, mimeData = '', None try: #model = getattr(self.scene().itemAt(*self.mousePos),'_name','') selected = self.scene()._selectedItems if not selected: self.debug( 'jdrawView.getModelMimeData(%s): nothing to drag' % model) return model = getattr(([s for s in selected if s.isUnderMouse() and getattr( s, '_name', '')] or [selected])[0], '_name', '') self.debug('getModelMimeData(%s)' % model) mimeData = Qt.QMimeData() if model: taurusType = taurushelper.getValidTypesForName(model, False) if TaurusElementType.Device in taurusType: self.debug('getMimeData(): DeviceModel at %s: %s', self.mousePos, model) mimeData.setData(TAURUS_DEV_MIME_TYPE, model) if TaurusElementType.Attribute in taurusType: self.debug('getMimeData(): AttributeModel at %s: %s', self.mousePos, model) mimeData.setData(TAURUS_ATTR_MIME_TYPE, model) else: self.debug('getMimeData(): UnknownModel at %s: %s', self.mousePos, model) mimeData.setData(TAURUS_MODEL_MIME_TYPE, model) except: self.debug( 'jdrawView.getModelMimeData(%s): unable to get MimeData' % model) self.debug(traceback.format_exc()) return mimeData #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @classmethod def setDefaultPanelClass(klass, other): """ This method returns the Class used to open new object panels on double-click (TaurusDevicePanel by default) """ klass._defaultClass = other @classmethod def defaultPanelClass(klass): """ This method assigns the Class used to open new object panels on double-click (TaurusDevicePanel by default) If an string is used it can be either a Taurus class or an OS launcher """ if not hasattr(klass, '_defaultClass'): from taurus.qt.qtgui.panel import TaurusDevicePanel # 'taurusdevicepanel' #You can use an executable or a class klass._defaultClass = TaurusDevicePanel obj = klass._defaultClass return obj def setPanelClass(self, widget): self._panelClass = widget def panelClass(self): if self._panelClass is None: return self.defaultPanelClass() else: return self._panelClass @Qt.pyqtSlot('QString') def setModel(self, model, alias=None, delayed=False, trace=False): self.modelName = str(model) self._currF = str(model) if alias is not None: self.setAlias(alias) ll = taurus.getLogLevel() if trace: taurus.setLogLevel(taurus.Debug) # self.debug('setModel("%s")'%model) if self._currF: #filename = str(self._currFile.absoluteFilePath()) filename = self._currF filename = os.path.realpath(filename) if os.path.isfile(filename): self.debug("Starting to parse %s" % filename) self.path = os.path.dirname(filename) factory = self.getGraphicsFactory(delayed=delayed) scene = jdraw_parser.parse(filename, factory) scene.setSelectionStyle(self._selectionStyle) self.debug("Obtained %s(%s)", type(scene).__name__, filename) if not scene: self.warning("TaurusJDrawSynopticsView.setModel(%s): Unable to parse %s!!!" % ( model, filename)) elif self.w_scene is None and scene.sceneRect(): self.w_scene = scene.sceneRect().width() self.h_scene = scene.sceneRect().height() else: self.debug('JDrawView.sceneRect() is NONE!!!') self.setScene(scene) self.scene().graphicItemSelected.connect(self._graphicItemSelected) self.scene().graphicSceneClicked.connect(self._graphicSceneClicked) # Qt.QApplication.instance().lastWindowClosed.connect(self.close) #It caused a # segfault! self.__modelsChanged() self.setWindowTitle(self.modelName) # The emitted signal contains the filename and a dictionary # with the name of items and its color self.emitColors() # get_item_colors(emit=True) self.fitting() else: self.setScene(None) #self.debug('out of setModel()') taurus.setLogLevel(ll) def closeEvent(self, event=None): if self.scene(): self.scene().closeAllPanels() Qt.QGraphicsView.closeEvent(self, event) def setModels(self): """ This method triggers item.setModel(item._name) in all internal items. """ for item in self.scene().items(): if item._name and isinstance(item, TaurusGraphicsItem): self.debug( 'TaurusJDrawGraphicsFactory.setModels(): calling item.setModel(%s)' % (item._name)) item.setModel(item._name) def getModel(self): return self._currF @classmethod def getQtDesignerPluginInfo(cls): ret = TaurusBaseWidget.getQtDesignerPluginInfo() ret['group'] = 'Taurus Display' ret['module'] = 'taurus.qt.qtgui.graphic' ret['icon'] = "designer:graphicsview.png" return ret model = Qt.pyqtProperty("QString", getModel, setModel) def setSelectionStyle(self, selectionStyle): if isinstance(selectionStyle, (Qt.QString, basestring)): selectionStyle = str(selectionStyle).upper() try: selectionStyle = SynopticSelectionStyle[selectionStyle] except: self.debug('invalid selectionStyle "%s"', selectionStyle) return if self.scene() is not None: self.scene().setSelectionStyle(selectionStyle) self._selectionStyle = selectionStyle def getSelectionStyle(self): return self._selectionStyle def getSelectionStyleName(self): return SynopticSelectionStyle.whatis(self.getSelectionStyle()) def resetSelectionStyle(self): self.setSelectionStyle(SynopticSelectionStyle.OUTLINE) selectionStyle = Qt.pyqtProperty("QString", getSelectionStyleName, setSelectionStyle, resetSelectionStyle)
def resetEnableWheelEvent(self): self.setEnableWheelEvent(False) @classmethod def getQtDesignerPluginInfo(cls): ret = TaurusBaseWritableWidget.getQtDesignerPluginInfo() ret['module'] = 'taurus.qt.qtgui.input' ret['icon'] = "designer:lineedit.png" return ret #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- model = Qt.pyqtProperty("QString", TaurusBaseWritableWidget.getModel, TaurusBaseWritableWidget.setModel, TaurusBaseWritableWidget.resetModel) useParentModel = Qt.pyqtProperty( "bool", TaurusBaseWritableWidget.getUseParentModel, TaurusBaseWritableWidget.setUseParentModel, TaurusBaseWritableWidget.resetUseParentModel) autoApply = Qt.pyqtProperty("bool", TaurusBaseWritableWidget.getAutoApply, TaurusBaseWritableWidget.setAutoApply, TaurusBaseWritableWidget.resetAutoApply) forcedApply = Qt.pyqtProperty("bool", TaurusBaseWritableWidget.getForcedApply, TaurusBaseWritableWidget.setForcedApply, TaurusBaseWritableWidget.resetForcedApply)
def __init__(self, src): self.display = '' self.icon = Qt.QIcon() self.ok = True self.processSrc(src)
def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.setObjectName(self.__class__.__name__) self._doorName = "" self._macroId = None self.setLayout(Qt.QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.addToFavouritesAction = Qt.QAction( Qt.QIcon("status:software-update-available.svg"), "Add to favourites", self) self.addToFavouritesAction.triggered.connect(self.onAddToFavourites) self.addToFavouritesAction.setToolTip("Add to favourites") self.stopMacroAction = Qt.QAction( Qt.QIcon("actions:media_playback_stop.svg"), "Stop macro", self) self.stopMacroAction.triggered.connect(self.onStopMacro) self.stopMacroAction.setToolTip("Stop macro") self.pauseMacroAction = Qt.QAction( Qt.QIcon("actions:media_playback_pause.svg"), "Pause macro", self) self.pauseMacroAction.triggered.connect(self.onPauseMacro) self.pauseMacroAction.setToolTip("Pause macro") self.playMacroAction = Qt.QAction( Qt.QIcon("actions:media_playback_start.svg"), "Start macro", self) self.playMacroAction.triggered.connect(self.onPlayMacro) self.playMacroAction.setToolTip("Start macro") actionsLayout = Qt.QHBoxLayout() actionsLayout.setContentsMargins(0, 0, 0, 0) addToFavouritsButton = Qt.QToolButton() addToFavouritsButton.setDefaultAction(self.addToFavouritesAction) self.addToFavouritesAction.setEnabled(False) actionsLayout.addWidget(addToFavouritsButton) self.macroComboBox = MacroComboBox(self) self.macroComboBox.setModelColumn(0) actionsLayout.addWidget(self.macroComboBox) stopMacroButton = Qt.QToolButton() stopMacroButton.setDefaultAction(self.stopMacroAction) actionsLayout.addWidget(stopMacroButton) pauseMacroButton = Qt.QToolButton() pauseMacroButton.setDefaultAction(self.pauseMacroAction) actionsLayout.addWidget(pauseMacroButton) self.playMacroButton = Qt.QToolButton() self.playMacroButton.setDefaultAction(self.playMacroAction) actionsLayout.addWidget(self.playMacroButton) self.disableControlActions() self.doorStateLed = TaurusLed(self) actionsLayout.addWidget(self.doorStateLed) self.layout().addLayout(actionsLayout) splitter = Qt.QSplitter(self) self.layout().addWidget(splitter) splitter.setOrientation(Qt.Qt.Vertical) self._paramEditorModel = ParamEditorModel() self.stackedWidget = Qt.QStackedWidget() self.standardMacroParametersEditor = StandardMacroParametersEditor( self.stackedWidget) self.stackedWidget.addWidget(self.standardMacroParametersEditor) self.customMacroParametersEditor = None splitter.addWidget(self.stackedWidget) self._favouritesBuffer = None self.favouritesMacrosEditor = FavouritesMacrosEditor(self) self.registerConfigDelegate(self.favouritesMacrosEditor) self.favouritesMacrosEditor.setFocusPolicy(Qt.Qt.NoFocus) self._historyBuffer = None self.historyMacrosViewer = HistoryMacrosViewer(self) self.registerConfigDelegate(self.historyMacrosViewer) self.historyMacrosViewer.setFocusPolicy(Qt.Qt.NoFocus) self.tabMacroListsWidget = Qt.QTabWidget(self) self.tabMacroListsWidget.addTab( self.favouritesMacrosEditor, "Favourite list") self.tabMacroListsWidget.addTab( self.historyMacrosViewer, "History Viewer") splitter.addWidget(self.tabMacroListsWidget) # Due to a limitation in the useParentModel architecture of Taurus, # the parent of historyMacrosViewer and favouritesMacrosEditor # must be recalculated. See more details in the taurus snippet code [1] # [1] https://raw.githubusercontent.com/taurus-org/taurus/develop/doc/source/devel/examples/parentmodel_issue_demo.py self.historyMacrosViewer.recheckTaurusParent() self.favouritesMacrosEditor.recheckTaurusParent() self._isHistoryMacro = False self.macroProgressBar = MacroProgressBar(self) self.layout().addWidget(self.macroProgressBar) #spockCommandLabel = Qt.QLabel("Spock command:", self) # spockCommandLabel.setFont(Qt.QFont("Courier",9)) self.spockCommand = SpockCommandWidget("Spock", self) self.spockCommand.setSizePolicy( Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum) spockCommandLayout = Qt.QHBoxLayout() spockCommandLayout.setContentsMargins(0, 0, 0, 0) # spockCommandLayout.addWidget(spockCommandLabel) spockCommandLayout.addWidget(self.spockCommand) self.layout().addLayout(spockCommandLayout) self.macroComboBox.currentIndexChanged['QString'].connect( self.onMacroComboBoxChanged) self.favouritesMacrosEditor.list.favouriteSelected.connect( self.onFavouriteSelected) self.historyMacrosViewer.list.historySelected.connect( self.onHistorySelected) self.spockCommand.pressedReturn.connect(self.onPlayMacro) self.spockCommand.spockComboBox.connect(self.setComboBoxItem) self.spockCommand.elementUp.connect(self.setHistoryUp) self.spockCommand.elementDown.connect(self.setHistoryDown) self.spockCommand.expandTree.connect( self.standardMacroParametersEditor.tree.expandAll)