def sizeHint(self, _, index: QModelIndex) -> QSize: """ Estimate the height of the row. This is mostly dependent on the tags attached to each item. """ data_item = index.model().data_items[index.row()] tags_disabled = self.get_bool_gui_setting("disable_tags") if data_item["type"] != REGULAR_TORRENT or tags_disabled: return QSize(0, DEFAULT_ROW_HEIGHT) name_column_width = index.model().name_column_width cur_tag_x = 6 cur_tag_y = TAG_TOP_MARGIN for tag_text in data_item.get("tags", ())[:MAX_TAGS_TO_SHOW]: text_width = self.font_metrics.horizontalAdvance(tag_text) tag_box_width = text_width + 2 * TAG_TEXT_HORIZONTAL_PADDING # Check whether this tag is going to overflow if cur_tag_x + tag_box_width >= name_column_width: cur_tag_x = 6 cur_tag_y += TAG_HEIGHT + 10 cur_tag_x += tag_box_width + TAG_HORIZONTAL_MARGIN # Account for the 'edit tags' button if cur_tag_x + TAG_HEIGHT >= name_column_width: cur_tag_y += TAG_HEIGHT + 10 return QSize(0, cur_tag_y + TAG_HEIGHT + 10)
def currentIndexChanged(self, editor: typing.Any, index: QModelIndex, curIndex: int): cur_Row = index.row() model = index.model() c_index = index.model().createIndex con = model.Condictions[cur_Row] if editor.currentData(): exp = self.expressionData[editor.currentIndex()] con.template = editor.currentData().template con.valueEnabled = editor.currentData().valueEnabled v0 = con.value[0] if con.valueEnabled[0] else None v1 = con.value[1] if con.valueEnabled[1] else None self.value = (v0, v1) con.titleEnglish = exp.titleEnglish con.titleChinese = exp.titleChinese # 如果条件是一个不用输入数据参数的条件,并且当前行是最后一行直接插入一个空行 if cur_Row == model.Condictions.count() - 1 and con.template == ( 0, 0): model.insertRow(model.Condictions.count()) else: con.value = (None, None) con.template = None con.valueEnabled = (0, 0) con.titleEnglish = None con.titleChinese = None # 发射信号更新界面相关数据 model.valueChanged() model.dataChanged.emit(c_index(cur_Row, COLUMN_VALUE1), c_index(cur_Row, COLUMN_VALUE2), [Qt.DisplayRole]) model.refreshValueDelegate(cur_Row)
class ImportExportManager(QObject): import_finished = pyqtSignal(int) export_finished = pyqtSignal(int) def __init__(self, target_widget, default_attrs=None): super().__init__(target_widget) self.target_widget = target_widget self.default_attrs = default_attrs self.export_action = create_action(None, "Export ...", self.handle_export_action) self.import_action = create_action(None, "Import ...", self.handle_import_action) self.model_index = QModelIndex() def populate_menu(self, menu): menu.addAction(self.export_action) menu.addAction(self.import_action) def connect_custom_context_menu(self): self.target_widget.setContextMenuPolicy(Qt.CustomContextMenu) self.target_widget.customContextMenuRequested.connect( self.show_context_menu) def show_context_menu(self, point): self.model_index = self.target_widget.indexAt(point) model_data = self.get_model_data() if model_data is not None: context_menu = QMenu() self.populate_menu(context_menu) context_menu.exec(self.target_widget.mapToGlobal(point)) def handle_export_action(self): if not self.model_index.isValid(): return data = self.get_model_data() attrs = list(data.keys()) dialog = ExportDialog.init(self.target_widget, data, attrs, self.default_attrs) dialog.finished.connect(self.export_finished.emit) dialog.open() def get_model_data(self): model = self.model_index.model() entry = model.data(self.model_index, Qt.UserRole) if entry: return entry.as_dict() def handle_import_action(self): if not self.model_index.isValid(): return model = self.model_index.model() entry = model.data(self.model_index, Qt.UserRole) attrs = entry.fields() dialog = ImportDialog.init(self.target_widget, attrs, self.default_attrs) if dialog: dialog.import_accepted.connect(entry.update) dialog.finished.connect(self.import_finished.emit) dialog.open()
def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex): if index.column() > 0: data = editor.currentData() index.model().setData(index, data, Qt.EditRole) model.clear456(index.row()) if data: self.Dialog.fieldChange(index, data)
def paint(self, painter: QPainter, option: QStyleOptionViewItem, model_index: QModelIndex): column = model_index.column() new_rect = QRect(option.rect) if column == NAME_COL: # Part Name option.displayAlignment = Qt.AlignVCenter QStyledItemDelegate.paint(self, painter, option, model_index) if column == LOCKED_COL: # Visibility element = _QCOMMONSTYLE.PE_IndicatorCheckBox styleoption = QStyleOptionButton() styleoption.rect = new_rect checked = model_index.model().data(model_index, Qt.EditRole) styleoption.state |= QStyle.State_On if checked else QStyle.State_Off # make the check box look a little more active by changing the pallete styleoption.palette.setBrush(QPalette.Button, Qt.white) styleoption.palette.setBrush(QPalette.HighlightedText, Qt.black) _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) if checked: # element = _QCOMMONSTYLE.PE_IndicatorMenuCheckMark # _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) # _QCOMMONSTYLE.drawItemText(painter, new_rect, Qt.AlignCenter, styleoption.palette, True, 'L') icon = QPixmap(":/outlinericons/lock") _QCOMMONSTYLE.drawItemPixmap(painter, new_rect, Qt.AlignCenter, icon) if column == VISIBLE_COL: # Visibility element = _QCOMMONSTYLE.PE_IndicatorCheckBox styleoption = QStyleOptionButton() styleoption.rect = new_rect checked = model_index.model().data(model_index, Qt.EditRole) styleoption.state |= QStyle.State_On if checked else QStyle.State_Off # make the check box look a little more active by changing the pallete styleoption.palette.setBrush(QPalette.Button, Qt.white) styleoption.palette.setBrush(QPalette.HighlightedText, Qt.black) _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) if checked: # element = _QCOMMONSTYLE.PE_IndicatorMenuCheckMark # _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) icon = QPixmap(":/outlinericons/eye") _QCOMMONSTYLE.drawItemPixmap(painter, new_rect, Qt.AlignCenter, icon) elif column == COLOR_COL: # Color # Alternate way to get color # outline_tw = self.parent() # item = outline_tw.itemFromIndex(model_index) # color = item.getColor() # print("COLOR_COL", item) color = model_index.model().data(model_index, Qt.EditRole) element = _QCOMMONSTYLE.PE_IndicatorCheckBox styleoption = QStyleOptionViewItem() brush = getBrushObj(color) styleoption.palette.setBrush(QPalette.Button, brush) styleoption.rect = new_rect _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) else: QStyledItemDelegate.paint(self, painter, option, model_index)
def setEditorData(self, editor: QWidget, index: QModelIndex): if isinstance(editor, ExternalProgramWidget): item = index.model().data(index) editor.extProgramLineEdit.setText(item) elif isinstance(editor, RandomValueWidget): items = index.model().data(index, Qt.EditRole) editor.spinBoxRandomMax.setValue(items[1]) editor.spinBoxRandomMin.setValue(items[0]) else: super().setEditorData(editor, index)
def setEditorData(self, editor: QWidget, index: QModelIndex) -> None: if isinstance(editor, FileAddressEditor): editor.setText(index.model().data(index, Qt.EditRole)) elif isinstance(editor, QComboBox): data = index.model().data(index, Qt.EditRole) idx = editor.findData(data) if idx > -1: editor.setCurrentIndex(idx) else: super(xyfieldDelegate, self).setEditorData(editor, index)
def setEditorData(self, editor: QWidget, index: QModelIndex): if isinstance(editor, ExternalProgramWidget): item = index.model().data(index) editor.line_edit_external_program.setText(item) elif isinstance(editor, RandomValueWidget): items = index.model().data(index, Qt.EditRole) editor.spinbox_random_max.setValue(items[1]) editor.spinbox_random_min.setValue(items[0]) else: super().setEditorData(editor, index)
def createEditor(self, parent: QWidget, option: 'QStyleOptionViewItem', index: QModelIndex) -> QWidget: section = index.column( ) if self.orientation == Qt.Horizontal else index.row() self.index = index if self.buttonSection is None: return super().createEditor(parent, option, index) if self.buttonSection[section] is not None: title = self.buttonSection[section][ 'text'] if 'text' in self.buttonSection[section] else "请选择..." type = self.buttonSection[section][ 'type'] if 'type' in self.buttonSection[section] else "f" if type == 'c': currentData = self.index.data(Qt.DisplayRole) self.cmb_level = QComboBox(parent) # if index.row() in index.model().levelData(): # datas = index.model().levelData()[index.row()] # for data in datas: # self.cmb_level.addItem(str(data)) url_index, level_index, url, level = self.mainWindow.return_url_and_level( self.index.row()) key = "" if url in index.model().levelData(): key = url if url + "_" + str(level) in index.model().levelData(): key = url + "_" + str(level) if url + "_*" in index.model().levelData(): key = url + "_*" if key != "": datas = index.model().levelData()[key] for data in datas: self.cmb_level.addItem(str(data)) if currentData is None: self.cmb_level.setCurrentText("") else: self.cmb_level.setCurrentText(str(currentData)) self.cmb_level.currentIndexChanged.connect( self.cmb_selectionchange) return self.cmb_level else: self.mAddressDialog = FileAddressEditor(parent, option, type) self.mAddressDialog.clickButton.connect( lambda: self.mBtn_address_clicked(parent, title, type)) self.mAddressDialog.editingFinished.connect( self.commitAndCloseEditor) return self.mAddressDialog else: return super().createEditor(parent, option, index)
def createEditor( self, parent: QWidget, option: QStyleOptionViewItem, idx: QModelIndex, ): values = idx.model().data(idx, Qt.UserRole + 10) # TODO:Need to change this to not be hard-coded. if values is None: return super().createEditor(parent, option, idx) cb = QComboBox(parent) cb.addItems(values) currentText = idx.model().data(idx, Qt.DisplayRole) editorIdx = cb.findText(currentText) cb.setCurrentIndex(editorIdx) return cb
def setEditorData(self, editor: QWidget, model_index: QModelIndex): column = model_index.column() if column == NAME_COL: # Part Name text_QString = model_index.model().data(model_index, Qt.EditRole) editor.setText(text_QString) # elif column == VISIBLE_COL: # Visibility # value = model_index.model().data(model_index, Qt.EditRole) # editor.setChecked(value) elif column == COLOR_COL: # Color value = model_index.model().data(model_index, Qt.EditRole) editor.setCurrentColor(QColor(value)) else: QStyledItemDelegate.setEditorData(self, editor, model_index)
def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex): txt = editor.text() if txt is None: index.model().setData(index, None, Qt.EditRole) return v = None if self.__ValueType == JPFieldType.Int: v = int(txt.replace(",", "")) elif self.__ValueType == JPFieldType.Float: v = float(txt.replace(",", "")) else: v = txt index.model().setData(index, v, Qt.EditRole)
def createEditor(self, parent: QtWidgets.QWidget, option: QtWidgets.QStyleOptionViewItem, index: QtCore.QModelIndex) -> QtWidgets.QWidget: wdgt = QtWidgets.QComboBox(parent) vc = index.model()._viewColumns[index.column()] self.rowSource = vc.rowSource for r in self.rowSource: wdgt.addItem(r[0], r[1]) v = index.model().data(index, QtCore.Qt.EditRole) for i, r in enumerate(self.rowSource): if r[1] == v: wdgt.setCurrentIndex(i) return wdgt return wdgt
def paint(self, painter: QtGui.QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None: cubeable = index.model().get_item(index) if not cubeable: return if isinstance(cubeable, Cardboard): cubeable = cubeable.original_printing image_promise = Context.pixmap_loader.get_pixmap(cubeable, size_slug = self._size_slug) if image_promise.is_fulfilled: painter.drawPixmap(option.rect, image_promise.get()) else: painter.drawPixmap(option.rect, Context.pixmap_loader.get_default_pixmap(size_slug = self._size_slug)) image_promise.then(self._get_image_done_callback(index, index.model()))
def leafs(self, searchedIndex: QModelIndex) -> QModelIndexList: leafs = QModelIndexList() if searchedIndex.isValid(): childCount = searchedIndex.model().columnCount(searchedIndex) for i in range(childCount): leafs += self.searchLeafs(searchedIndex.child(0, i)) return leafs
def listview_timefilter_navi_doubleclicked(index: QModelIndex): timefilter_listitem: QStandardItem = index.model().itemFromIndex(index) timefilter_item: dict = DatabaseInterface.find_one_time_filters_by_id( timefilter_listitem.time_filter_id) timefilter_dialog = TimefilterDialog(str(timefilter_item['_id'])) timefilter_dialog.exec() NavigationConfigInputInterface.refresh_listview_timefilters_navi()
def paint(self, painter: QPainter, option, index: QModelIndex): if option.state & QStyle.State_Selected: painter.fillRect(option.rect, option.palette.highlight()) r = option.rect x, y, w, h = r.x(), r.y(), r.width(), r.height() size = min(w, h) brightness = index.model().data(index, Qt.DisplayRole) radius = (size / 2.0) - (brightness / 255.0 * size / 2.0) if radius == 0.0: return painter.save() painter.setRenderHint(QPainter.Antialiasing, True) painter.setPen(Qt.NoPen) if option.state & QStyle.State_Selected: painter.setBrush(option.palette.highlightedText()) else: painter.setBrush(option.palette.text()) painter.drawEllipse(QRectF(x + w / 2 - radius, y + h / 2.0 - radius, 2 * radius, 2 * radius)) painter.restore()
def setEditorData(self, editor: QWidget, index: QModelIndex): editor.blockSignals(True) try: editor.setValue(int(index.model().data(index))) except ValueError: pass # If Label was deleted and UI not updated yet editor.blockSignals(False)
def sizeHint(self, option: 'QStyleOptionViewItem', index: QModelIndex) -> QSize: if not index.isValid(): return QSize() playlist = index.model().at(index.row()) font = QApplication.font() title_fm = QFontMetrics(font) playlist_rec = title_fm.boundingRect(0, 0, option.rect.width() - PlaylistDelegate.icon_diameter, 0, Qt.AlignLeft | Qt.AlignTop | Qt.TextWordWrap, playlist.name) title_rect = title_fm.boundingRect(option.rect.left() + PlaylistDelegate.pad_horizontal, playlist_rec.bottom() + PlaylistDelegate.pad_vertical, playlist_rec.width(), 0, Qt.AlignHCenter | Qt.AlignTop | Qt.TextWordWrap, playlist.name) playlist_size = QSize(PlaylistDelegate.icon_diameter, playlist_rec.height() + PlaylistDelegate.pad_vertical + title_rect.height()) if playlist_size.height() < PlaylistDelegate.icon_diameter: playlist_size.setHeight(PlaylistDelegate.icon_diameter) return playlist_size
def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): model = index.model() row = index.row() lbl = model.message_type[row] if lbl.value_type_index == 2: line_edit = ExpressionLineEdit(parent) line_edit.setPlaceholderText("(item1.length + 3) ^ 0x12") line_edit.setCompleter( QCompleter(self.controller.completer_model, line_edit)) line_edit.setValidator( RuleExpressionValidator(self.controller.sim_expression_parser)) line_edit.setToolTip( self.controller.sim_expression_parser.formula_help) return line_edit elif lbl.value_type_index == 3: return ExternalProgramWidget(parent) elif lbl.value_type_index == 4: random_widget = RandomValueWidget(parent) random_widget.spinbox_random_min.setMaximum(lbl.fuzz_maximum - 2) random_widget.spinbox_random_max.setMinimum(1) random_widget.spinbox_random_max.setMaximum(lbl.fuzz_maximum - 1) return random_widget else: return super().createEditor(parent, option, index)
def updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, model_index: QModelIndex): """ Args: editor: Description option: Description model_index: Description """ column = model_index.column() if column == 0: editor.setGeometry(option.rect) elif column == 1: value = model_index.model().data(model_index, Qt.EditRole) data_type = type(value) if data_type is bool: rect = QRect(option.rect) delta = option.rect.width() / 2 - 9 rect.setX(option.rect.x() + delta) # Hack to center the checkbox editor.setGeometry(rect) else: editor.setGeometry(option.rect) else: QStyledItemDelegate.updateEditorGeometry(self, editor, option, model_index)
def sizeHint(self, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> QtCore.QSize: if not index.isValid(): return QSize() context = index.model().chat_message_contexts()[index.row()] msg_text = index.data(Qt.DisplayRole) msg_font = QApplication.font() msg_fm = QFontMetrics(msg_font) msg_rect = msg_fm.boundingRect( 0, 0, option.rect.width() - MessageItemDelegate.total_pfp_width + MessageItemDelegate.profile_padding, 0, Qt.AlignLeft | Qt.AlignTop | Qt.TextWordWrap, msg_text) msg_size = QSize( option.rect.width(), msg_rect.height() + MessageItemDelegate.padding + MessageItemDelegate.profile_padding) if msg_size.height() < MessageItemDelegate.icon_radius: msg_size.setHeight(MessageItemDelegate.icon_radius) return msg_size
def setEditorData(self, editor: QWidget, index: QModelIndex) -> None: editor.blockSignals(True) try: editor.setValue(float(index.model().data(index))) except ValueError: pass editor.blockSignals(False)
def setEditorData(self, editor: QWidget, index: QModelIndex): data = index.model().data(index, Qt.EditRole) if data is None: editor.setCurrentIndex(-1) else: editor.setCurrentIndex(data[0]) return
def _mapToLocal(self, index: QModelIndex) -> QModelIndex: """Возвращает индекс из модели с локальными данными для соответствующего индекса `index` из текущей модели.""" if not index.isValid(): return QModelIndex() assert index.model() is self return self.__localDataModel.createIndex(index.row(), index.column(), index.internalId())
def get_selected_checklist(self, index: QtCore.QModelIndex) -> models.CheckList: model = index.model() identifier_item = model.item(index.row(), ChecklistModelColumn.IDENTIFIER.value) result = identifier_item.data( role=CustomDataRoles.CHECKLIST_DOWNLOADER_IDENTIFIER.value) return result
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex: """Переопределяет соответствующий родительский метод.""" assert parent.model() is self if parent.isValid( ) else True # assert self.checkIndex(parent, self.DoNotUseParent) sourceParent = self._mapToLocal(parent) sourceIndex = self.__localDataModel.index(row, column, sourceParent) return self._mapFromLocal(sourceIndex)
def setEditorData(self, editor: QtWidgets.QWidget, index: QtCore.QModelIndex): v = index.model().data(index, QtCore.Qt.EditRole) lst = [r for r in self.dataList if r[0] == v] editor.itemValue_ = None if lst: editor.setText(str(lst[0][1])) editor.itemValue_ = lst[0][0]
def paint(self, QPainter, QStyleOptionViewItem, QModelIndex): proxyModel = QModelIndex.model() index = proxyModel.mapToSource(QModelIndex) model = QModelIndex.model().sourceModel() filepath = model.filePath(index) try: _, _, files = next(os.walk(filepath)) except Exception as e: print('filepath:%s, error:%s' % (filepath, str(e))) return pr = QWindow().devicePixelRatio() lsize = QSize(ITEM_WIDTH, ITEM_HEIGHT - 20) rsize = lsize * pr qimage = None rect = QStyleOptionViewItem.rect offsetx = 0 files.reverse() for file in files: if not '.jpg' in file: continue qimage = QImage('%s/%s' % (filepath, file)).scaled( rsize, Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation) lImgHeight = int(qimage.height() / pr) lImgWidth = int(qimage.width() / pr) imgrect = QRect(rect.left() + offsetx, rect.top(), lImgWidth, lImgHeight) pixmap = QPixmap.fromImage(qimage) pixmap.setDevicePixelRatio(pr) QPainter.drawPixmap(imgrect, pixmap) offsetx += lImgWidth + 10 txtrect = QRect(rect.left(), rect.top() + (ITEM_HEIGHT - 20), ITEM_WIDTH, 20) QPainter.drawText(txtrect, Qt.AlignCenter, os.path.basename(index.data(Qt.DisplayRole))) if QStyleOptionViewItem.state & QStyle.State_Selected: highlight_color = QStyleOptionViewItem.palette.highlight().color() highlight_color.setAlpha(50) highlight_brush = QBrush(highlight_color) QPainter.fillRect(rect, highlight_brush)
def canvas_from_index(self, index: QModelIndex): if not index.isValid(): return None if index.data(EnsembleModel.data_type_role) != WorkspaceDataType.Intent: print(f'WARNING: canvas_from_index index {index} is not an intent') return None # Canvas exists for index, return # TODO: in tab view, with multiple intents selected (e.g. 2 rows checked), # non-0 row intents (every intent except first) does not have a valid object in canvas_role canvas = index.model().data(index, EnsembleModel.canvas_role) if canvas: return canvas # There is another canvas we know about we should use for match_index in self.all_intent_indexes(index.model()): if self.is_matching_canvas_type(index, match_index): canvas = match_index.model().data(match_index, EnsembleModel.canvas_role) if canvas is not None: index.model().setData(index, canvas, EnsembleModel.canvas_role) return canvas # Does not exist, create new canvas and return intent = index.model().data(index, EnsembleModel.object_role) canvas_class_name = intent.canvas registry = pluginmanager canvas = self.canvas_from_registry(canvas_class_name, registry, intent.canvas_name) index.model().setData(index, canvas, EnsembleModel.canvas_role) return canvas
def setEditorData(self, editor: QWidget, index: QModelIndex): editor.blockSignals(True) item = index.model().data(index) try: indx = self.items.index(item) if item in self.items else int(item) editor.setCurrentIndex(indx) except ValueError: pass editor.blockSignals(False)
def paint(self, painter: QPainter, option: QStyleOptionViewItem, model_index: QModelIndex): """ Args: painter: Description option: Description model_index: Description """ # row = model_index.row() column = model_index.column() if column == 0: # Part Name option.displayAlignment = Qt.AlignVCenter QStyledItemDelegate.paint(self, painter, option, model_index) if column == 1: # Visibility value = model_index.model().data(model_index, Qt.EditRole) data_type = type(value) if data_type is str: # print("val", value) if COLOR_PATTERN.search(value): # print("found color") element = _QCOMMONSTYLE.PE_IndicatorCheckBox styleoption = QStyleOptionViewItem() styleoption.palette.setBrush(QPalette.Button, getBrushObj(value)) styleoption.rect = QRect(option.rect) _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) option.displayAlignment = Qt.AlignVCenter QStyledItemDelegate.paint(self, painter, option, model_index) elif data_type is int: option.displayAlignment = Qt.AlignVCenter QStyledItemDelegate.paint(self, painter, option, model_index) elif data_type is float: option.displayAlignment = Qt.AlignVCenter QStyledItemDelegate.paint(self, painter, option, model_index) elif data_type is bool: element = _QCOMMONSTYLE.PE_IndicatorCheckBox styleoption = QStyleOptionButton() styleoption.rect = QRect(option.rect) checked = value styleoption.state |= QStyle.State_On if checked else QStyle.State_Off styleoption.palette.setBrush(QPalette.Button, Qt.white) styleoption.palette.setBrush(QPalette.HighlightedText, Qt.black) _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) if checked: element = _QCOMMONSTYLE.PE_IndicatorMenuCheckMark _QCOMMONSTYLE.drawPrimitive(element, styleoption, painter) else: QStyledItemDelegate.paint(self, painter, option, model_index)
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): if self.colors: try: item = index.model().data(index) index = self.items.index(item) if item in self.items else int(item) color = self.colors[index] x, y, h = option.rect.x(), option.rect.y(), option.rect.height() rect = QRectF(x + 8, y + h / 2 - 8, 16, 16) painter.fillRect(rect, QColor("black")) rect = rect.adjusted(1, 1, -1, -1) painter.fillRect(rect, QColor(color.red(), color.green(), color.blue(), 255)) except: super().paint(painter, option, index) else: super().paint(painter, option, index)
def configureEditor(self, parent_qw: QWidget, option: QStyleOptionViewItem, model_index: QModelIndex) -> QWidget: """ Args: parent_qw: Description option Description model_index: Description Returns: the widget used to edit the item specified by index for editing Raises: NotImplementedError: Description """ cn_m = self.outlineViewObj() key = self.key() if key == 'name': return QLineEdit(parent_qw) elif key not in cn_m.editable_properties: return None if self.is_enum: editor = QComboBox(parent_qw) for val in ENUM_NAMES[key]: editor.addItem(val) else: data_type = type(model_index.model().data(model_index, Qt.DisplayRole)) if data_type is str: editor = QLineEdit(parent_qw) elif data_type is int: editor = QSpinBox(parent_qw) editor.setRange(-359, 359) elif data_type is float: editor = QDoubleSpinBox(parent_qw) editor.setDecimals(0) editor.setRange(-359, 359) elif data_type is bool: editor = QCheckBox(parent_qw) elif isinstance(None, data_type): return None else: raise NotImplementedError return editor
class textEditView(QTextEdit): def __init__(self, parent=None, index=None, html=None, spellcheck=None, highlighting=False, dict="", autoResize=False): QTextEdit.__init__(self, parent) self._column = Outline.text self._index = None self._indexes = None self._model = None self._placeholderText = self.placeholderText() self._updating = False self._item = None self._highlighting = highlighting self._textFormat = "text" self.setAcceptRichText(False) # When setting up a theme, this becomes true. self._fromTheme = False self._themeData = None self._highlighterClass = BasicHighlighter if spellcheck is None: spellcheck = settings.spellcheck self.spellcheck = spellcheck self.currentDict = dict if dict else settings.dict self._defaultFontSize = qApp.font().pointSize() self.highlighter = None self.setAutoResize(autoResize) self._defaultBlockFormat = QTextBlockFormat() self._defaultCharFormat = QTextCharFormat() self.highlightWord = "" self.highligtCS = False self._dict = None # self.document().contentsChanged.connect(self.submit, F.AUC) # Submit text changed only after 500ms without modifications self.updateTimer = QTimer() self.updateTimer.setInterval(500) self.updateTimer.setSingleShot(True) self.updateTimer.timeout.connect(self.submit) # self.updateTimer.timeout.connect(lambda: print("Timeout")) self.updateTimer.stop() self.document().contentsChanged.connect(self.updateTimer.start, F.AUC) # self.document().contentsChanged.connect(lambda: print("Document changed")) # self.document().contentsChanged.connect(lambda: print(self.objectName(), "Contents changed")) self.setEnabled(False) if index: self.setCurrentModelIndex(index) elif html: self.document().setHtml(html) self.setReadOnly(True) # Spellchecking if enchant and self.spellcheck: try: self._dict = enchant.Dict(self.currentDict if self.currentDict else self.getDefaultLocale()) except enchant.errors.DictNotFoundError: self.spellcheck = False else: self.spellcheck = False if self._highlighting and not self.highlighter: self.highlighter = self._highlighterClass(self) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) def getDefaultLocale(self): default_locale = enchant.get_default_language() if default_locale is None: default_locale = QLocale.system().name() if default_locale is None: default_locale = enchant.list_dicts()[0][0] return default_locale def setModel(self, model): self._model = model try: self._model.dataChanged.connect(self.update, F.AUC) except TypeError: pass def setColumn(self, col): self._column = col def setHighlighting(self, val): self._highlighting = val def setDefaultBlockFormat(self, bf): self._defaultBlockFormat = bf if self.highlighter: self.highlighter.setDefaultBlockFormat(bf) def setCurrentModelIndex(self, index): self._indexes = None if index.isValid(): self.setEnabled(True) if index.column() != self._column: index = index.sibling(index.row(), self._column) self._index = QPersistentModelIndex(index) self.setPlaceholderText(self._placeholderText) if not self._model: self.setModel(index.model()) self.setupEditorForIndex(self._index) self.loadFontSettings() self.updateText() else: self._index = QModelIndex() self.setPlainText("") self.setEnabled(False) def currentIndex(self): """ Getter function used to normalized views access with QAbstractItemViews. """ if self._index: return self._index else: return QModelIndex() def getSelection(self): """ Getter function used to normalized views access with QAbstractItemViews. """ return [self.currentIndex()] def setCurrentModelIndexes(self, indexes): self._index = None self._indexes = [] for i in indexes: if i.isValid(): self.setEnabled(True) if i.column() != self._column: i = i.sibling(i.row(), self._column) self._indexes.append(QModelIndex(i)) if not self._model: self.setModel(i.model()) self.updateText() def setupEditorForIndex(self, index): # Setting highlighter if self._highlighting: self.highlighter = self._highlighterClass(self) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) self.highlighter.updateColorScheme() def loadFontSettings(self): if self._fromTheme or \ not self._index or \ type(self._index.model()) != outlineModel or \ self._column != Outline.text: return opt = settings.textEditor f = QFont() f.fromString(opt["font"]) background = (opt["background"] if not opt["backgroundTransparent"] else "transparent") foreground = opt["fontColor"] # if not opt["backgroundTransparent"] # else S.text # self.setFont(f) self.setStyleSheet("""QTextEdit{{ background: {bg}; color: {foreground}; font-family: {ff}; font-size: {fs}; margin: {mTB}px {mLR}px; {maxWidth} }} """.format( bg=background, foreground=foreground, ff=f.family(), fs="{}pt".format(str(f.pointSize())), mTB = opt["marginsTB"], mLR = opt["marginsLR"], maxWidth = "max-width: {}px;".format(opt["maxWidth"]) if opt["maxWidth"] else "", ) ) self._defaultFontSize = f.pointSize() # We set the parent background to the editor's background in case # there are margins. We check that the parent class is a QWidget because # if textEditView is used in fullScreenEditor, then we don't want to # set the background. if self.parent().__class__ == QWidget: self.parent().setStyleSheet(""" QWidget#{name}{{ background: {bg}; }}""".format( # We style by name, otherwise all inheriting widgets get the same # colored background, for example context menu. name=self.parent().objectName(), bg=background, )) cf = QTextCharFormat() # cf.setFont(f) # cf.setForeground(QColor(opt["fontColor"])) self.setCursorWidth(opt["cursorWidth"]) bf = QTextBlockFormat() bf.setLineHeight(opt["lineSpacing"], bf.ProportionalHeight) bf.setTextIndent(opt["tabWidth"] * 1 if opt["indent"] else 0) bf.setTopMargin(opt["spacingAbove"]) bf.setBottomMargin(opt["spacingBelow"]) bf.setAlignment(Qt.AlignLeft if opt["textAlignment"] == 0 else Qt.AlignCenter if opt["textAlignment"] == 1 else Qt.AlignRight if opt["textAlignment"] == 2 else Qt.AlignJustify) self._defaultCharFormat = cf self._defaultBlockFormat = bf if self.highlighter: self.highlighter.updateColorScheme() self.highlighter.setMisspelledColor(QColor(opt["misspelled"])) self.highlighter.setDefaultCharFormat(self._defaultCharFormat) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) def update(self, topLeft, bottomRight): if self._updating: return if self._index and self._index.isValid(): if topLeft.parent() != self._index.parent(): return # print("Model changed: ({}:{}), ({}:{}/{}), ({}:{}) for {} of {}".format( # topLeft.row(), topLeft.column(), # self._index.row(), self._index.row(), self._column, # bottomRight.row(), bottomRight.column(), # self.objectName(), self.parent().objectName())) if topLeft.row() <= self._index.row() <= bottomRight.row(): if topLeft.column() <= self._column <= bottomRight.column(): self.updateText() elif self._indexes: update = False for i in self._indexes: if topLeft.row() <= i.row() <= bottomRight.row(): update = True if update: self.updateText() def disconnectDocument(self): try: self.document().contentsChanged.disconnect(self.updateTimer.start) except: pass def reconnectDocument(self): self.document().contentsChanged.connect(self.updateTimer.start, F.AUC) def updateText(self): if self._updating: return # print("Updating", self.objectName()) self._updating = True if self._index: self.disconnectDocument() if self.toPlainText() != F.toString(self._index.data()): # print(" Updating plaintext") self.document().setPlainText(F.toString(self._index.data())) self.reconnectDocument() elif self._indexes: self.disconnectDocument() t = [] same = True for i in self._indexes: item = i.internalPointer() t.append(F.toString(item.data(self._column))) for t2 in t[1:]: if t2 != t[0]: same = False break if same: self.document().setPlainText(t[0]) else: self.document().setPlainText("") if not self._placeholderText: self._placeholderText = self.placeholderText() self.setPlaceholderText(self.tr("Various")) self.reconnectDocument() self._updating = False def submit(self): self.updateTimer.stop() if self._updating: return # print("Submitting", self.objectName()) if self._index and self._index.isValid(): # item = self._index.internalPointer() if self.toPlainText() != self._index.data(): # print(" Submitting plain text") self._updating = True self._model.setData(QModelIndex(self._index), self.toPlainText()) self._updating = False elif self._indexes: self._updating = True for i in self._indexes: item = i.internalPointer() if self.toPlainText() != F.toString(item.data(self._column)): print("Submitting many indexes") self._model.setData(i, self.toPlainText()) self._updating = False def keyPressEvent(self, event): if event.key() == Qt.Key_V and event.modifiers() & Qt.ControlModifier: text = QApplication.clipboard().text() self.insertPlainText(text) else: QTextEdit.keyPressEvent(self, event) if event.key() == Qt.Key_Space: self.submit() # ----------------------------------------------------------------------------------------------------- # Resize stuff def resizeEvent(self, e): QTextEdit.resizeEvent(self, e) if self._autoResize: self.sizeChange() def sizeChange(self): opt = settings.textEditor docHeight = self.document().size().height() + 2 * opt["marginsTB"] if self.heightMin <= docHeight <= self.heightMax: self.setMinimumHeight(docHeight) def setAutoResize(self, val): self._autoResize = val if self._autoResize: self.document().contentsChanged.connect(self.sizeChange) self.heightMin = 0 self.heightMax = 65000 self.sizeChange() ############################################################################### # SPELLCHECKING ############################################################################### # Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ def setDict(self, d): self.currentDict = d if d and enchant.dict_exists(d): self._dict = enchant.Dict(d) if self.highlighter: self.highlighter.rehighlight() def toggleSpellcheck(self, v): self.spellcheck = v if enchant and self.spellcheck and not self._dict: if self.currentDict and enchant.dict_exists(self.currentDict): self._dict = enchant.Dict(self.currentDict) elif enchant.get_default_language() and enchant.dict_exists(enchant.get_default_language()): self._dict = enchant.Dict(enchant.get_default_language()) else: self.spellcheck = False if self.highlighter: self.highlighter.rehighlight() else: self.spellcheck = False def mousePressEvent(self, event): if event.button() == Qt.RightButton: # Rewrite the mouse event to a left button event so the cursor is # moved to the location of the pointer. event = QMouseEvent(QEvent.MouseButtonPress, event.pos(), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) QTextEdit.mousePressEvent(self, event) def wheelEvent(self, event): """ We catch wheelEvent if key modifier is CTRL to change font size. Note: this should be in a class specific for main textEditView (#TODO). """ if event.modifiers() & Qt.ControlModifier: # Get the wheel angle. d = event.angleDelta().y() / 120 # Update settings f = QFont() f.fromString(settings.textEditor["font"]) f.setPointSizeF(f.pointSizeF() + d) settings.textEditor["font"] = f.toString() # Update font to all textEditView. Drastically. for w in F.mainWindow().findChildren(textEditView, QRegExp(".*")): w.loadFontSettings() # We tell the world that we accepted this event event.accept() return QTextEdit.wheelEvent(self, event) class SpellAction(QAction): """A special QAction that returns the text in a signal. Used for spellcheck.""" correct = pyqtSignal(str) def __init__(self, *args): QAction.__init__(self, *args) self.triggered.connect(lambda x: self.correct.emit( str(self.text()))) def contextMenuEvent(self, event): # Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ popup_menu = self.createStandardContextMenu() popup_menu.exec_(event.globalPos()) def createStandardContextMenu(self): popup_menu = QTextEdit.createStandardContextMenu(self) if not self.spellcheck: return popup_menu # Select the word under the cursor. # But only if there is no selection (otherwise it's impossible to select more text to copy/cut) cursor = self.textCursor() if not cursor.hasSelection(): cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if self._dict and cursor.hasSelection(): text = str(cursor.selectedText()) valid = self._dict.check(text) selectedWord = cursor.selectedText() if not valid: spell_menu = QMenu(self.tr('Spelling Suggestions'), self) spell_menu.setIcon(F.themeIcon("spelling")) for word in self._dict.suggest(text): action = self.SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: add to dictionary addAction = QAction(self.tr("&Add to dictionary"), popup_menu) addAction.setIcon(QIcon.fromTheme("list-add")) addAction.triggered.connect(self.addWordToDict) addAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], addAction) # Adds: suggestions popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) # popup_menu.insertSeparator(popup_menu.actions()[0]) # If word was added to custom dict, give the possibility to remove it elif valid and self._dict.is_added(selectedWord): popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: remove from dictionary rmAction = QAction(self.tr("&Remove from custom dictionary"), popup_menu) rmAction.setIcon(QIcon.fromTheme("list-remove")) rmAction.triggered.connect(self.rmWordFromDict) rmAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], rmAction) return popup_menu def correctWord(self, word): """ Replaces the selected text with word. """ cursor = self.textCursor() cursor.beginEditBlock() cursor.removeSelectedText() cursor.insertText(word) cursor.endEditBlock() def addWordToDict(self): word = self.sender().data() self._dict.add(word) self.highlighter.rehighlight() def rmWordFromDict(self): word = self.sender().data() self._dict.remove(word) self.highlighter.rehighlight() ############################################################################### # FORMATTING ############################################################################### def focusOutEvent(self, event): """Submit changes just before focusing out.""" QTextEdit.focusOutEvent(self, event) self.submit() ############################################################################### # KEYBOARD SHORTCUTS ############################################################################### def callMainTreeView(self, functionName): """ The tree view in main window must have same index as the text edit that has focus. So we can pass it the call for documents edits like: duplicate, move up, etc. """ if self._index and self._column == Outline.text: function = getattr(F.mainWindow().treeRedacOutline, functionName) function() def rename(self): self.callMainTreeView("rename") def duplicate(self): self.callMainTreeView("duplicate") def moveUp(self): self.callMainTreeView("moveUp") def moveDown(self): self.callMainTreeView("moveDown")
class textEditView(QTextEdit): def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="", autoResize=False): QTextEdit.__init__(self, parent) self._column = Outline.text.value self._index = None self._indexes = None self._model = None self._placeholderText = self.placeholderText() self._updating = False self._item = None self._highlighting = highlighting self._textFormat = "text" self.setAcceptRichText(False) # When setting up a theme, this becomes true. self._fromTheme = False self.spellcheck = spellcheck self.currentDict = dict if dict else settings.dict self.highlighter = None self.setAutoResize(autoResize) self._defaultBlockFormat = QTextBlockFormat() self._defaultCharFormat = QTextCharFormat() self.highlightWord = "" self.highligtCS = False self.defaultFontPointSize = qApp.font().pointSize() self._dict = None # self.document().contentsChanged.connect(self.submit, AUC) # Submit text changed only after 500ms without modifications self.updateTimer = QTimer() self.updateTimer.setInterval(500) self.updateTimer.setSingleShot(True) self.updateTimer.timeout.connect(self.submit) # self.updateTimer.timeout.connect(lambda: print("Timeout")) self.updateTimer.stop() self.document().contentsChanged.connect(self.updateTimer.start, AUC) # self.document().contentsChanged.connect(lambda: print("Document changed")) # self.document().contentsChanged.connect(lambda: print(self.objectName(), "Contents changed")) self.setEnabled(False) if index: self.setCurrentModelIndex(index) elif html: self.document().setHtml(html) self.setReadOnly(True) # Spellchecking if enchant and self.spellcheck: try: self._dict = enchant.Dict(self.currentDict if self.currentDict else enchant.get_default_language()) except enchant.errors.DictNotFoundError: self.spellcheck = False else: self.spellcheck = False if self._highlighting and not self.highlighter: self.highlighter = basicHighlighter(self) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) def setModel(self, model): self._model = model try: self._model.dataChanged.connect(self.update, AUC) except TypeError: pass try: self._model.rowsAboutToBeRemoved.connect(self.rowsAboutToBeRemoved, AUC) except TypeError: pass def setColumn(self, col): self._column = col def setHighlighting(self, val): self._highlighting = val def setDefaultBlockFormat(self, bf): self._defaultBlockFormat = bf if self.highlighter: self.highlighter.setDefaultBlockFormat(bf) def setCurrentModelIndex(self, index): self._indexes = None if index.isValid(): self.setEnabled(True) if index.column() != self._column: index = index.sibling(index.row(), self._column) self._index = index self.setPlaceholderText(self._placeholderText) if not self._model: self.setModel(index.model()) self.setupEditorForIndex(self._index) self.loadFontSettings() self.updateText() else: self._index = QModelIndex() self.setPlainText("") self.setEnabled(False) def setCurrentModelIndexes(self, indexes): self._index = None self._indexes = [] for i in indexes: if i.isValid(): self.setEnabled(True) if i.column() != self._column: i = i.sibling(i.row(), self._column) self._indexes.append(i) if not self._model: self.setModel(i.model()) self.updateText() def setupEditorForIndex(self, index): # In which model are we editing? if type(index.model()) != outlineModel: self._textFormat = "text" return # what type of text are we editing? if self._column not in [Outline.text.value, Outline.notes.value]: self._textFormat = "text" else: self._textFormat = "md" # Setting highlighter if self._highlighting: item = index.internalPointer() if self._column in [Outline.text.value, Outline.notes.value]: self.highlighter = MMDHighlighter(self) else: self.highlighter = basicHighlighter(self) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) def loadFontSettings(self): if self._fromTheme or \ not self._index or \ type(self._index.model()) != outlineModel or \ self._column != Outline.text.value: return opt = settings.textEditor f = QFont() f.fromString(opt["font"]) # self.setFont(f) self.setStyleSheet("""QTextEdit{{ background: {bg}; color: {foreground}; font-family: {ff}; font-size: {fs}; }} """.format( bg=opt["background"], foreground=opt["fontColor"], ff=f.family(), fs="{}pt".format(str(f.pointSize())))) cf = QTextCharFormat() # cf.setFont(f) # cf.setForeground(QColor(opt["fontColor"])) bf = QTextBlockFormat() bf.setLineHeight(opt["lineSpacing"], bf.ProportionalHeight) bf.setTextIndent(opt["tabWidth"] * 1 if opt["indent"] else 0) bf.setTopMargin(opt["spacingAbove"]) bf.setBottomMargin(opt["spacingBelow"]) self._defaultCharFormat = cf self._defaultBlockFormat = bf if self.highlighter: self.highlighter.setMisspelledColor(QColor(opt["misspelled"])) self.highlighter.setDefaultCharFormat(self._defaultCharFormat) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) def update(self, topLeft, bottomRight): if self._updating: return elif self._index: if topLeft.parent() != self._index.parent(): return # print("Model changed: ({}:{}), ({}:{}/{}), ({}:{}) for {} of {}".format( # topLeft.row(), topLeft.column(), # self._index.row(), self._index.row(), self._column, # bottomRight.row(), bottomRight.column(), # self.objectName(), self.parent().objectName())) if topLeft.row() <= self._index.row() <= bottomRight.row(): if topLeft.column() <= self._column <= bottomRight.column(): self.updateText() elif self._indexes: update = False for i in self._indexes: if topLeft.row() <= i.row() <= bottomRight.row(): update = True if update: self.updateText() def rowsAboutToBeRemoved(self, parent, first, last): if self._index: if self._index.parent() == parent and \ first <= self._index.row() <= last: self._index = None self.setEnabled(False) # FIXME: self._indexes def disconnectDocument(self): try: self.document().contentsChanged.disconnect(self.updateTimer.start) except: pass def reconnectDocument(self): self.document().contentsChanged.connect(self.updateTimer.start, AUC) def updateText(self): if self._updating: return # print("Updating", self.objectName()) self._updating = True if self._index: self.disconnectDocument() if self.toPlainText() != toString(self._model.data(self._index)): # print(" Updating plaintext") self.document().setPlainText(toString(self._model.data(self._index))) self.reconnectDocument() elif self._indexes: self.disconnectDocument() t = [] same = True for i in self._indexes: item = i.internalPointer() t.append(toString(item.data(self._column))) for t2 in t[1:]: if t2 != t[0]: same = False break if same: self.document().setPlainText(t[0]) else: self.document().setPlainText("") if not self._placeholderText: self._placeholderText = self.placeholderText() self.setPlaceholderText(self.tr("Various")) self.reconnectDocument() self._updating = False def submit(self): self.updateTimer.stop() if self._updating: return # print("Submitting", self.objectName()) if self._index: # item = self._index.internalPointer() if self.toPlainText() != self._model.data(self._index): # print(" Submitting plain text") self._updating = True self._model.setData(self._index, self.toPlainText()) self._updating = False elif self._indexes: self._updating = True for i in self._indexes: item = i.internalPointer() if self.toPlainText() != toString(item.data(self._column)): print("Submitting many indexes") self._model.setData(i, self.toPlainText()) self._updating = False def keyPressEvent(self, event): QTextEdit.keyPressEvent(self, event) if event.key() == Qt.Key_Space: self.submit() # ----------------------------------------------------------------------------------------------------- # Resize stuff def resizeEvent(self, e): QTextEdit.resizeEvent(self, e) if self._autoResize: self.sizeChange() def sizeChange(self): docHeight = self.document().size().height() if self.heightMin <= docHeight <= self.heightMax: self.setMinimumHeight(docHeight) def setAutoResize(self, val): self._autoResize = val if self._autoResize: self.document().contentsChanged.connect(self.sizeChange) self.heightMin = 0 self.heightMax = 65000 self.sizeChange() ############################################################################### # SPELLCHECKING ############################################################################### # Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ def setDict(self, d): self.currentDict = d self._dict = enchant.Dict(d) if self.highlighter: self.highlighter.rehighlight() def toggleSpellcheck(self, v): self.spellcheck = v if enchant and self.spellcheck and not self._dict: if self.currentDict: self._dict = enchant.Dict(self.currentDict) elif enchant.dict_exists(enchant.get_default_language()): self._dict = enchant.Dict(enchant.get_default_language()) else: self.spellcheck = False if self.highlighter: self.highlighter.rehighlight() else: self.spellcheck = False def mousePressEvent(self, event): if event.button() == Qt.RightButton: # Rewrite the mouse event to a left button event so the cursor is # moved to the location of the pointer. event = QMouseEvent(QEvent.MouseButtonPress, event.pos(), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) QTextEdit.mousePressEvent(self, event) class SpellAction(QAction): """A special QAction that returns the text in a signal. Used for spellckech.""" correct = pyqtSignal(str) def __init__(self, *args): QAction.__init__(self, *args) self.triggered.connect(lambda x: self.correct.emit( str(self.text()))) def contextMenuEvent(self, event): # Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ popup_menu = self.createStandardContextMenu() popup_menu.exec_(event.globalPos()) def createStandardContextMenu(self): popup_menu = QTextEdit.createStandardContextMenu(self) if not self.spellcheck: return popup_menu # Select the word under the cursor. # But only if there is no selection (otherwise it's impossible to select more text to copy/cut) cursor = self.textCursor() if not cursor.hasSelection(): cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if cursor.hasSelection(): text = str(cursor.selectedText()) valid = self._dict.check(text) selectedWord = cursor.selectedText() if not valid: spell_menu = QMenu(self.tr('Spelling Suggestions'), self) for word in self._dict.suggest(text): action = self.SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: add to dictionary addAction = QAction(self.tr("&Add to dictionary"), popup_menu) addAction.triggered.connect(self.addWordToDict) addAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], addAction) # Adds: suggestions popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) # popup_menu.insertSeparator(popup_menu.actions()[0]) # If word was added to custom dict, give the possibility to remove it elif valid and self._dict.is_added(selectedWord): popup_menu.insertSeparator(popup_menu.actions()[0]) # Adds: remove from dictionary rmAction = QAction(self.tr("&Remove from custom dictionary"), popup_menu) rmAction.triggered.connect(self.rmWordFromDict) rmAction.setData(selectedWord) popup_menu.insertAction(popup_menu.actions()[0], rmAction) return popup_menu def correctWord(self, word): """ Replaces the selected text with word. """ cursor = self.textCursor() cursor.beginEditBlock() cursor.removeSelectedText() cursor.insertText(word) cursor.endEditBlock() def addWordToDict(self): word = self.sender().data() self._dict.add(word) self.highlighter.rehighlight() def rmWordFromDict(self): word = self.sender().data() self._dict.remove(word) self.highlighter.rehighlight() ############################################################################### # FORMATTING ############################################################################### def focusOutEvent(self, event): """Submit changes just before focusing out.""" QTextEdit.focusOutEvent(self, event) self.submit() def focusInEvent(self, event): """Finds textFormatter and attach them to that view.""" QTextEdit.focusInEvent(self, event) p = self.parent() while p.parent(): p = p.parent() if self._index: for tF in p.findChildren(textFormat, QRegExp(".*"), Qt.FindChildrenRecursively): tF.updateFromIndex(self._index) tF.setTextEdit(self) def applyFormat(self, _format): if self._textFormat == "md": if _format == "Bold": MDFormatSelection(self, 0) elif _format == "Italic": MDFormatSelection(self, 1) elif _format == "Code": MDFormatSelection(self, 2) elif _format == "Clear": MDFormatSelection(self)
def setEditorData(self, editor: SectionComboBox, index: QModelIndex): editor.blockSignals(True) item = index.model().data(index) editor.setCurrentText(item) editor.blockSignals(False)
def setEditorData(self, editor: QCheckBox, index: QModelIndex): editor.blockSignals(True) editor.setChecked(index.model().data(index)) self.enabled = editor.isChecked() editor.blockSignals(False)