def __init__(self, settings, directory, check_id_fct, annotations_path, parent=None): super().__init__(parent) # FIXME Delayed refactoring of check_id_fct and annotations_path. # Variables section. library_id = settings["libraryID"] library_type = settings["libraryType"] api_key = settings["apiKey"] self._zotero = ZoteroWrap(library_id, library_type, api_key, directory) # Widgets section. model = ZoteroTableModel(self._zotero, check_id_fct, annotations_path) model.load() proxy_model = QSortFilterProxyModel() proxy_model.setSourceModel(model) proxy_model.setDynamicSortFilter(True) proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) proxy_model.setFilterKeyColumn(-1) # NB: All columns. self.view = QTableView(self) self.view.setModel(proxy_model) self.view.setCornerButtonEnabled(False) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.view.setSelectionMode(QAbstractItemView.SingleSelection) # NB: Triggers a call to sortByColumn() which sorts by the first column. self.view.setSortingEnabled(True) self.view.setWordWrap(False) self.view.verticalHeader().hide() self.filter_edit = FilterEdit(self.view) # NB: The thread does not begin executing until start() is called. self.refresh_thread = ZoteroRefreshThread(model, self) # Layouts section. header_layout = QFormLayout() header_layout.addRow("Filter:", self.filter_edit) header_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) utils.configure_form_layout(header_layout) main_layout = QVBoxLayout() main_layout.addLayout(header_layout) main_layout.addWidget(self.view) self.setLayout(main_layout) # Signals section. self.filter_edit.textChanged.connect(proxy_model.setFilterFixedString) self.refresh_thread.started.connect(self.refresh_started) self.refresh_thread.finished.connect(self.refresh_finished)
class SortFilterTableView(QTableView): def __init__(self, parent=None): super().__init__(parent) self._proxy_model = QSortFilterProxyModel(self) self._proxy_model.setDynamicSortFilter(True) super().setModel(self._proxy_model) header = FilterHeader(self) header.filter_changed.connect(self.set_filter) self.setHorizontalHeader(header) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.ContiguousSelection) self.import_export_manager = ImportExportManager(self) self.import_export_manager.connect_custom_context_menu() def set_filter(self, section, filter_text): log.debug("set_filter(section: %s, filter: %r)", section, filter_text) self._proxy_model.setFilterWildcard(filter_text) self._proxy_model.setFilterKeyColumn(section) def setModel(self, model): self.horizontalHeader().set_filter_boxes(model.columnCount()) self._proxy_model.setSourceModel(model) self._proxy_model.sort(0, Qt.AscendingOrder) super().setModel(self._proxy_model) font = model.data(0, Qt.FontRole) if font is None: font = self.font() metrics = QFontMetrics(font) self.verticalHeader().setDefaultSectionSize(metrics.lineSpacing() * 1.5) self.horizontalHeader().setDefaultSectionSize(metrics.maxWidth() * 5)
def setEditorData(self, editor, idx): modeldata = idx.data(Qt.UserRole) # idx.data(Qt.DisplayRole) ##print(modeldata) #print("in setEditorData, db=", editor.window().db) #####dict_ = eval(modeldata) #if editor.window().db: # dict_ = dict_from_DB(editor.window().db, dict_["UUID"]) #else: dict_ = eval(modeldata) # this expanding DbDocFileMetadata for childs, not desirable, but hard to find an alternative to eval #dict_ = ast.literal_eval(modeldata) #jsonString = json.dumps(modeldata) #dict_ = json.loads(jsonString) ###modeldata2 = modeldata.replace("'", '"') ###dict_ = json.loads(modeldata2) model = editor.model() model.clear() model = QStandardItemModel(0, 2) editor.setHeaderHidden(False) model.setHorizontalHeaderLabels(['Attribute', 'Value']) # using QSortFilterProxyModel to facilitate sorting the metdata list # QSortFilterProxyModel (or related) seems to be what is causing this following warning: # 'Trying to create a QVariant instance of QMetaType::Void type, an invalid QVariant will be constructed instead' proxymodel = QSortFilterProxyModel() proxymodel.setSourceModel(model) proxymodel.setDynamicSortFilter(True) proxymodel.setSortCaseSensitivity( Qt.CaseInsensitive ) # none of these 3 lines appear to have any effect on sorting the metadata list #proxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive) #proxymodel.sort(0, Qt.AscendingOrder) # Qt.DescendingOrder #proxymodel.setSortRole(Qt.DisplayRole) editor.setModel(proxymodel) for ii, (key, value) in enumerate(sorted(dict_.items())): model.setItem(ii, 0, QStandardItem(key)) model.setItem(ii, 1, QStandardItem(str(value)) )
def init_ui(self): self.resize(600, 500) hbox = QHBoxLayout() tableview = QTableView() hbox.addWidget(tableview) self.setLayout(hbox) model = QStandardItemModel() model.setHorizontalHeaderLabels(['年龄', '身高', '体重']) items = [[19, 180, 60], [20, 179, 61], [21, 178, 62], [22, 177, 63]] for ele1 in items: for idx, ele2 in enumerate(ele1): ele1[idx] = QStandardItem(str(ele2)) for item in items: model.appendRow(item) sort_model = QSortFilterProxyModel() sort_model.setDynamicSortFilter(True) sort_model.setSourceModel(model) tableview.setModel(sort_model) tableview.setSortingEnabled(True)
def __init__(self, settings, directory, check_id_fct, annotations_path, parent=None): super().__init__(parent) # FIXME Delayed refactoring of check_id_fct and annotations_path. # Variables section. library_id = settings["libraryID"] library_type = settings["libraryType"] api_key = settings["apiKey"] self._zotero = ZoteroWrap(library_id, library_type, api_key, directory) # Widgets section. model = ZoteroTableModel(self._zotero, check_id_fct, annotations_path) model.load() proxy_model = QSortFilterProxyModel() proxy_model.setSourceModel(model) proxy_model.setDynamicSortFilter(True) proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) proxy_model.setFilterKeyColumn(-1) # NB: All columns. self.view = QTableView(self) self.view.setModel(proxy_model) self.view.setCornerButtonEnabled(False) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.view.setSelectionMode(QAbstractItemView.SingleSelection) # NB: Triggers a call to sortByColumn() which sorts by the first column. self.view.setSortingEnabled(True) self.view.setWordWrap(False) self.view.verticalHeader().hide() self.filter_edit = FilterEdit(self.view) # NB: The thread does not begin executing until start() is called. self.refresh_thread = ZoteroRefreshThread(model, self) # Layouts section. header_layout = QFormLayout() header_layout.addRow("Filter:", self.filter_edit) header_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) utils.configure_form_layout(header_layout) main_layout = QVBoxLayout() main_layout.addLayout(header_layout) main_layout.addWidget(self.view) self.setLayout(main_layout) # Signals section. self.filter_edit.textChanged.connect(proxy_model.setFilterFixedString) self.refresh_thread.started.connect(self.refresh_started) self.refresh_thread.finished.connect(self.refresh_finished)
def createModel(parent,rows,cols,colNames): model=QStandardItemModel(rows, cols+1, parent) i=0 for c in colNames: model.setHeaderData(i, Qt.Horizontal, c) i+=1 proxyModel=QSortFilterProxyModel() proxyModel.setDynamicSortFilter(True) proxyModel.setSourceModel(model) proxyModel.setFilterKeyColumn(0) return proxyModel
def createModel(parent, rows, cols, colNames): model = QStandardItemModel(rows, cols + 1, parent) i = 0 for c in colNames: model.setHeaderData(i, Qt.Horizontal, colNames[i]) i += 1 proxyModel = QSortFilterProxyModel() proxyModel.setDynamicSortFilter(True) proxyModel.setSourceModel(model) proxyModel.setFilterKeyColumn(0) return proxyModel
class RegionView(QTableView): def __init__(self, parent=None): super().__init__() self.sorter = None def set_model(self, regions): self.sorter = QSortFilterProxyModel() self.sorter.setDynamicSortFilter(True) self.sorter.setSourceModel(RegionList(regions)) self.setModel(self.sorter) self.resizeColumnsToContents() self.setSortingEnabled(True)
class HCRContractView(QTableView): def __init__(self, parent=None): super().__init__() self.sorter = None def set_model(self, contracts): self.sorter = QSortFilterProxyModel() self.sorter.setDynamicSortFilter(True) self.sorter.setSourceModel(HCRContractModel(contracts)) self.setModel(self.sorter) self.resizeColumnsToContents() self.setSortingEnabled(True)
class SpellingDictionaryEditDialog(QDialog, Ui_SpellingDictionaryEditDialog): """ Class implementing a dialog to edit the various spell checking dictionaries. """ def __init__(self, data, info, parent=None): """ Constructor @param data contents to be edited (string) @param info info string to show at the header (string) @param parent reference to the parent widget (QWidget) """ super(SpellingDictionaryEditDialog, self).__init__(parent) self.setupUi(self) self.infoLabel.setText(info) self.__model = QStringListModel( [line.strip() for line in data.splitlines() if line.strip()], self) self.__model.sort(0) self.__proxyModel = QSortFilterProxyModel(self) self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.__proxyModel.setDynamicSortFilter(True) self.__proxyModel.setSourceModel(self.__model) self.wordList.setModel(self.__proxyModel) self.searchEdit.textChanged.connect( self.__proxyModel.setFilterFixedString) self.removeButton.clicked.connect(self.wordList.removeSelected) self.removeAllButton.clicked.connect(self.wordList.removeAll) @pyqtSlot() def on_addButton_clicked(self): """ Private slot to handle adding an entry. """ self.__model.insertRow(self.__model.rowCount()) self.wordList.edit( self.__proxyModel.index(self.__model.rowCount() - 1, 0)) def getData(self): """ Public method to get the data. @return data of the dialog (string) """ return os.linesep.join([ line.strip() for line in self.__model.stringList() if line.strip() ]) + os.linesep
class OptimizerView(QTableView): def __init__(self, parent=None): super().__init__() self.sorter = None def set_model(self, data): self.sorter = QSortFilterProxyModel() self.sorter.setDynamicSortFilter(True) self.sorter.setSortRole(Qt.EditRole) self.sorter.setSourceModel(OptimizerModel(data)) self.setModel(self.sorter) self.resizeColumnsToContents() self.setSortingEnabled(True)
class SpellingDictionaryEditDialog(QDialog, Ui_SpellingDictionaryEditDialog): """ Class implementing a dialog to edit the various spell checking dictionaries. """ def __init__(self, data, info, parent=None): """ Constructor @param data contents to be edited (string) @param info info string to show at the header (string) @param parent reference to the parent widget (QWidget) """ super(SpellingDictionaryEditDialog, self).__init__(parent) self.setupUi(self) self.infoLabel.setText(info) self.__model = QStringListModel(data.splitlines(), self) self.__model.sort(0) self.__proxyModel = QSortFilterProxyModel(self) self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.__proxyModel.setDynamicSortFilter(True) self.__proxyModel.setSourceModel(self.__model) self.wordList.setModel(self.__proxyModel) self.searchEdit.textChanged.connect( self.__proxyModel.setFilterFixedString) self.removeButton.clicked.connect(self.wordList.removeSelected) self.removeAllButton.clicked.connect(self.wordList.removeAll) @pyqtSlot() def on_addButton_clicked(self): """ Private slot to handle adding an entry. """ self.__model.insertRow(self.__model.rowCount()) self.wordList.edit( self.__proxyModel.index(self.__model.rowCount() - 1, 0)) def getData(self): """ Public method to get the data. @return data of the dialog (string) """ return os.linesep.join( [line for line in self.__model.stringList() if line])
class PopUpView(QTableView): def __init__(self, parent=None): super().__init__() self.sorter = None def set_model(self, data): self.sorter = QSortFilterProxyModel() self.sorter.setDynamicSortFilter(True) self.sorter.setSortRole(Qt.EditRole) self.sorter.setSourceModel(PopUpModel(data)) self.setModel(self.sorter) self.resizeColumnsToContents() self.setSortingEnabled(True) self.setSelectionBehavior(QAbstractItemView.SelectRows)
def connectDB(self, initQuery): self.db = QtSql.QSqlDatabase.addDatabase('QMYSQL') self.db.setHostName(self.config['db']['host']) self.db.setUserName(self.config['db']['login']) self.db.setPassword(self.config['db']['password']) self.db.setDatabaseName(self.config['db']['dbname']) tabmodel = Model(self, self.db, initQuery) orderedTabmodel = QSortFilterProxyModel(self) orderedTabmodel.setSourceModel(tabmodel) orderedTabmodel.setDynamicSortFilter(True) self.tableView.setModel(orderedTabmodel) # self.tableView.setContextMenuPolicy(Qt.CustomContextMenu) # self.tableView.customContextMenuRequested[QPoint].connect(self.contextMenuRequested) self.tableView.show() self.tableView.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents)
def main(): """The main entry point, compatible with setuptools entry points.""" app = QApplication(sys.argv) with open(os.path.join(os.path.dirname(__file__), 'testgui.ui')) as fobj: window = loadUi(fobj) model = GameListModel(get_games()) model_sorted = QSortFilterProxyModel() model_sorted.setDynamicSortFilter(True) model_sorted.setSortCaseSensitivity(Qt.CaseInsensitive) model_sorted.setSourceModel(model) model_sorted.sort(0, Qt.AscendingOrder) window.view_games.setModel(model_sorted) window.show() sys.exit(app.exec_())
class SortFilterTreeView(QTreeView): def __init__(self, parent=None): super().__init__(parent) self._proxy_model = QSortFilterProxyModel(self) self._proxy_model.setDynamicSortFilter(True) super().setModel(self._proxy_model) header = FilterHeader(self) header.filter_changed.connect(self.set_filter) self.setHeader(header) self.setSortingEnabled(True) def set_filter(self, section, filter_text): self._proxy_model.setFilterWildcard(filter_text) self._proxy_model.setFilterKeyColumn(section) def setModel(self, model): self.header().set_filter_boxes(model.columnCount()) self._proxy_model.setSourceModel(model) self.sortByColumn(0, Qt.AscendingOrder) super().setModel(self._proxy_model)
class CompilerView(QTableView): def __init__(self, parent=None): super().__init__() self.sorter = None def set_model(self, data): self.sorter = QSortFilterProxyModel() self.sorter.setDynamicSortFilter(True) self.sorter.setSortRole(Qt.EditRole) self.sorter.setFilterKeyColumn(1) self.sorter.setSourceModel(CompilerModel(data)) self.setModel(self.sorter) self.resizeColumnsToContents() self.setColumnWidth(0, max(100, self.columnWidth(0))) self.setColumnWidth(1, max(100, self.columnWidth(1))) for x in range (4, 8): self.setColumnWidth(x, max(self.columnWidth(x), 100)) self.setSortingEnabled(True) self.setSelectionBehavior(QAbstractItemView.SelectRows)
class DataFrameDialog(QDialog, Ui_DataFrameDialog): def __init__(self, dataframe): super(DataFrameDialog, self).__init__() self.setupUi(self) def dataitem(value): item = QStandardItem() try: item.setData(float(value), 2) except ValueError: item.setText(str(value)) return item self.datatable = QStandardItemModel(self) self.datatable.setColumnCount(dataframe.shape[1]) for row in dataframe.itertuples(index=True): self.datatable.appendRow([dataitem(x) for x in row]) self.datatable.setHorizontalHeaderLabels( ["Index"] + [x.title() for x in dataframe.axes[1]]) self.proxymodel = QSortFilterProxyModel(self) self.proxymodel.setSourceModel(self.datatable) self.tableView.setModel(self.proxymodel) self.proxymodel.setDynamicSortFilter(True) self.proxymodel.sort(0)
class BreakPointViewer(QTreeView): """ Class implementing the Breakpoint viewer widget. Breakpoints will be shown with all their details. They can be modified through the context menu of this widget. @signal sourceFile(str, int) emitted to show the source of a breakpoint """ sourceFile = pyqtSignal(str, int) def __init__(self, parent=None): """ Constructor @param parent the parent (QWidget) """ super(BreakPointViewer, self).__init__(parent) self.setObjectName("BreakPointViewer") self.__model = None self.setItemsExpandable(False) self.setRootIsDecorated(False) self.setAlternatingRowColors(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setWindowTitle(self.tr("Breakpoints")) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.__showContextMenu) self.doubleClicked.connect(self.__doubleClicked) self.__createPopupMenus() self.condHistory = [] self.fnHistory = [] self.fnHistory.append('') def setModel(self, model): """ Public slot to set the breakpoint model. @param model reference to the breakpoint model (BreakPointModel) """ self.__model = model self.sortingModel = QSortFilterProxyModel() self.sortingModel.setDynamicSortFilter(True) self.sortingModel.setSourceModel(self.__model) super(BreakPointViewer, self).setModel(self.sortingModel) header = self.header() header.setSortIndicator(0, Qt.AscendingOrder) header.setSortIndicatorShown(True) if qVersion() >= "5.0.0": header.setSectionsClickable(True) else: header.setClickable(True) self.setSortingEnabled(True) self.__layoutDisplay() def __layoutDisplay(self): """ Private slot to perform a layout operation. """ self.__resizeColumns() self.__resort() def __resizeColumns(self): """ Private slot to resize the view when items get added, edited or deleted. """ self.header().resizeSections(QHeaderView.ResizeToContents) self.header().setStretchLastSection(True) def __resort(self): """ Private slot to resort the tree. """ self.model().sort(self.header().sortIndicatorSection(), self.header().sortIndicatorOrder()) def __toSourceIndex(self, index): """ Private slot to convert an index to a source index. @param index index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapToSource(index) def __fromSourceIndex(self, sindex): """ Private slot to convert a source index to an index. @param sindex source index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapFromSource(sindex) def __setRowSelected(self, index, selected=True): """ Private slot to select a complete row. @param index index determining the row to be selected (QModelIndex) @param selected flag indicating the action (bool) """ if not index.isValid(): return if selected: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) else: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.Deselect | QItemSelectionModel.Rows) self.selectionModel().select(index, flags) def __createPopupMenus(self): """ Private method to generate the popup menus. """ self.menu = QMenu() self.menu.addAction(self.tr("Add"), self.__addBreak) self.menu.addAction(self.tr("Edit..."), self.__editBreak) self.menu.addSeparator() self.menu.addAction(self.tr("Enable"), self.__enableBreak) self.menu.addAction(self.tr("Enable all"), self.__enableAllBreaks) self.menu.addSeparator() self.menu.addAction(self.tr("Disable"), self.__disableBreak) self.menu.addAction(self.tr("Disable all"), self.__disableAllBreaks) self.menu.addSeparator() self.menu.addAction(self.tr("Delete"), self.__deleteBreak) self.menu.addAction(self.tr("Delete all"), self.__deleteAllBreaks) self.menu.addSeparator() self.menu.addAction(self.tr("Goto"), self.__showSource) self.menu.addSeparator() self.menu.addAction(self.tr("Configure..."), self.__configure) self.backMenuActions = {} self.backMenu = QMenu() self.backMenu.addAction(self.tr("Add"), self.__addBreak) self.backMenuActions["EnableAll"] = \ self.backMenu.addAction(self.tr("Enable all"), self.__enableAllBreaks) self.backMenuActions["DisableAll"] = \ self.backMenu.addAction(self.tr("Disable all"), self.__disableAllBreaks) self.backMenuActions["DeleteAll"] = \ self.backMenu.addAction(self.tr("Delete all"), self.__deleteAllBreaks) self.backMenu.aboutToShow.connect(self.__showBackMenu) self.backMenu.addSeparator() self.backMenu.addAction(self.tr("Configure..."), self.__configure) self.multiMenu = QMenu() self.multiMenu.addAction(self.tr("Add"), self.__addBreak) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Enable selected"), self.__enableSelectedBreaks) self.multiMenu.addAction(self.tr("Enable all"), self.__enableAllBreaks) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Disable selected"), self.__disableSelectedBreaks) self.multiMenu.addAction(self.tr("Disable all"), self.__disableAllBreaks) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Delete selected"), self.__deleteSelectedBreaks) self.multiMenu.addAction(self.tr("Delete all"), self.__deleteAllBreaks) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Configure..."), self.__configure) def __showContextMenu(self, coord): """ Private slot to show the context menu. @param coord the position of the mouse pointer (QPoint) """ cnt = self.__getSelectedItemsCount() if cnt <= 1: index = self.indexAt(coord) if index.isValid(): cnt = 1 self.__setRowSelected(index) coord = self.mapToGlobal(coord) if cnt > 1: self.multiMenu.popup(coord) elif cnt == 1: self.menu.popup(coord) else: self.backMenu.popup(coord) def __clearSelection(self): """ Private slot to clear the selection. """ for index in self.selectedIndexes(): self.__setRowSelected(index, False) def __addBreak(self): """ Private slot to handle the add breakpoint context menu entry. """ from .EditBreakpointDialog import EditBreakpointDialog dlg = EditBreakpointDialog((self.fnHistory[0], None), None, self.condHistory, self, modal=1, addMode=1, filenameHistory=self.fnHistory) if dlg.exec_() == QDialog.Accepted: fn, line, cond, temp, enabled, count = dlg.getAddData() if fn is not None: if fn in self.fnHistory: self.fnHistory.remove(fn) self.fnHistory.insert(0, fn) if cond: if cond in self.condHistory: self.condHistory.remove(cond) self.condHistory.insert(0, cond) self.__model.addBreakPoint(fn, line, (cond, temp, enabled, count)) self.__resizeColumns() self.__resort() def __doubleClicked(self, index): """ Private slot to handle the double clicked signal. @param index index of the entry that was double clicked (QModelIndex) """ if index.isValid(): self.__editBreakpoint(index) def __editBreak(self): """ Private slot to handle the edit breakpoint context menu entry. """ index = self.currentIndex() if index.isValid(): self.__editBreakpoint(index) def __editBreakpoint(self, index): """ Private slot to edit a breakpoint. @param index index of breakpoint to be edited (QModelIndex) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): bp = self.__model.getBreakPointByIndex(sindex) if not bp: return fn, line, cond, temp, enabled, count = bp[:6] from .EditBreakpointDialog import EditBreakpointDialog dlg = EditBreakpointDialog( (fn, line), (cond, temp, enabled, count), self.condHistory, self, modal=True) if dlg.exec_() == QDialog.Accepted: cond, temp, enabled, count = dlg.getData() if cond: if cond in self.condHistory: self.condHistory.remove(cond) self.condHistory.insert(0, cond) self.__model.setBreakPointByIndex( sindex, fn, line, (cond, temp, enabled, count)) self.__resizeColumns() self.__resort() def __setBpEnabled(self, index, enabled): """ Private method to set the enabled status of a breakpoint. @param index index of breakpoint to be enabled/disabled (QModelIndex) @param enabled flag indicating the enabled status to be set (boolean) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.setBreakPointEnabledByIndex(sindex, enabled) def __enableBreak(self): """ Private slot to handle the enable breakpoint context menu entry. """ index = self.currentIndex() self.__setBpEnabled(index, True) self.__resizeColumns() self.__resort() def __enableAllBreaks(self): """ Private slot to handle the enable all breakpoints context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setBpEnabled(index, True) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __enableSelectedBreaks(self): """ Private slot to handle the enable selected breakpoints context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setBpEnabled(index, True) self.__resizeColumns() self.__resort() def __disableBreak(self): """ Private slot to handle the disable breakpoint context menu entry. """ index = self.currentIndex() self.__setBpEnabled(index, False) self.__resizeColumns() self.__resort() def __disableAllBreaks(self): """ Private slot to handle the disable all breakpoints context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setBpEnabled(index, False) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __disableSelectedBreaks(self): """ Private slot to handle the disable selected breakpoints context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setBpEnabled(index, False) self.__resizeColumns() self.__resort() def __deleteBreak(self): """ Private slot to handle the delete breakpoint context menu entry. """ index = self.currentIndex() sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.deleteBreakPointByIndex(sindex) def __deleteAllBreaks(self): """ Private slot to handle the delete all breakpoints context menu entry. """ self.__model.deleteAll() def __deleteSelectedBreaks(self): """ Private slot to handle the delete selected breakpoints context menu entry. """ idxList = [] for index in self.selectedIndexes(): sindex = self.__toSourceIndex(index) if sindex.isValid() and index.column() == 0: idxList.append(sindex) self.__model.deleteBreakPoints(idxList) def __showSource(self): """ Private slot to handle the goto context menu entry. """ index = self.currentIndex() sindex = self.__toSourceIndex(index) bp = self.__model.getBreakPointByIndex(sindex) if not bp: return fn, line = bp[:2] self.sourceFile.emit(fn, line) def highlightBreakpoint(self, fn, lineno): """ Public slot to handle the clientLine signal. @param fn filename of the breakpoint (string) @param lineno line number of the breakpoint (integer) """ sindex = self.__model.getBreakPointIndex(fn, lineno) if sindex.isValid(): return index = self.__fromSourceIndex(sindex) if index.isValid(): self.__clearSelection() self.__setRowSelected(index, True) def handleResetUI(self): """ Public slot to reset the breakpoint viewer. """ self.__clearSelection() def __showBackMenu(self): """ Private slot to handle the aboutToShow signal of the background menu. """ if self.model().rowCount() == 0: self.backMenuActions["EnableAll"].setEnabled(False) self.backMenuActions["DisableAll"].setEnabled(False) self.backMenuActions["DeleteAll"].setEnabled(False) else: self.backMenuActions["EnableAll"].setEnabled(True) self.backMenuActions["DisableAll"].setEnabled(True) self.backMenuActions["DeleteAll"].setEnabled(True) def __getSelectedItemsCount(self): """ Private method to get the count of items selected. @return count of items selected (integer) """ count = len(self.selectedIndexes()) // (self.__model.columnCount() - 1) # column count is 1 greater than selectable return count def __configure(self): """ Private method to open the configuration dialog. """ e5App().getObject("UserInterface").showPreferences( "debuggerGeneralPage")
class Explorer(QWidget): """ This class implements the diagram predicate node explorer. """ def __init__(self, mainwindow): """ Initialize the Explorer. :type mainwindow: MainWindow """ super().__init__(mainwindow) self.expanded = {} self.searched = {} self.scrolled = {} self.mainview = None self.iconA = QIcon(':/icons/treeview-icon-attribute') self.iconC = QIcon(':/icons/treeview-icon-concept') self.iconD = QIcon(':/icons/treeview-icon-datarange') self.iconI = QIcon(':/icons/treeview-icon-instance') self.iconR = QIcon(':/icons/treeview-icon-role') self.iconV = QIcon(':/icons/treeview-icon-value') self.search = StringField(self) self.search.setAcceptDrops(False) self.search.setClearButtonEnabled(True) self.search.setPlaceholderText('Search...') self.search.setFixedHeight(30) self.model = QStandardItemModel(self) self.proxy = QSortFilterProxyModel(self) self.proxy.setDynamicSortFilter(False) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxy.setSortCaseSensitivity(Qt.CaseSensitive) self.proxy.setSourceModel(self.model) self.view = ExplorerView(mainwindow, self) self.view.setModel(self.proxy) self.mainLayout = QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.search) self.mainLayout.addWidget(self.view) self.setContentsMargins(0, 0, 0, 0) self.setMinimumWidth(216) self.setMinimumHeight(160) connect(self.view.doubleClicked, self.itemDoubleClicked) connect(self.view.pressed, self.itemPressed) connect(self.view.collapsed, self.itemCollapsed) connect(self.view.expanded, self.itemExpanded) connect(self.search.textChanged, self.filterItem) #################################################################################################################### # # # EVENTS # # # #################################################################################################################### def paintEvent(self, paintEvent): """ This is needed for the widget to pick the stylesheet. :type paintEvent: QPaintEvent """ option = QStyleOption() option.initFrom(self) painter = QPainter(self) style = self.style() style.drawPrimitive(QStyle.PE_Widget, option, painter, self) #################################################################################################################### # # # SLOTS # # # #################################################################################################################### @pyqtSlot('QGraphicsItem') def add(self, item): """ Add a node in the tree view. :type item: AbstractItem """ if item.node and item.predicate: parent = self.parentFor(item) if not parent: parent = ParentItem(item) parent.setIcon(self.iconFor(item)) self.model.appendRow(parent) self.proxy.sort(0, Qt.AscendingOrder) child = ChildItem(item) child.setData(item) parent.appendRow(child) self.proxy.sort(0, Qt.AscendingOrder) @pyqtSlot(str) def filterItem(self, key): """ Executed when the search box is filled with data. :type key: str """ if self.mainview: self.proxy.setFilterFixedString(key) self.proxy.sort(Qt.AscendingOrder) self.searched[self.mainview] = key @pyqtSlot('QModelIndex') def itemCollapsed(self, index): """ Executed when an item in the tree view is collapsed. :type index: QModelIndex """ if self.mainview: if self.mainview in self.expanded: item = self.model.itemFromIndex(self.proxy.mapToSource(index)) expanded = self.expanded[self.mainview] expanded.remove(item.text()) @pyqtSlot('QModelIndex') def itemDoubleClicked(self, index): """ Executed when an item in the tree view is double clicked. :type index: QModelIndex """ item = self.model.itemFromIndex(self.proxy.mapToSource(index)) node = item.data() if node: self.selectNode(node) self.focusNode(node) @pyqtSlot('QModelIndex') def itemExpanded(self, index): """ Executed when an item in the tree view is expanded. :type index: QModelIndex """ if self.mainview: item = self.model.itemFromIndex(self.proxy.mapToSource(index)) if self.mainview not in self.expanded: self.expanded[self.mainview] = set() expanded = self.expanded[self.mainview] expanded.add(item.text()) @pyqtSlot('QModelIndex') def itemPressed(self, index): """ Executed when an item in the tree view is clicked. :type index: QModelIndex """ item = self.model.itemFromIndex(self.proxy.mapToSource(index)) node = item.data() if node: self.selectNode(node) @pyqtSlot('QGraphicsItem') def remove(self, item): """ Remove a node from the tree view. :type item: AbstractItem """ if item.node and item.predicate: parent = self.parentFor(item) if parent: child = self.childFor(parent, item) if child: parent.removeRow(child.index().row()) if not parent.rowCount(): self.model.removeRow(parent.index().row()) #################################################################################################################### # # # AUXILIARY METHODS # # # #################################################################################################################### @staticmethod def childFor(parent, node): """ Search the item representing this node among parent children. :type parent: QStandardItem :type node: AbstractNode """ key = ChildItem.key(node) for i in range(parent.rowCount()): child = parent.child(i) if child.text() == key: return child return None def parentFor(self, node): """ Search the parent element of the given node. :type node: AbstractNode :rtype: QStandardItem """ key = ParentItem.key(node) for i in self.model.findItems(key, Qt.MatchExactly): n = i.child(0).data() if node.item is n.item: return i return None #################################################################################################################### # # # INTERFACE # # # #################################################################################################################### def browse(self, view): """ Set the widget to inspect the given view. :type view: MainView """ self.reset() self.mainview = view if self.mainview: scene = self.mainview.scene() connect(scene.index.sgnItemAdded, self.add) connect(scene.index.sgnItemRemoved, self.remove) for item in scene.index.nodes(): self.add(item) if self.mainview in self.expanded: expanded = self.expanded[self.mainview] for i in range(self.model.rowCount()): item = self.model.item(i) index = self.proxy.mapFromSource( self.model.indexFromItem(item)) self.view.setExpanded(index, item.text() in expanded) key = '' if self.mainview in self.searched: key = self.searched[self.mainview] self.search.setText(key) if self.mainview in self.scrolled: rect = self.rect() item = first(self.model.findItems( self.scrolled[self.mainview])) for i in range(self.model.rowCount()): self.view.scrollTo( self.proxy.mapFromSource( self.model.indexFromItem(self.model.item(i)))) index = self.proxy.mapToSource( self.view.indexAt(rect.topLeft())) if self.model.itemFromIndex(index) is item: break def reset(self): """ Clear the widget from inspecting the current view. """ if self.mainview: rect = self.rect() item = self.model.itemFromIndex( self.proxy.mapToSource(self.view.indexAt(rect.topLeft()))) if item: node = item.data() key = ParentItem.key(node) if node else item.text() self.scrolled[self.mainview] = key else: self.scrolled.pop(self.mainview, None) try: scene = self.mainview.scene() disconnect(scene.index.sgnItemAdded, self.add) disconnect(scene.index.sgnItemRemoved, self.remove) except RuntimeError: pass finally: self.mainview = None self.model.clear() def flush(self, view): """ Flush the cache of the given mainview. :type view: MainView """ self.expanded.pop(view, None) self.searched.pop(view, None) self.scrolled.pop(view, None) def iconFor(self, node): """ Returns the icon for the given node. :type node: """ if node.item is Item.AttributeNode: return self.iconA if node.item is Item.ConceptNode: return self.iconC if node.item is Item.ValueDomainNode: return self.iconD if node.item is Item.ValueRestrictionNode: return self.iconD if node.item is Item.IndividualNode: if node.identity is Identity.Instance: return self.iconI if node.identity is Identity.Value: return self.iconV if node.item is Item.RoleNode: return self.iconR def focusNode(self, node): """ Focus the given node in the main view. :type node: AbstractNode """ if self.mainview: self.mainview.centerOn(node) def selectNode(self, node): """ Select the given node in the main view. :type node: AbstractNode """ if self.mainview: scene = self.mainview.scene() scene.clearSelection() node.setSelected(True)
class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): """ Class implementing a dialog to generate code for a Qt5 dialog. """ DialogClasses = { "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", "QTabWidget", "QToolBox", "QStackedWidget" } Separator = 25 * "=" def __init__(self, formName, project, parent=None): """ Constructor @param formName name of the file containing the form (string) @param project reference to the project object @param parent parent widget if the dialog (QWidget) """ super(CreateDialogCodeDialog, self).__init__(parent) self.setupUi(self) self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.slotsView.header().hide() self.project = project self.formFile = formName filename, ext = os.path.splitext(self.formFile) self.srcFile = '{0}{1}'.format( filename, self.project.getDefaultSourceExtension()) self.slotsModel = QStandardItemModel() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.proxyModel.setSourceModel(self.slotsModel) self.slotsView.setModel(self.proxyModel) # initialize some member variables self.__initError = False self.__module = None packagesRoot = self.project.getUicParameter("PackagesRoot") if packagesRoot: self.packagesPath = os.path.join(self.project.getProjectPath(), packagesRoot) else: self.packagesPath = self.project.getProjectPath() if os.path.exists(self.srcFile): vm = e5App().getObject("ViewManager") ed = vm.getOpenEditor(self.srcFile) if ed and not vm.checkDirty(ed): self.__initError = True return try: splitExt = os.path.splitext(self.srcFile) if len(splitExt) == 2: exts = [splitExt[1]] else: exts = None from Utilities import ModuleParser self.__module = ModuleParser.readModule(self.srcFile, extensions=exts, caching=False) except ImportError: pass if self.__module is not None: self.filenameEdit.setText(self.srcFile) classesList = [] vagueClassesList = [] for cls in list(self.__module.classes.values()): if not set(cls.super).isdisjoint( CreateDialogCodeDialog.DialogClasses): classesList.append(cls.name) else: vagueClassesList.append(cls.name) classesList.sort() self.classNameCombo.addItems(classesList) if vagueClassesList: if classesList: self.classNameCombo.addItem( CreateDialogCodeDialog.Separator) self.classNameCombo.addItems(sorted(vagueClassesList)) if (os.path.exists(self.srcFile) and self.__module is not None and self.classNameCombo.count() == 0): self.__initError = True E5MessageBox.critical( self, self.tr("Create Dialog Code"), self.tr("""The file <b>{0}</b> exists but does not contain""" """ any classes.""").format(self.srcFile)) self.okButton.setEnabled(self.classNameCombo.count() > 0) self.__updateSlotsModel() def initError(self): """ Public method to determine, if there was an initialzation error. @return flag indicating an initialzation error (boolean) """ return self.__initError def __runUicLoadUi(self, command): """ Private method to run the UicLoadUi.py script with the given command and return the output. @param command uic command to be run @type str @return tuple of process output and error flag @rtype tuple of (str, bool) """ venvName = self.project.getDebugProperty("VIRTUALENV") venvManager = e5App().getObject("VirtualEnvManager") interpreter = venvManager.getVirtualenvInterpreter(venvName) execPath = venvManager.getVirtualenvExecPath(venvName) if not interpreter: interpreter = sys.executable env = QProcessEnvironment.systemEnvironment() if execPath: if env.contains("PATH"): env.insert("PATH", os.pathsep.join([execPath, env.value("PATH")])) else: env.insert("PATH", execPath) loadUi = os.path.join(os.path.dirname(__file__), "UicLoadUi.py") args = [ loadUi, command, self.formFile, self.packagesPath, ] uicText = "" ok = False proc = QProcess() proc.setWorkingDirectory(self.packagesPath) proc.setProcessEnvironment(env) proc.start(interpreter, args) started = proc.waitForStarted(5000) finished = proc.waitForFinished(30000) if started and finished: output = proc.readAllStandardOutput() outText = str(output, "utf-8", "replace") if proc.exitCode() == 0: ok = True uicText = outText.strip() else: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, outText)) else: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>The project specific Python interpreter <b>{0}</b>""" """ could not be started or did not finish within 30""" """ seconds.</p>""").format(interpreter)) return uicText, ok def __objectName(self): """ Private method to get the object name of a form. @return object name @rtype str """ objectName = "" output, ok = self.__runUicLoadUi("object_name") if ok and output: objectName = output return objectName def __className(self): """ Private method to get the class name of a form. @return class name @rtype str """ className = "" output, ok = self.__runUicLoadUi("class_name") if ok and output: className = output return className def __signatures(self): """ Private slot to get the signatures. @return list of signatures (list of strings) """ if self.__module is None: return [] signatures = [] clsName = self.classNameCombo.currentText() if clsName: cls = self.__module.classes[clsName] for meth in list(cls.methods.values()): if meth.name.startswith("on_"): if meth.pyqtSignature is not None: sig = ", ".join([ bytes(QMetaObject.normalizedType(t)).decode() for t in meth.pyqtSignature.split(",") ]) signatures.append("{0}({1})".format(meth.name, sig)) else: signatures.append(meth.name) return signatures def __mapType(self, type_): """ Private method to map a type as reported by Qt's meta object to the correct Python type. @param type_ type as reported by Qt (QByteArray) @return mapped Python type (string) """ mapped = bytes(type_).decode() # I. always check for * mapped = mapped.replace("*", "") if (self.project.getProjectLanguage() != "Python2" or self.project.getProjectType in ("PySide", "PySide2")): # 1. check for const mapped = mapped.replace("const ", "") # 2. replace QString and QStringList mapped = (mapped.replace("QStringList", "list").replace("QString", "str")) # 3. replace double by float mapped = mapped.replace("double", "float") return mapped def __updateSlotsModel(self): """ Private slot to update the slots tree display. """ self.filterEdit.clear() output, ok = self.__runUicLoadUi("signatures") if ok and output: objectsList = json.loads(output.strip()) signatureList = self.__signatures() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) for objectDict in objectsList: itm = QStandardItem("{0} ({1})".format( objectDict["name"], objectDict["class_name"])) self.slotsModel.appendRow(itm) for methodDict in objectDict["methods"]: itm2 = QStandardItem(methodDict["signature"]) itm.appendRow(itm2) if self.__module is not None: if (methodDict["methods"][0] in signatureList or methodDict["methods"][1] in signatureList): itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) itm2.setCheckState(Qt.Checked) itm2.setForeground(QBrush(Qt.blue)) continue itm2.setData(methodDict["pyqt_signature"], pyqtSignatureRole) itm2.setData(methodDict["python_signature"], pythonSignatureRole) itm2.setData(methodDict["return_type"], returnTypeRole) itm2.setData(methodDict["parameter_types"], parameterTypesListRole) itm2.setData(methodDict["parameter_names"], parameterNamesListRole) itm2.setFlags( Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)) itm2.setCheckState(Qt.Unchecked) self.slotsView.sortByColumn(0, Qt.AscendingOrder) def __generateCode(self): """ Private slot to generate the code as requested by the user. """ # first decide on extension if (self.filenameEdit.text().endswith(".py") or self.filenameEdit.text().endswith(".pyw")): self.__generatePythonCode() elif self.filenameEdit.text().endswith(".rb"): pass # second decide on project language elif self.project.getProjectLanguage() in ["Python2", "Python3"]: self.__generatePythonCode() elif self.project.getProjectLanguage() == "Ruby": pass else: # assume Python (our global default) self.__generatePythonCode() def __generatePythonCode(self): """ Private slot to generate Python code as requested by the user. """ # init some variables sourceImpl = [] appendAtIndex = -1 indentStr = " " slotsCode = [] if self.__module is None: # new file try: if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py2.tmpl") elif self.project.getProjectType() == "PySide2": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside2.py2.tmpl") elif self.project.getProjectType() == "PyQt5": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py2.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py2.tmpl") else: if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py.tmpl") elif self.project.getProjectType() == "PySide2": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside2.py.tmpl") elif self.project.getProjectType() in [ "PyQt5", "E6Plugin" ]: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py.tmpl") tmplFile = open(tmplName, 'r', encoding="utf-8") template = tmplFile.read() tmplFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the code template file""" """ "{0}".</p><p>Reason: {1}</p>""").format( tmplName, str(why))) return objName = self.__objectName() if objName: template = (template.replace( "$FORMFILE$", os.path.splitext( os.path.basename(self.formFile))[0]).replace( "$FORMCLASS$", objName).replace( "$CLASSNAME$", self.classNameCombo.currentText()).replace( "$SUPERCLASS$", self.__className())) sourceImpl = template.splitlines(True) appendAtIndex = -1 # determine indent string for line in sourceImpl: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break else: # extend existing file try: srcFile = open(self.srcFile, 'r', encoding="utf-8") sourceImpl = srcFile.readlines() srcFile.close() if not sourceImpl[-1].endswith("\n"): sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.srcFile, str(why))) return cls = self.__module.classes[self.classNameCombo.currentText()] if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: appendAtIndex = -1 # delete empty lines at end while not sourceImpl[-1].strip(): del sourceImpl[-1] else: appendAtIndex = cls.endlineno - 1 while not sourceImpl[appendAtIndex].strip(): appendAtIndex -= 1 appendAtIndex += 1 # determine indent string for line in sourceImpl[cls.lineno:cls.endlineno + 1]: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break # do the coding stuff if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() in ("PySide", "PySide2"): pyqtSignatureFormat = '@Slot({0})' elif self.project.getProjectType() == "PyQt5": pyqtSignatureFormat = '@pyqtSlot({0})' else: pyqtSignatureFormat = '@pyqtSignature("{0}")' else: if self.project.getProjectType() in ("PySide", "PySide2"): pyqtSignatureFormat = '@Slot({0})' else: pyqtSignatureFormat = '@pyqtSlot({0})' for row in range(self.slotsModel.rowCount()): topItem = self.slotsModel.item(row) for childRow in range(topItem.rowCount()): child = topItem.child(childRow) if (child.checkState() and child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable)): slotsCode.append('{0}\n'.format(indentStr)) slotsCode.append('{0}{1}\n'.format( indentStr, pyqtSignatureFormat.format( child.data(pyqtSignatureRole)))) slotsCode.append('{0}def {1}:\n'.format( indentStr, child.data(pythonSignatureRole))) indentStr2 = indentStr * 2 slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append( '{0}Slot documentation goes here.\n'.format( indentStr2)) if (child.data(returnTypeRole) or child.data(parameterTypesListRole)): slotsCode.append('{0}\n'.format(indentStr2)) if child.data(parameterTypesListRole): for name, type_ in zip( child.data(parameterNamesListRole), child.data(parameterTypesListRole)): slotsCode.append( '{0}@param {1} DESCRIPTION\n'.format( indentStr2, name)) slotsCode.append('{0}@type {1}\n'.format( indentStr2, type_)) if child.data(returnTypeRole): slotsCode.append( '{0}@returns DESCRIPTION\n'.format(indentStr2)) slotsCode.append('{0}@rtype {1}\n'.format( indentStr2, child.data(returnTypeRole))) slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append('{0}# {1}: not implemented yet\n'.format( indentStr2, "TODO")) slotsCode.append( '{0}raise NotImplementedError\n'.format(indentStr2)) if appendAtIndex == -1: sourceImpl.extend(slotsCode) else: sourceImpl[appendAtIndex:appendAtIndex] = slotsCode # write the new code try: if self.project.useSystemEol(): newline = None else: newline = self.project.getEolString() srcFile = open(self.filenameEdit.text(), 'w', encoding="utf-8", newline=newline) srcFile.write("".join(sourceImpl)) srcFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not write the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.filenameEdit.text(), str(why))) return self.project.appendFile(self.filenameEdit.text()) @pyqtSlot(int) def on_classNameCombo_activated(self, index): """ Private slot to handle the activated signal of the classname combo. @param index index of the activated item (integer) """ if (self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator): self.okButton.setEnabled(False) self.filterEdit.clear() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) else: self.okButton.setEnabled(True) self.__updateSlotsModel() def on_filterEdit_textChanged(self, text): """ Private slot called, when thext of the filter edit has changed. @param text changed text (string) """ re = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(re) @pyqtSlot() def on_newButton_clicked(self): """ Private slot called to enter the data for a new dialog class. """ path, file = os.path.split(self.srcFile) objName = self.__objectName() if objName: dlg = NewDialogClassDialog(objName, file, path, self) if dlg.exec_() == QDialog.Accepted: className, fileName = dlg.getData() self.classNameCombo.clear() self.classNameCombo.addItem(className) self.srcFile = fileName self.filenameEdit.setText(self.srcFile) self.__module = None self.okButton.setEnabled(self.classNameCombo.count() > 0) def on_buttonBox_clicked(self, button): """ Private slot to handle the buttonBox clicked signal. @param button reference to the button that was clicked (QAbstractButton) """ if button == self.okButton: self.__generateCode() self.accept()
class Table(QWidget): def __init__(self, name, data, columns=None, index=False, checkable=False, parent=None): QWidget.__init__(self, parent) self.name = name self.index = index self.checkable = checkable if not any([data, columns]): self.columns = [] else: self.columns = columns if columns else list(data[0].keys()) if checkable: self.columns.insert(0, '') if index: self.columns.insert(0, 'ID') self.setData(data) self.initUI() def initUI(self): # Layout UI elements of table mainLayout = QVBoxLayout() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.sourceModel = QStandardItemModel(0, len(self.columns), self) for i, column in enumerate(self.columns): self.sourceModel.setHeaderData(i, Qt.Horizontal, column) self.proxyModel.setSourceModel(self.sourceModel) self.proxyGroupBox = QGroupBox(self.name) self.proxyView = DeselectableTreeView() self.proxyView.setRootIsDecorated(False) self.proxyView.setAlternatingRowColors(True) self.proxyView.setModel(self.proxyModel) if not self.checkable: self.proxyView.setSortingEnabled(True) self.proxyView.sortByColumn(0, Qt.AscendingOrder) self.proxyView.setEditTriggers(QAbstractItemView.NoEditTriggers) proxyLayout = QGridLayout() proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3) self.proxyGroupBox.setLayout(proxyLayout) mainLayout.addWidget(self.proxyGroupBox) self.setLayout(mainLayout) self.update(self.data) def setSourceModel(self, model): self.proxyModel.setSourceModel(model) def setData(self, data): self.data = [] for i, item in enumerate(data): d = {} for col in self.columns: if col == 'ID': d[col] = item.get(col, i + 1) else: d[col] = item.get(col) self.data.append(d) #self.data = [{k: item.get(k, i+1) for k in self.columns} for i, item in enumerate(data)] def sortBy(self, colName): idx = 0 try: idx = self.columns.index(colName) except: pass self.proxyView.sortByColumn(idx, Qt.AscendingOrder) def rowCount(self): return self.sourceModel.rowCount() def columnCount(self): return self.sourceModel.columnCount() def addRow(self, row_i, rowData): self.sourceModel.insertRow(row_i) for col_i, data in enumerate(rowData.values()): if self.checkable and col_i == 0: self.proxyView.setColumnWidth(col_i, 1) item = QStandardItem(True) item.setCheckable(True) item.setCheckState(False) self.sourceModel.setItem(row_i, col_i, item) else: self.sourceModel.setData(self.sourceModel.index(row_i, col_i), data) def update(self, data): self.setData(data) self.sourceModel.removeRows(0, self.sourceModel.rowCount()) for i, data in enumerate(self.data): self.addRow(i, data) def getSelectedRowIndex(self): ''' Returns the index of the selected row from the source model ''' try: return self.proxyModel.mapToSource( self.proxyView.selectedIndexes()[0]).row() except: return False def getCheckedRowData(self): selectedData = [] for row_i in range(self.sourceModel.rowCount()): item = self.sourceModel.item(row_i, 0) if item.checkState(): selectedData.append(self.data[row_i]) return selectedData
class WatchPointViewer(QTreeView): """ Class implementing the watch expression viewer widget. Watch expressions will be shown with all their details. They can be modified through the context menu of this widget. """ def __init__(self, parent=None): """ Constructor @param parent the parent (QWidget) """ super(WatchPointViewer, self).__init__(parent) self.setObjectName("WatchExpressionViewer") self.__model = None self.setItemsExpandable(False) self.setRootIsDecorated(False) self.setAlternatingRowColors(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setWindowTitle(self.tr("Watchpoints")) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.__showContextMenu) self.doubleClicked.connect(self.__doubleClicked) self.__createPopupMenus() def setModel(self, model): """ Public slot to set the watch expression model. @param model reference to the watch expression model (WatchPointModel) """ self.__model = model self.sortingModel = QSortFilterProxyModel() self.sortingModel.setDynamicSortFilter(True) self.sortingModel.setSourceModel(self.__model) super(WatchPointViewer, self).setModel(self.sortingModel) header = self.header() header.setSortIndicator(0, Qt.AscendingOrder) header.setSortIndicatorShown(True) if qVersion() >= "5.0.0": header.setSectionsClickable(True) else: header.setClickable(True) self.setSortingEnabled(True) self.__layoutDisplay() def __layoutDisplay(self): """ Private slot to perform a layout operation. """ self.__resizeColumns() self.__resort() def __resizeColumns(self): """ Private slot to resize the view when items get added, edited or deleted. """ self.header().resizeSections(QHeaderView.ResizeToContents) self.header().setStretchLastSection(True) def __resort(self): """ Private slot to resort the tree. """ self.model().sort(self.header().sortIndicatorSection(), self.header().sortIndicatorOrder()) def __toSourceIndex(self, index): """ Private slot to convert an index to a source index. @param index index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapToSource(index) def __fromSourceIndex(self, sindex): """ Private slot to convert a source index to an index. @param sindex source index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapFromSource(sindex) def __setRowSelected(self, index, selected=True): """ Private slot to select a complete row. @param index index determining the row to be selected (QModelIndex) @param selected flag indicating the action (bool) """ if not index.isValid(): return if selected: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) else: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.Deselect | QItemSelectionModel.Rows) self.selectionModel().select(index, flags) def __createPopupMenus(self): """ Private method to generate the popup menus. """ self.menu = QMenu() self.menu.addAction(self.tr("Add"), self.__addWatchPoint) self.menu.addAction(self.tr("Edit..."), self.__editWatchPoint) self.menu.addSeparator() self.menu.addAction(self.tr("Enable"), self.__enableWatchPoint) self.menu.addAction(self.tr("Enable all"), self.__enableAllWatchPoints) self.menu.addSeparator() self.menu.addAction(self.tr("Disable"), self.__disableWatchPoint) self.menu.addAction(self.tr("Disable all"), self.__disableAllWatchPoints) self.menu.addSeparator() self.menu.addAction(self.tr("Delete"), self.__deleteWatchPoint) self.menu.addAction(self.tr("Delete all"), self.__deleteAllWatchPoints) self.menu.addSeparator() self.menu.addAction(self.tr("Configure..."), self.__configure) self.backMenuActions = {} self.backMenu = QMenu() self.backMenu.addAction(self.tr("Add"), self.__addWatchPoint) self.backMenuActions["EnableAll"] = \ self.backMenu.addAction(self.tr("Enable all"), self.__enableAllWatchPoints) self.backMenuActions["DisableAll"] = \ self.backMenu.addAction(self.tr("Disable all"), self.__disableAllWatchPoints) self.backMenuActions["DeleteAll"] = \ self.backMenu.addAction(self.tr("Delete all"), self.__deleteAllWatchPoints) self.backMenu.addSeparator() self.backMenu.addAction(self.tr("Configure..."), self.__configure) self.backMenu.aboutToShow.connect(self.__showBackMenu) self.multiMenu = QMenu() self.multiMenu.addAction(self.tr("Add"), self.__addWatchPoint) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Enable selected"), self.__enableSelectedWatchPoints) self.multiMenu.addAction(self.tr("Enable all"), self.__enableAllWatchPoints) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Disable selected"), self.__disableSelectedWatchPoints) self.multiMenu.addAction(self.tr("Disable all"), self.__disableAllWatchPoints) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Delete selected"), self.__deleteSelectedWatchPoints) self.multiMenu.addAction(self.tr("Delete all"), self.__deleteAllWatchPoints) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Configure..."), self.__configure) def __showContextMenu(self, coord): """ Private slot to show the context menu. @param coord the position of the mouse pointer (QPoint) """ cnt = self.__getSelectedItemsCount() if cnt <= 1: index = self.indexAt(coord) if index.isValid(): cnt = 1 self.__setRowSelected(index) coord = self.mapToGlobal(coord) if cnt > 1: self.multiMenu.popup(coord) elif cnt == 1: self.menu.popup(coord) else: self.backMenu.popup(coord) def __clearSelection(self): """ Private slot to clear the selection. """ for index in self.selectedIndexes(): self.__setRowSelected(index, False) def __findDuplicates(self, cond, special, showMessage=False, index=QModelIndex()): """ Private method to check, if an entry already exists. @param cond condition to check (string) @param special special condition to check (string) @param showMessage flag indicating a message should be shown, if a duplicate entry is found (boolean) @param index index that should not be considered duplicate (QModelIndex) @return flag indicating a duplicate entry (boolean) """ idx = self.__model.getWatchPointIndex(cond, special) duplicate = idx.isValid() and \ idx.internalPointer() != index.internalPointer() if showMessage and duplicate: if not special: msg = self.tr("""<p>A watch expression '<b>{0}</b>'""" """ already exists.</p>""")\ .format(Utilities.html_encode(cond)) else: msg = self.tr( """<p>A watch expression '<b>{0}</b>'""" """ for the variable <b>{1}</b> already exists.</p>""")\ .format(special, Utilities.html_encode(cond)) E5MessageBox.warning(self, self.tr("Watch expression already exists"), msg) return duplicate def __addWatchPoint(self): """ Private slot to handle the add watch expression context menu entry. """ from .EditWatchpointDialog import EditWatchpointDialog dlg = EditWatchpointDialog(("", False, True, 0, ""), self) if dlg.exec_() == QDialog.Accepted: cond, temp, enabled, ignorecount, special = dlg.getData() if not self.__findDuplicates(cond, special, True): self.__model.addWatchPoint(cond, special, (temp, enabled, ignorecount)) self.__resizeColumns() self.__resort() def __doubleClicked(self, index): """ Private slot to handle the double clicked signal. @param index index of the entry that was double clicked (QModelIndex) """ if index.isValid(): self.__doEditWatchPoint(index) def __editWatchPoint(self): """ Private slot to handle the edit watch expression context menu entry. """ index = self.currentIndex() if index.isValid(): self.__doEditWatchPoint(index) def __doEditWatchPoint(self, index): """ Private slot to edit a watch expression. @param index index of watch expression to be edited (QModelIndex) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): wp = self.__model.getWatchPointByIndex(sindex) if not wp: return cond, special, temp, enabled, count = wp[:5] from .EditWatchpointDialog import EditWatchpointDialog dlg = EditWatchpointDialog((cond, temp, enabled, count, special), self) if dlg.exec_() == QDialog.Accepted: cond, temp, enabled, count, special = dlg.getData() if not self.__findDuplicates(cond, special, True, sindex): self.__model.setWatchPointByIndex(sindex, cond, special, (temp, enabled, count)) self.__resizeColumns() self.__resort() def __setWpEnabled(self, index, enabled): """ Private method to set the enabled status of a watch expression. @param index index of watch expression to be enabled/disabled (QModelIndex) @param enabled flag indicating the enabled status to be set (boolean) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.setWatchPointEnabledByIndex(sindex, enabled) def __enableWatchPoint(self): """ Private slot to handle the enable watch expression context menu entry. """ index = self.currentIndex() self.__setWpEnabled(index, True) self.__resizeColumns() self.__resort() def __enableAllWatchPoints(self): """ Private slot to handle the enable all watch expressions context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setWpEnabled(index, True) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __enableSelectedWatchPoints(self): """ Private slot to handle the enable selected watch expressions context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setWpEnabled(index, True) self.__resizeColumns() self.__resort() def __disableWatchPoint(self): """ Private slot to handle the disable watch expression context menu entry. """ index = self.currentIndex() self.__setWpEnabled(index, False) self.__resizeColumns() self.__resort() def __disableAllWatchPoints(self): """ Private slot to handle the disable all watch expressions context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setWpEnabled(index, False) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __disableSelectedWatchPoints(self): """ Private slot to handle the disable selected watch expressions context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setWpEnabled(index, False) self.__resizeColumns() self.__resort() def __deleteWatchPoint(self): """ Private slot to handle the delete watch expression context menu entry. """ index = self.currentIndex() sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.deleteWatchPointByIndex(sindex) def __deleteAllWatchPoints(self): """ Private slot to handle the delete all watch expressions context menu entry. """ self.__model.deleteAll() def __deleteSelectedWatchPoints(self): """ Private slot to handle the delete selected watch expressions context menu entry. """ idxList = [] for index in self.selectedIndexes(): sindex = self.__toSourceIndex(index) if sindex.isValid() and index.column() == 0: idxList.append(sindex) self.__model.deleteWatchPoints(idxList) def __showBackMenu(self): """ Private slot to handle the aboutToShow signal of the background menu. """ if self.model().rowCount() == 0: self.backMenuActions["EnableAll"].setEnabled(False) self.backMenuActions["DisableAll"].setEnabled(False) self.backMenuActions["DeleteAll"].setEnabled(False) else: self.backMenuActions["EnableAll"].setEnabled(True) self.backMenuActions["DisableAll"].setEnabled(True) self.backMenuActions["DeleteAll"].setEnabled(True) def __getSelectedItemsCount(self): """ Private method to get the count of items selected. @return count of items selected (integer) """ count = len(self.selectedIndexes()) // (self.__model.columnCount() - 1) # column count is 1 greater than selectable return count def __configure(self): """ Private method to open the configuration dialog. """ e5App().getObject("UserInterface")\ .showPreferences("debuggerGeneralPage")
def sorted(self): proxy_model = QSortFilterProxyModel(self) proxy_model.setSourceModel(self) proxy_model.setDynamicSortFilter(True) proxy_model.sort(0) return proxy_model
class WatchPointViewer(QTreeView): """ Class implementing the watch expression viewer widget. Watch expressions will be shown with all their details. They can be modified through the context menu of this widget. """ def __init__(self, parent=None): """ Constructor @param parent the parent (QWidget) """ super(WatchPointViewer, self).__init__(parent) self.setObjectName("WatchExpressionViewer") self.__model = None self.setItemsExpandable(False) self.setRootIsDecorated(False) self.setAlternatingRowColors(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setWindowTitle(self.tr("Watchpoints")) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.__showContextMenu) self.doubleClicked.connect(self.__doubleClicked) self.__createPopupMenus() def setModel(self, model): """ Public slot to set the watch expression model. @param model reference to the watch expression model (WatchPointModel) """ self.__model = model self.sortingModel = QSortFilterProxyModel() self.sortingModel.setDynamicSortFilter(True) self.sortingModel.setSourceModel(self.__model) super(WatchPointViewer, self).setModel(self.sortingModel) header = self.header() header.setSortIndicator(0, Qt.AscendingOrder) header.setSortIndicatorShown(True) if qVersion() >= "5.0.0": header.setSectionsClickable(True) else: header.setClickable(True) self.setSortingEnabled(True) self.__layoutDisplay() def __layoutDisplay(self): """ Private slot to perform a layout operation. """ self.__resizeColumns() self.__resort() def __resizeColumns(self): """ Private slot to resize the view when items get added, edited or deleted. """ self.header().resizeSections(QHeaderView.ResizeToContents) self.header().setStretchLastSection(True) def __resort(self): """ Private slot to resort the tree. """ self.model().sort(self.header().sortIndicatorSection(), self.header().sortIndicatorOrder()) def __toSourceIndex(self, index): """ Private slot to convert an index to a source index. @param index index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapToSource(index) def __fromSourceIndex(self, sindex): """ Private slot to convert a source index to an index. @param sindex source index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapFromSource(sindex) def __setRowSelected(self, index, selected=True): """ Private slot to select a complete row. @param index index determining the row to be selected (QModelIndex) @param selected flag indicating the action (bool) """ if not index.isValid(): return if selected: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) else: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.Deselect | QItemSelectionModel.Rows) self.selectionModel().select(index, flags) def __createPopupMenus(self): """ Private method to generate the popup menus. """ self.menu = QMenu() self.menu.addAction(self.tr("Add"), self.__addWatchPoint) self.menu.addAction(self.tr("Edit..."), self.__editWatchPoint) self.menu.addSeparator() self.menu.addAction(self.tr("Enable"), self.__enableWatchPoint) self.menu.addAction(self.tr("Enable all"), self.__enableAllWatchPoints) self.menu.addSeparator() self.menu.addAction(self.tr("Disable"), self.__disableWatchPoint) self.menu.addAction(self.tr("Disable all"), self.__disableAllWatchPoints) self.menu.addSeparator() self.menu.addAction(self.tr("Delete"), self.__deleteWatchPoint) self.menu.addAction(self.tr("Delete all"), self.__deleteAllWatchPoints) self.menu.addSeparator() self.menu.addAction(self.tr("Configure..."), self.__configure) self.backMenuActions = {} self.backMenu = QMenu() self.backMenu.addAction(self.tr("Add"), self.__addWatchPoint) self.backMenuActions["EnableAll"] = \ self.backMenu.addAction(self.tr("Enable all"), self.__enableAllWatchPoints) self.backMenuActions["DisableAll"] = \ self.backMenu.addAction(self.tr("Disable all"), self.__disableAllWatchPoints) self.backMenuActions["DeleteAll"] = \ self.backMenu.addAction(self.tr("Delete all"), self.__deleteAllWatchPoints) self.backMenu.addSeparator() self.backMenu.addAction(self.tr("Configure..."), self.__configure) self.backMenu.aboutToShow.connect(self.__showBackMenu) self.multiMenu = QMenu() self.multiMenu.addAction(self.tr("Add"), self.__addWatchPoint) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Enable selected"), self.__enableSelectedWatchPoints) self.multiMenu.addAction(self.tr("Enable all"), self.__enableAllWatchPoints) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Disable selected"), self.__disableSelectedWatchPoints) self.multiMenu.addAction(self.tr("Disable all"), self.__disableAllWatchPoints) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Delete selected"), self.__deleteSelectedWatchPoints) self.multiMenu.addAction(self.tr("Delete all"), self.__deleteAllWatchPoints) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Configure..."), self.__configure) def __showContextMenu(self, coord): """ Private slot to show the context menu. @param coord the position of the mouse pointer (QPoint) """ cnt = self.__getSelectedItemsCount() if cnt <= 1: index = self.indexAt(coord) if index.isValid(): cnt = 1 self.__setRowSelected(index) coord = self.mapToGlobal(coord) if cnt > 1: self.multiMenu.popup(coord) elif cnt == 1: self.menu.popup(coord) else: self.backMenu.popup(coord) def __clearSelection(self): """ Private slot to clear the selection. """ for index in self.selectedIndexes(): self.__setRowSelected(index, False) def __findDuplicates(self, cond, special, showMessage=False, index=QModelIndex()): """ Private method to check, if an entry already exists. @param cond condition to check (string) @param special special condition to check (string) @param showMessage flag indicating a message should be shown, if a duplicate entry is found (boolean) @param index index that should not be considered duplicate (QModelIndex) @return flag indicating a duplicate entry (boolean) """ idx = self.__model.getWatchPointIndex(cond, special) duplicate = idx.isValid() and \ idx.internalPointer() != index.internalPointer() if showMessage and duplicate: if not special: msg = self.tr("""<p>A watch expression '<b>{0}</b>'""" """ already exists.</p>""")\ .format(Utilities.html_encode(cond)) else: msg = self.tr( """<p>A watch expression '<b>{0}</b>'""" """ for the variable <b>{1}</b> already exists.</p>""")\ .format(special, Utilities.html_encode(cond)) E5MessageBox.warning( self, self.tr("Watch expression already exists"), msg) return duplicate def __addWatchPoint(self): """ Private slot to handle the add watch expression context menu entry. """ from .EditWatchpointDialog import EditWatchpointDialog dlg = EditWatchpointDialog(("", False, True, 0, ""), self) if dlg.exec_() == QDialog.Accepted: cond, temp, enabled, ignorecount, special = dlg.getData() if not self.__findDuplicates(cond, special, True): self.__model.addWatchPoint(cond, special, (temp, enabled, ignorecount)) self.__resizeColumns() self.__resort() def __doubleClicked(self, index): """ Private slot to handle the double clicked signal. @param index index of the entry that was double clicked (QModelIndex) """ if index.isValid(): self.__doEditWatchPoint(index) def __editWatchPoint(self): """ Private slot to handle the edit watch expression context menu entry. """ index = self.currentIndex() if index.isValid(): self.__doEditWatchPoint(index) def __doEditWatchPoint(self, index): """ Private slot to edit a watch expression. @param index index of watch expression to be edited (QModelIndex) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): wp = self.__model.getWatchPointByIndex(sindex) if not wp: return cond, special, temp, enabled, count = wp[:5] from .EditWatchpointDialog import EditWatchpointDialog dlg = EditWatchpointDialog( (cond, temp, enabled, count, special), self) if dlg.exec_() == QDialog.Accepted: cond, temp, enabled, count, special = dlg.getData() if not self.__findDuplicates(cond, special, True, sindex): self.__model.setWatchPointByIndex( sindex, cond, special, (temp, enabled, count)) self.__resizeColumns() self.__resort() def __setWpEnabled(self, index, enabled): """ Private method to set the enabled status of a watch expression. @param index index of watch expression to be enabled/disabled (QModelIndex) @param enabled flag indicating the enabled status to be set (boolean) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.setWatchPointEnabledByIndex(sindex, enabled) def __enableWatchPoint(self): """ Private slot to handle the enable watch expression context menu entry. """ index = self.currentIndex() self.__setWpEnabled(index, True) self.__resizeColumns() self.__resort() def __enableAllWatchPoints(self): """ Private slot to handle the enable all watch expressions context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setWpEnabled(index, True) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __enableSelectedWatchPoints(self): """ Private slot to handle the enable selected watch expressions context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setWpEnabled(index, True) self.__resizeColumns() self.__resort() def __disableWatchPoint(self): """ Private slot to handle the disable watch expression context menu entry. """ index = self.currentIndex() self.__setWpEnabled(index, False) self.__resizeColumns() self.__resort() def __disableAllWatchPoints(self): """ Private slot to handle the disable all watch expressions context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setWpEnabled(index, False) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __disableSelectedWatchPoints(self): """ Private slot to handle the disable selected watch expressions context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setWpEnabled(index, False) self.__resizeColumns() self.__resort() def __deleteWatchPoint(self): """ Private slot to handle the delete watch expression context menu entry. """ index = self.currentIndex() sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.deleteWatchPointByIndex(sindex) def __deleteAllWatchPoints(self): """ Private slot to handle the delete all watch expressions context menu entry. """ self.__model.deleteAll() def __deleteSelectedWatchPoints(self): """ Private slot to handle the delete selected watch expressions context menu entry. """ idxList = [] for index in self.selectedIndexes(): sindex = self.__toSourceIndex(index) if sindex.isValid() and index.column() == 0: idxList.append(sindex) self.__model.deleteWatchPoints(idxList) def __showBackMenu(self): """ Private slot to handle the aboutToShow signal of the background menu. """ if self.model().rowCount() == 0: self.backMenuActions["EnableAll"].setEnabled(False) self.backMenuActions["DisableAll"].setEnabled(False) self.backMenuActions["DeleteAll"].setEnabled(False) else: self.backMenuActions["EnableAll"].setEnabled(True) self.backMenuActions["DisableAll"].setEnabled(True) self.backMenuActions["DeleteAll"].setEnabled(True) def __getSelectedItemsCount(self): """ Private method to get the count of items selected. @return count of items selected (integer) """ count = len(self.selectedIndexes()) // (self.__model.columnCount() - 1) # column count is 1 greater than selectable return count def __configure(self): """ Private method to open the configuration dialog. """ e5App().getObject("UserInterface")\ .showPreferences("debuggerGeneralPage")
class Example(QWidget): def __init__(self): super().__init__() self.setGeometry(300, 300, 400, 240) self.setWindowTitle("Filtering data") self.initData() self.initUI() def initData(self): words = ["radar", "robert", "Rome", "rodeo", "rust", "ready", "robot", "rampart", "RAM", "ROM"] self.model = QStringListModel(words) self.filterModel = QSortFilterProxyModel(self) self.filterModel.setSourceModel(self.model) self.filterModel.setDynamicSortFilter(True) def initUI(self): grid = QGridLayout() grid.setSpacing(10) self.lv = QListView(self) self.lv.setModel(self.filterModel) grid.addWidget(self.lv, 0, 0, 2, 2) self.filText = QLineEdit(self) grid.addWidget(self.filText, 0, 3, Qt.AlignTop) self.case = QCheckBox("Case sensitive", self) grid.addWidget(self.case, 1, 3, Qt.AlignTop) self.filterCombo = QComboBox(self) self.filterCombo.addItem("Regular expression", QVariant(QRegExp.RegExp)) self.filterCombo.addItem("Wildcard", QVariant(QRegExp.Wildcard)) self.filterCombo.addItem("Fixed string", QVariant(QRegExp.FixedString)) grid.addWidget(self.filterCombo, 2, 0) self.filterCombo.activated[str].connect(self.filterItems) self.filText.textChanged[str].connect(self.filterItems) self.case.toggled[bool].connect(self.filterItems) self.setLayout(grid) def filterItems(self, value): idx = self.filterCombo.currentIndex() syntaxType = self.filterCombo.itemData(idx) syntax = QRegExp.PatternSyntax(syntaxType) if self.case.isChecked(): case = Qt.CaseSensitive else:
def sorted(self): proxy_model = QSortFilterProxyModel(self) proxy_model.setSourceModel(self) proxy_model.setDynamicSortFilter(True) proxy_model.sort(0) return proxy_model
class SortFilterTableView(QTableView): def __init__(self, parent=None): super().__init__(parent) self._proxy_model = QSortFilterProxyModel(self) self._proxy_model.setDynamicSortFilter(True) super().setModel(self._proxy_model) header = FilterHeader(self) header.filter_changed.connect(self.set_filter) self.setHorizontalHeader(header) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.ContiguousSelection) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.show_context_menu) self.import_export_manager = ImportExportManager(self) self.copy_action = create_action( None, "Copy", self.copy_selection_to_clipboard) def show_context_menu(self, point): self.import_export_manager.set_model_index(self.indexAt(point)) context_menu = QMenu() context_menu.addAction(self.copy_action) context_menu.addAction(self.import_export_manager.export_action) context_menu.addAction(self.import_export_manager.import_action) context_menu.exec(self.mapToGlobal(point)) def keyPressEvent(self, event: QKeyEvent): if event.type() == QKeyEvent.KeyPress \ and event.matches(QKeySequence.Copy): self.copy_selection_to_clipboard() else: super().keyPressEvent(event) def copy_selection_to_clipboard(self): selected_indexes = self.selectionModel().selectedIndexes() if not selected_indexes or len(selected_indexes) == 0: return model = self.model() result = "\n".join( "\t".join(row) for row in self.selected_rows(model, selected_indexes) ) cp = QApplication.clipboard() cp.setText(result) def selected_rows(self, model, selected_indexes): row = [] last_row = selected_indexes[0].row() for current in selected_indexes: value = str(model.data(current, Qt.DisplayRole)) if last_row != current.row(): yield row row = [value, ] else: row.append(value) last_row = current.row() def set_filter(self, section, filter_text): log.debug("set_filter(section: %s, filter: %r)", section, filter_text) self._proxy_model.setFilterWildcard(filter_text) self._proxy_model.setFilterKeyColumn(section) def setModel(self, model): self.horizontalHeader().set_filter_boxes(model.columnCount()) self._proxy_model.setSourceModel(model) self._proxy_model.sort(0, Qt.AscendingOrder) super().setModel(self._proxy_model) font = model.data(0, Qt.FontRole) if font is None: font = self.font() metrics = QFontMetrics(font) self.verticalHeader().setDefaultSectionSize(metrics.lineSpacing() * 1.5) self.horizontalHeader().setDefaultSectionSize(metrics.maxWidth() * 5)
class BreakPointViewer(QTreeView): """ Class implementing the Breakpoint viewer widget. Breakpoints will be shown with all their details. They can be modified through the context menu of this widget. @signal sourceFile(str, int) emitted to show the source of a breakpoint """ sourceFile = pyqtSignal(str, int) def __init__(self, parent=None): """ Constructor @param parent the parent (QWidget) """ super(BreakPointViewer, self).__init__(parent) self.setObjectName("BreakPointViewer") self.__model = None self.setItemsExpandable(False) self.setRootIsDecorated(False) self.setAlternatingRowColors(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setWindowTitle(self.tr("Breakpoints")) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.__showContextMenu) self.doubleClicked.connect(self.__doubleClicked) self.__createPopupMenus() self.condHistory = [] self.fnHistory = [] self.fnHistory.append('') self.__loadRecent() def setModel(self, model): """ Public slot to set the breakpoint model. @param model reference to the breakpoint model (BreakPointModel) """ self.__model = model self.sortingModel = QSortFilterProxyModel() self.sortingModel.setDynamicSortFilter(True) self.sortingModel.setSourceModel(self.__model) super(BreakPointViewer, self).setModel(self.sortingModel) header = self.header() header.setSortIndicator(0, Qt.AscendingOrder) header.setSortIndicatorShown(True) header.setSectionsClickable(True) self.setSortingEnabled(True) self.__layoutDisplay() def __layoutDisplay(self): """ Private slot to perform a layout operation. """ self.__resizeColumns() self.__resort() def __resizeColumns(self): """ Private slot to resize the view when items get added, edited or deleted. """ self.header().resizeSections(QHeaderView.ResizeToContents) self.header().setStretchLastSection(True) def __resort(self): """ Private slot to resort the tree. """ self.model().sort(self.header().sortIndicatorSection(), self.header().sortIndicatorOrder()) def __toSourceIndex(self, index): """ Private slot to convert an index to a source index. @param index index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapToSource(index) def __fromSourceIndex(self, sindex): """ Private slot to convert a source index to an index. @param sindex source index to be converted (QModelIndex) @return mapped index (QModelIndex) """ return self.sortingModel.mapFromSource(sindex) def __setRowSelected(self, index, selected=True): """ Private slot to select a complete row. @param index index determining the row to be selected (QModelIndex) @param selected flag indicating the action (bool) """ if not index.isValid(): return if selected: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) else: flags = QItemSelectionModel.SelectionFlags( QItemSelectionModel.Deselect | QItemSelectionModel.Rows) self.selectionModel().select(index, flags) def __createPopupMenus(self): """ Private method to generate the popup menus. """ self.menu = QMenu() self.menu.addAction(self.tr("Add"), self.__addBreak) self.menu.addAction(self.tr("Edit..."), self.__editBreak) self.menu.addSeparator() self.menu.addAction(self.tr("Enable"), self.__enableBreak) self.menu.addAction(self.tr("Enable all"), self.__enableAllBreaks) self.menu.addSeparator() self.menu.addAction(self.tr("Disable"), self.__disableBreak) self.menu.addAction(self.tr("Disable all"), self.__disableAllBreaks) self.menu.addSeparator() self.menu.addAction(self.tr("Delete"), self.__deleteBreak) self.menu.addAction(self.tr("Delete all"), self.__deleteAllBreaks) self.menu.addSeparator() self.menu.addAction(self.tr("Goto"), self.__showSource) self.menu.addSeparator() self.menu.addAction(self.tr("Configure..."), self.__configure) self.backMenuActions = {} self.backMenu = QMenu() self.backMenu.addAction(self.tr("Add"), self.__addBreak) self.backMenuActions["EnableAll"] = self.backMenu.addAction( self.tr("Enable all"), self.__enableAllBreaks) self.backMenuActions["DisableAll"] = self.backMenu.addAction( self.tr("Disable all"), self.__disableAllBreaks) self.backMenuActions["DeleteAll"] = self.backMenu.addAction( self.tr("Delete all"), self.__deleteAllBreaks) self.backMenu.aboutToShow.connect(self.__showBackMenu) self.backMenu.addSeparator() self.backMenu.addAction(self.tr("Configure..."), self.__configure) self.multiMenu = QMenu() self.multiMenu.addAction(self.tr("Add"), self.__addBreak) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Enable selected"), self.__enableSelectedBreaks) self.multiMenu.addAction(self.tr("Enable all"), self.__enableAllBreaks) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Disable selected"), self.__disableSelectedBreaks) self.multiMenu.addAction(self.tr("Disable all"), self.__disableAllBreaks) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Delete selected"), self.__deleteSelectedBreaks) self.multiMenu.addAction(self.tr("Delete all"), self.__deleteAllBreaks) self.multiMenu.addSeparator() self.multiMenu.addAction(self.tr("Configure..."), self.__configure) def __showContextMenu(self, coord): """ Private slot to show the context menu. @param coord the position of the mouse pointer (QPoint) """ cnt = self.__getSelectedItemsCount() if cnt <= 1: index = self.indexAt(coord) if index.isValid(): cnt = 1 self.__setRowSelected(index) coord = self.mapToGlobal(coord) if cnt > 1: self.multiMenu.popup(coord) elif cnt == 1: self.menu.popup(coord) else: self.backMenu.popup(coord) def __clearSelection(self): """ Private slot to clear the selection. """ for index in self.selectedIndexes(): self.__setRowSelected(index, False) def __addBreak(self): """ Private slot to handle the add breakpoint context menu entry. """ from .EditBreakpointDialog import EditBreakpointDialog dlg = EditBreakpointDialog((self.fnHistory[0], None), None, self.condHistory, self, modal=1, addMode=1, filenameHistory=self.fnHistory) if dlg.exec_() == QDialog.Accepted: fn, line, cond, temp, enabled, count = dlg.getAddData() if fn is not None: if fn in self.fnHistory: self.fnHistory.remove(fn) self.fnHistory.insert(0, fn) if cond: if cond in self.condHistory: self.condHistory.remove(cond) self.condHistory.insert(0, cond) self.__saveRecent() self.__model.addBreakPoint(fn, line, (cond, temp, enabled, count)) self.__resizeColumns() self.__resort() def __doubleClicked(self, index): """ Private slot to handle the double clicked signal. @param index index of the entry that was double clicked (QModelIndex) """ if index.isValid(): self.__editBreakpoint(index) def __editBreak(self): """ Private slot to handle the edit breakpoint context menu entry. """ index = self.currentIndex() if index.isValid(): self.__editBreakpoint(index) def __editBreakpoint(self, index): """ Private slot to edit a breakpoint. @param index index of breakpoint to be edited (QModelIndex) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): bp = self.__model.getBreakPointByIndex(sindex) if not bp: return fn, line, cond, temp, enabled, count = bp[:6] from .EditBreakpointDialog import EditBreakpointDialog dlg = EditBreakpointDialog((fn, line), (cond, temp, enabled, count), self.condHistory, self, modal=True) if dlg.exec_() == QDialog.Accepted: cond, temp, enabled, count = dlg.getData() if cond: if cond in self.condHistory: self.condHistory.remove(cond) self.condHistory.insert(0, cond) self.__saveRecent() self.__model.setBreakPointByIndex(sindex, fn, line, (cond, temp, enabled, count)) self.__resizeColumns() self.__resort() def __setBpEnabled(self, index, enabled): """ Private method to set the enabled status of a breakpoint. @param index index of breakpoint to be enabled/disabled (QModelIndex) @param enabled flag indicating the enabled status to be set (boolean) """ sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.setBreakPointEnabledByIndex(sindex, enabled) def __enableBreak(self): """ Private slot to handle the enable breakpoint context menu entry. """ index = self.currentIndex() self.__setBpEnabled(index, True) self.__resizeColumns() self.__resort() def __enableAllBreaks(self): """ Private slot to handle the enable all breakpoints context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setBpEnabled(index, True) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __enableSelectedBreaks(self): """ Private slot to handle the enable selected breakpoints context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setBpEnabled(index, True) self.__resizeColumns() self.__resort() def __disableBreak(self): """ Private slot to handle the disable breakpoint context menu entry. """ index = self.currentIndex() self.__setBpEnabled(index, False) self.__resizeColumns() self.__resort() def __disableAllBreaks(self): """ Private slot to handle the disable all breakpoints context menu entry. """ index = self.model().index(0, 0) while index.isValid(): self.__setBpEnabled(index, False) index = self.indexBelow(index) self.__resizeColumns() self.__resort() def __disableSelectedBreaks(self): """ Private slot to handle the disable selected breakpoints context menu entry. """ for index in self.selectedIndexes(): if index.column() == 0: self.__setBpEnabled(index, False) self.__resizeColumns() self.__resort() def __deleteBreak(self): """ Private slot to handle the delete breakpoint context menu entry. """ index = self.currentIndex() sindex = self.__toSourceIndex(index) if sindex.isValid(): self.__model.deleteBreakPointByIndex(sindex) def __deleteAllBreaks(self): """ Private slot to handle the delete all breakpoints context menu entry. """ self.__model.deleteAll() def __deleteSelectedBreaks(self): """ Private slot to handle the delete selected breakpoints context menu entry. """ idxList = [] for index in self.selectedIndexes(): sindex = self.__toSourceIndex(index) if sindex.isValid() and index.column() == 0: idxList.append(sindex) self.__model.deleteBreakPoints(idxList) def __showSource(self): """ Private slot to handle the goto context menu entry. """ index = self.currentIndex() sindex = self.__toSourceIndex(index) bp = self.__model.getBreakPointByIndex(sindex) if not bp: return fn, line = bp[:2] self.sourceFile.emit(fn, line) def highlightBreakpoint(self, fn, lineno): """ Public slot to handle the clientLine signal. @param fn filename of the breakpoint (string) @param lineno line number of the breakpoint (integer) """ sindex = self.__model.getBreakPointIndex(fn, lineno) if sindex.isValid(): return index = self.__fromSourceIndex(sindex) if index.isValid(): self.__clearSelection() self.__setRowSelected(index, True) def handleResetUI(self): """ Public slot to reset the breakpoint viewer. """ self.__clearSelection() def __showBackMenu(self): """ Private slot to handle the aboutToShow signal of the background menu. """ if self.model().rowCount() == 0: self.backMenuActions["EnableAll"].setEnabled(False) self.backMenuActions["DisableAll"].setEnabled(False) self.backMenuActions["DeleteAll"].setEnabled(False) else: self.backMenuActions["EnableAll"].setEnabled(True) self.backMenuActions["DisableAll"].setEnabled(True) self.backMenuActions["DeleteAll"].setEnabled(True) def __getSelectedItemsCount(self): """ Private method to get the count of items selected. @return count of items selected (integer) """ count = len(self.selectedIndexes()) // (self.__model.columnCount() - 1) # column count is 1 greater than selectable return count def __configure(self): """ Private method to open the configuration dialog. """ e5App().getObject("UserInterface").showPreferences( "debuggerGeneralPage") def __loadRecent(self): """ Private method to load the recently used file names. """ Preferences.Prefs.rsettings.sync() # load recently used file names self.fnHistory = [] self.fnHistory.append('') rs = Preferences.Prefs.rsettings.value(recentNameBreakpointFiles) if rs is not None: recent = [ f for f in Preferences.toList(rs) if QFileInfo(f).exists() ] self.fnHistory.extend( recent[:Preferences.getDebugger("RecentNumber")]) # load recently entered condition expressions self.condHistory = [] rs = Preferences.Prefs.rsettings.value(recentNameBreakpointConditions) if rs is not None: self.condHistory = Preferences.toList( rs)[:Preferences.getDebugger("RecentNumber")] def __saveRecent(self): """ Private method to save the list of recently used file names. """ recent = [f for f in self.fnHistory if f] Preferences.Prefs.rsettings.setValue(recentNameBreakpointFiles, recent) Preferences.Prefs.rsettings.setValue(recentNameBreakpointConditions, self.condHistory) Preferences.Prefs.rsettings.sync()
class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): """ Class implementing a dialog to generate code for a Qt4/Qt5 dialog. """ DialogClasses = { "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", "QTabWidget", "QToolBox", "QStackedWidget" } Separator = 25 * "=" def __init__(self, formName, project, parent=None): """ Constructor @param formName name of the file containing the form (string) @param project reference to the project object @param parent parent widget if the dialog (QWidget) """ super(CreateDialogCodeDialog, self).__init__(parent) self.setupUi(self) self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.slotsView.header().hide() self.project = project self.formFile = formName filename, ext = os.path.splitext(self.formFile) self.srcFile = '{0}{1}'.format( filename, self.project.getDefaultSourceExtension()) self.slotsModel = QStandardItemModel() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.proxyModel.setSourceModel(self.slotsModel) self.slotsView.setModel(self.proxyModel) # initialize some member variables self.__initError = False self.__module = None if os.path.exists(self.srcFile): vm = e5App().getObject("ViewManager") ed = vm.getOpenEditor(self.srcFile) if ed and not vm.checkDirty(ed): self.__initError = True return try: splitExt = os.path.splitext(self.srcFile) if len(splitExt) == 2: exts = [splitExt[1]] else: exts = None from Utilities import ModuleParser self.__module = ModuleParser.readModule( self.srcFile, extensions=exts, caching=False) except ImportError: pass if self.__module is not None: self.filenameEdit.setText(self.srcFile) classesList = [] vagueClassesList = [] for cls in list(self.__module.classes.values()): if not set(cls.super).isdisjoint( CreateDialogCodeDialog.DialogClasses): classesList.append(cls.name) else: vagueClassesList.append(cls.name) classesList.sort() self.classNameCombo.addItems(classesList) if vagueClassesList: if classesList: self.classNameCombo.addItem( CreateDialogCodeDialog.Separator) self.classNameCombo.addItems(sorted(vagueClassesList)) if os.path.exists(self.srcFile) and \ self.__module is not None and \ self.classNameCombo.count() == 0: self.__initError = True E5MessageBox.critical( self, self.tr("Create Dialog Code"), self.tr( """The file <b>{0}</b> exists but does not contain""" """ any classes.""").format(self.srcFile)) self.okButton.setEnabled(self.classNameCombo.count() > 0) self.__updateSlotsModel() def initError(self): """ Public method to determine, if there was an initialzation error. @return flag indicating an initialzation error (boolean) """ return self.__initError def __objectName(self): """ Private method to get the object name of the dialog. @return object name (string) """ try: dlg = uic.loadUi( self.formFile, package=self.project.getProjectPath()) return dlg.objectName() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __className(self): """ Private method to get the class name of the dialog. @return class name (sting) """ try: dlg = uic.loadUi( self.formFile, package=self.project.getProjectPath()) return dlg.metaObject().className() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __signatures(self): """ Private slot to get the signatures. @return list of signatures (list of strings) """ if self.__module is None: return [] signatures = [] clsName = self.classNameCombo.currentText() if clsName: cls = self.__module.classes[clsName] for meth in list(cls.methods.values()): if meth.name.startswith("on_"): if meth.pyqtSignature is not None: sig = ", ".join( [bytes(QMetaObject.normalizedType(t)).decode() for t in meth.pyqtSignature.split(",")]) signatures.append("{0}({1})".format(meth.name, sig)) else: signatures.append(meth.name) return signatures def __mapType(self, type_): """ Private method to map a type as reported by Qt's meta object to the correct Python type. @param type_ type as reported by Qt (QByteArray) @return mapped Python type (string) """ mapped = bytes(type_).decode() if self.project.getProjectLanguage() != "Python2" or \ self.project.getProjectType == "PySide": # 1. check for const mapped = mapped.replace("const ", "") # 2. check for * mapped = mapped.replace("*", "") # 3. replace QString and QStringList mapped = mapped.replace("QStringList", "list")\ .replace("QString", "str") # 4. replace double by float mapped = mapped.replace("double", "float") return mapped def __updateSlotsModel(self): """ Private slot to update the slots tree display. """ self.filterEdit.clear() try: dlg = uic.loadUi( self.formFile, package=self.project.getProjectPath()) objects = dlg.findChildren(QWidget) + dlg.findChildren(QAction) signatureList = self.__signatures() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) for obj in objects: name = obj.objectName() if not name or name.startswith("qt_"): # ignore un-named or internal objects continue metaObject = obj.metaObject() className = metaObject.className() itm = QStandardItem("{0} ({1})".format(name, className)) self.slotsModel.appendRow(itm) for index in range(metaObject.methodCount()): metaMethod = metaObject.method(index) if metaMethod.methodType() == QMetaMethod.Signal: if qVersion() >= "5.0.0": itm2 = QStandardItem("on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()).decode())) else: itm2 = QStandardItem("on_{0}_{1}".format( name, metaMethod.signature())) itm.appendRow(itm2) if self.__module is not None: if qVersion() >= "5.0.0": method = "on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0]) else: method = "on_{0}_{1}".format( name, metaMethod.signature().split("(")[0]) method2 = "{0}({1})".format( method, ", ".join( [self.__mapType(t) for t in metaMethod.parameterTypes()])) if method2 in signatureList or \ method in signatureList: itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) itm2.setCheckState(Qt.Checked) itm2.setForeground(QBrush(Qt.blue)) continue returnType = self.__mapType( metaMethod.typeName().encode()) if returnType == 'void': returnType = "" parameterTypesList = [ self.__mapType(t) for t in metaMethod.parameterTypes()] pyqtSignature = ", ".join(parameterTypesList) parameterNames = metaMethod.parameterNames() if parameterNames: for index in range(len(parameterNames)): if not parameterNames[index]: parameterNames[index] = \ QByteArray("p{0:d}".format(index) .encode("utf-8")) parameterNamesList = [bytes(n).decode() for n in parameterNames] methNamesSig = ", ".join(parameterNamesList) if methNamesSig: if qVersion() >= "5.0.0": pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0], methNamesSig) else: pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, metaMethod.signature().split("(")[0], methNamesSig) else: if qVersion() >= "5.0.0": pythonSignature = "on_{0}_{1}(self)".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0]) else: pythonSignature = "on_{0}_{1}(self)".format( name, metaMethod.signature().split("(")[0]) itm2.setData(pyqtSignature, pyqtSignatureRole) itm2.setData(pythonSignature, pythonSignatureRole) itm2.setData(returnType, returnTypeRole) itm2.setData(parameterTypesList, parameterTypesListRole) itm2.setData(parameterNamesList, parameterNamesListRole) itm2.setFlags(Qt.ItemFlags( Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable) ) itm2.setCheckState(Qt.Unchecked) self.slotsView.sortByColumn(0, Qt.AscendingOrder) except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) def __generateCode(self): """ Private slot to generate the code as requested by the user. """ # first decide on extension if self.filenameEdit.text().endswith(".py") or \ self.filenameEdit.text().endswith(".pyw"): self.__generatePythonCode() elif self.filenameEdit.text().endswith(".rb"): pass # second decide on project language elif self.project.getProjectLanguage() in ["Python2", "Python3"]: self.__generatePythonCode() elif self.project.getProjectLanguage() == "Ruby": pass else: # assume Python (our global default) self.__generatePythonCode() def __generatePythonCode(self): """ Private slot to generate Python code as requested by the user. """ # init some variables sourceImpl = [] appendAtIndex = -1 indentStr = " " slotsCode = [] if self.__module is None: # new file try: if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py2.tmpl") elif self.project.getProjectType() == "PyQt5": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py2.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py2.tmpl") else: if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py.tmpl") elif self.project.getProjectType() in [ "PyQt5", "E6Plugin"]: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py.tmpl") tmplFile = open(tmplName, 'r', encoding="utf-8") template = tmplFile.read() tmplFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr( """<p>Could not open the code template file""" """ "{0}".</p><p>Reason: {1}</p>""") .format(tmplName, str(why))) return objName = self.__objectName() if objName: template = template\ .replace( "$FORMFILE$", os.path.splitext(os.path.basename(self.formFile))[0])\ .replace("$FORMCLASS$", objName)\ .replace("$CLASSNAME$", self.classNameCombo.currentText())\ .replace("$SUPERCLASS$", self.__className()) sourceImpl = template.splitlines(True) appendAtIndex = -1 # determine indent string for line in sourceImpl: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break else: # extend existing file try: srcFile = open(self.srcFile, 'r', encoding="utf-8") sourceImpl = srcFile.readlines() srcFile.close() if not sourceImpl[-1].endswith("\n"): sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr( """<p>Could not open the source file "{0}".</p>""" """<p>Reason: {1}</p>""") .format(self.srcFile, str(why))) return cls = self.__module.classes[self.classNameCombo.currentText()] if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: appendAtIndex = -1 # delete empty lines at end while not sourceImpl[-1].strip(): del sourceImpl[-1] else: appendAtIndex = cls.endlineno - 1 while not sourceImpl[appendAtIndex].strip(): appendAtIndex -= 1 appendAtIndex += 1 # determine indent string for line in sourceImpl[cls.lineno:cls.endlineno + 1]: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break # do the coding stuff if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' elif self.project.getProjectType() == "PyQt5": pyqtSignatureFormat = '@pyqtSlot({0})' else: pyqtSignatureFormat = '@pyqtSignature("{0}")' else: if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' else: pyqtSignatureFormat = '@pyqtSlot({0})' for row in range(self.slotsModel.rowCount()): topItem = self.slotsModel.item(row) for childRow in range(topItem.rowCount()): child = topItem.child(childRow) if child.checkState() and \ child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable): slotsCode.append('{0}\n'.format(indentStr)) slotsCode.append('{0}{1}\n'.format( indentStr, pyqtSignatureFormat.format( child.data(pyqtSignatureRole)))) slotsCode.append('{0}def {1}:\n'.format( indentStr, child.data(pythonSignatureRole))) indentStr2 = indentStr * 2 slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append( '{0}Slot documentation goes here.\n'.format( indentStr2)) if child.data(returnTypeRole) or \ child.data(parameterTypesListRole): slotsCode.append('{0}\n'.format(indentStr2)) if child.data(parameterTypesListRole): for name, type_ in zip( child.data(parameterNamesListRole), child.data(parameterTypesListRole)): slotsCode.append( '{0}@param {1} DESCRIPTION\n'.format( indentStr2, name)) slotsCode.append('{0}@type {1}\n'.format( indentStr2, type_)) if child.data(returnTypeRole): slotsCode.append( '{0}@returns DESCRIPTION\n'.format( indentStr2)) slotsCode.append('{0}@rtype {1}\n'.format( indentStr2, child.data(returnTypeRole))) slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append('{0}# {1}: not implemented yet\n'.format( indentStr2, "TODO")) slotsCode.append('{0}raise NotImplementedError\n'.format( indentStr2)) if appendAtIndex == -1: sourceImpl.extend(slotsCode) else: sourceImpl[appendAtIndex:appendAtIndex] = slotsCode # write the new code try: if self.project.useSystemEol(): newline = None else: newline = self.project.getEolString() srcFile = open(self.filenameEdit.text(), 'w', encoding="utf-8", newline=newline) srcFile.write("".join(sourceImpl)) srcFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not write the source file "{0}".</p>""" """<p>Reason: {1}</p>""") .format(self.filenameEdit.text(), str(why))) return self.project.appendFile(self.filenameEdit.text()) @pyqtSlot(int) def on_classNameCombo_activated(self, index): """ Private slot to handle the activated signal of the classname combo. @param index index of the activated item (integer) """ if (self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator): self.okButton.setEnabled(False) self.filterEdit.clear() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) else: self.okButton.setEnabled(True) self.__updateSlotsModel() def on_filterEdit_textChanged(self, text): """ Private slot called, when thext of the filter edit has changed. @param text changed text (string) """ re = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(re) @pyqtSlot() def on_newButton_clicked(self): """ Private slot called to enter the data for a new dialog class. """ path, file = os.path.split(self.srcFile) objName = self.__objectName() if objName: dlg = NewDialogClassDialog(objName, file, path, self) if dlg.exec_() == QDialog.Accepted: className, fileName = dlg.getData() self.classNameCombo.clear() self.classNameCombo.addItem(className) self.srcFile = fileName self.filenameEdit.setText(self.srcFile) self.__module = None self.okButton.setEnabled(self.classNameCombo.count() > 0) def on_buttonBox_clicked(self, button): """ Private slot to handle the buttonBox clicked signal. @param button reference to the button that was clicked (QAbstractButton) """ if button == self.okButton: self.__generateCode() self.accept()
class EmojisModel(): def update_model(self, clear=True): log.info("updating emoji model.") app = get_app() _ = app._tr # Clear all items if clear: self.model_paths = {} self.model.clear() self.emoji_groups.clear() # Add Headers self.model.setHorizontalHeaderLabels([_("Name")]) # Get emoji metadata emoji_metadata_path = os.path.join(info.PATH, "emojis", "data", "openmoji-optimized.json") with open(emoji_metadata_path, 'r', encoding="utf-8") as f: emoji_lookup = json.load(f) # get a list of files in the OpenShot /emojis directory emojis_dir = os.path.join(info.PATH, "emojis", "color", "svg") emoji_paths = [{"type": "common", "dir": emojis_dir, "files": os.listdir(emojis_dir)}, ] # Add optional user-defined transitions folder if os.path.exists(info.EMOJIS_PATH) and os.listdir(info.EMOJIS_PATH): emoji_paths.append({"type": "user", "dir": info.EMOJIS_PATH, "files": os.listdir(info.EMOJIS_PATH)}) for group in emoji_paths: dir = group["dir"] files = group["files"] for filename in sorted(files): path = os.path.join(dir, filename) fileBaseName = os.path.splitext(filename)[0] # Skip hidden files (such as .DS_Store, etc...) if filename[0] == "." or "thumbs.db" in filename.lower(): continue # get name of transition emoji = emoji_lookup.get(fileBaseName, {}) emoji_name = _(emoji.get("annotation", fileBaseName).capitalize()) emoji_type = _(emoji.get("group", "user").split('-')[0].capitalize()) # Track unique emoji groups if emoji_type not in self.emoji_groups: self.emoji_groups.append(emoji_type) # Check for thumbnail path (in build-in cache) thumb_path = os.path.join(info.IMAGES_PATH, "cache", "{}.png".format(fileBaseName)) # Check built-in cache (if not found) if not os.path.exists(thumb_path): # Check user folder cache thumb_path = os.path.join(info.CACHE_PATH, "{}.png".format(fileBaseName)) # Generate thumbnail (if needed) if not os.path.exists(thumb_path): try: # Reload this reader clip = openshot.Clip(path) reader = clip.Reader() # Open reader reader.Open() # Save thumbnail reader.GetFrame(0).Thumbnail( thumb_path, 75, 75, os.path.join(info.IMAGES_PATH, "mask.png"), "", "#000", True, "png", 85 ) reader.Close() clip.Close() except Exception: # Handle exception log.info('Invalid emoji image file: %s' % filename) msg = QMessageBox() msg.setText(_("{} is not a valid image file.".format(filename))) msg.exec_() continue row = [] # Set emoji data col = QStandardItem("Name") col.setIcon(QIcon(thumb_path)) col.setText(emoji_name) col.setToolTip(emoji_name) col.setData(path) col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled) row.append(col) # Append filterable group col = QStandardItem(emoji_type) row.append(col) # Append ROW to MODEL (if does not already exist in model) if path not in self.model_paths: self.model.appendRow(row) self.model_paths[path] = path def __init__(self, *args): # Create standard model self.app = get_app() self.model = EmojiStandardItemModel() self.model.setColumnCount(2) self.model_paths = {} self.emoji_groups = [] # Create proxy models (for grouping, sorting and filtering) self.group_model = QSortFilterProxyModel() self.group_model.setDynamicSortFilter(False) self.group_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.group_model.setSortCaseSensitivity(Qt.CaseSensitive) self.group_model.setSourceModel(self.model) self.group_model.setSortLocaleAware(True) self.group_model.setFilterKeyColumn(1) self.proxy_model = QSortFilterProxyModel() self.proxy_model.setDynamicSortFilter(False) self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxy_model.setSortCaseSensitivity(Qt.CaseSensitive) self.proxy_model.setSourceModel(self.group_model) self.proxy_model.setSortLocaleAware(True) # Attempt to load model testing interface, if requested # (will only succeed with Qt 5.11+) if info.MODEL_TEST: try: # Create model tester objects from PyQt5.QtTest import QAbstractItemModelTester self.model_tests = [] for m in [self.proxy_model, self.group_model, self.model]: self.model_tests.append( QAbstractItemModelTester( m, QAbstractItemModelTester.FailureReportingMode.Warning) ) log.info("Enabled {} model tests for emoji data".format(len(self.model_tests))) except ImportError: pass
class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): """ Class implementing a dialog to generate code for a Qt4/Qt5 dialog. """ DialogClasses = { "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", "QTabWidget", "QToolBox", "QStackedWidget" } Separator = 25 * "=" def __init__(self, formName, project, parent=None): """ Constructor @param formName name of the file containing the form (string) @param project reference to the project object @param parent parent widget if the dialog (QWidget) """ super(CreateDialogCodeDialog, self).__init__(parent) self.setupUi(self) self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.slotsView.header().hide() self.project = project self.formFile = formName filename, ext = os.path.splitext(self.formFile) self.srcFile = '{0}{1}'.format( filename, self.project.getDefaultSourceExtension()) self.slotsModel = QStandardItemModel() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.proxyModel.setSourceModel(self.slotsModel) self.slotsView.setModel(self.proxyModel) # initialize some member variables self.__initError = False self.__module = None if os.path.exists(self.srcFile): vm = e5App().getObject("ViewManager") ed = vm.getOpenEditor(self.srcFile) if ed and not vm.checkDirty(ed): self.__initError = True return try: splitExt = os.path.splitext(self.srcFile) if len(splitExt) == 2: exts = [splitExt[1]] else: exts = None from Utilities import ModuleParser self.__module = ModuleParser.readModule(self.srcFile, extensions=exts, caching=False) except ImportError: pass if self.__module is not None: self.filenameEdit.setText(self.srcFile) classesList = [] vagueClassesList = [] for cls in list(self.__module.classes.values()): if not set(cls.super).isdisjoint( CreateDialogCodeDialog.DialogClasses): classesList.append(cls.name) else: vagueClassesList.append(cls.name) classesList.sort() self.classNameCombo.addItems(classesList) if vagueClassesList: if classesList: self.classNameCombo.addItem( CreateDialogCodeDialog.Separator) self.classNameCombo.addItems(sorted(vagueClassesList)) if os.path.exists(self.srcFile) and \ self.__module is not None and \ self.classNameCombo.count() == 0: self.__initError = True E5MessageBox.critical( self, self.tr("Create Dialog Code"), self.tr("""The file <b>{0}</b> exists but does not contain""" """ any classes.""").format(self.srcFile)) self.okButton.setEnabled(self.classNameCombo.count() > 0) self.__updateSlotsModel() def initError(self): """ Public method to determine, if there was an initialzation error. @return flag indicating an initialzation error (boolean) """ return self.__initError def __objectName(self): """ Private method to get the object name of the dialog. @return object name (string) """ try: dlg = uic.loadUi(self.formFile, package=self.project.getProjectPath()) return dlg.objectName() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr("""<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __className(self): """ Private method to get the class name of the dialog. @return class name (sting) """ try: dlg = uic.loadUi(self.formFile, package=self.project.getProjectPath()) return dlg.metaObject().className() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr("""<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __signatures(self): """ Private slot to get the signatures. @return list of signatures (list of strings) """ if self.__module is None: return [] signatures = [] clsName = self.classNameCombo.currentText() if clsName: cls = self.__module.classes[clsName] for meth in list(cls.methods.values()): if meth.name.startswith("on_"): if meth.pyqtSignature is not None: sig = ", ".join([ bytes(QMetaObject.normalizedType(t)).decode() for t in meth.pyqtSignature.split(",") ]) signatures.append("{0}({1})".format(meth.name, sig)) else: signatures.append(meth.name) return signatures def __mapType(self, type_): """ Private method to map a type as reported by Qt's meta object to the correct Python type. @param type_ type as reported by Qt (QByteArray) @return mapped Python type (string) """ mapped = bytes(type_).decode() if self.project.getProjectLanguage() != "Python2" or \ self.project.getProjectType == "PySide": # 1. check for const mapped = mapped.replace("const ", "") # 2. check fpr * mapped = mapped.replace("*", "") # 3. replace QString and QStringList mapped = mapped.replace("QStringList", "list")\ .replace("QString", "str") # 4. replace double by float mapped = mapped.replace("double", "float") return mapped def __updateSlotsModel(self): """ Private slot to update the slots tree display. """ self.filterEdit.clear() try: dlg = uic.loadUi(self.formFile, package=self.project.getProjectPath()) objects = dlg.findChildren(QWidget) + dlg.findChildren(QAction) signatureList = self.__signatures() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) for obj in objects: name = obj.objectName() if not name or name.startswith("qt_"): # ignore un-named or internal objects continue metaObject = obj.metaObject() className = metaObject.className() itm = QStandardItem("{0} ({1})".format(name, className)) self.slotsModel.appendRow(itm) for index in range(metaObject.methodCount()): metaMethod = metaObject.method(index) if metaMethod.methodType() == QMetaMethod.Signal: if qVersion() >= "5.0.0": itm2 = QStandardItem("on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()).decode())) else: itm2 = QStandardItem("on_{0}_{1}".format( name, metaMethod.signature())) itm.appendRow(itm2) if self.__module is not None: if qVersion() >= "5.0.0": method = "on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()).decode( ).split("(")[0]) else: method = "on_{0}_{1}".format( name, metaMethod.signature().split("(")[0]) method2 = "{0}({1})".format( method, ", ".join([ self.__mapType(t) for t in metaMethod.parameterTypes() ])) if method2 in signatureList or \ method in signatureList: itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) itm2.setCheckState(Qt.Checked) itm2.setForeground(QBrush(Qt.blue)) continue pyqtSignature = \ ", ".join([self.__mapType(t) for t in metaMethod.parameterTypes()]) parameterNames = metaMethod.parameterNames() if parameterNames: for index in range(len(parameterNames)): if not parameterNames[index]: parameterNames[index] = \ QByteArray("p{0:d}".format(index) .encode("utf-8")) methNamesSig = \ ", ".join( [bytes(n).decode() for n in parameterNames]) if methNamesSig: if qVersion() >= "5.0.0": pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0], methNamesSig) else: pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, metaMethod.signature().split("(")[0], methNamesSig) else: if qVersion() >= "5.0.0": pythonSignature = "on_{0}_{1}(self)".format( name, bytes(metaMethod.methodSignature()).decode( ).split("(")[0]) else: pythonSignature = "on_{0}_{1}(self)".format( name, metaMethod.signature().split("(")[0]) itm2.setData(pyqtSignature, pyqtSignatureRole) itm2.setData(pythonSignature, pythonSignatureRole) itm2.setFlags( Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)) itm2.setCheckState(Qt.Unchecked) self.slotsView.sortByColumn(0, Qt.AscendingOrder) except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr("""<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) def __generateCode(self): """ Private slot to generate the code as requested by the user. """ # first decide on extension if self.filenameEdit.text().endswith(".py") or \ self.filenameEdit.text().endswith(".pyw"): self.__generatePythonCode() elif self.filenameEdit.text().endswith(".rb"): pass # second decide on project language elif self.project.getProjectLanguage() in ["Python2", "Python3"]: self.__generatePythonCode() elif self.project.getProjectLanguage() == "Ruby": pass else: # assume Python (our global default) self.__generatePythonCode() def __generatePythonCode(self): """ Private slot to generate Python code as requested by the user. """ # init some variables sourceImpl = [] appendAtIndex = -1 indentStr = " " slotsCode = [] if self.__module is None: # new file try: if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py2.tmpl") elif self.project.getProjectType() == "PyQt5": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py2.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py2.tmpl") else: if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py.tmpl") elif self.project.getProjectType() in [ "PyQt5", "E6Plugin" ]: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py.tmpl") tmplFile = open(tmplName, 'r', encoding="utf-8") template = tmplFile.read() tmplFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the code template file""" """ "{0}".</p><p>Reason: {1}</p>""").format( tmplName, str(why))) return objName = self.__objectName() if objName: template = template\ .replace( "$FORMFILE$", os.path.splitext(os.path.basename(self.formFile))[0])\ .replace("$FORMCLASS$", objName)\ .replace("$CLASSNAME$", self.classNameCombo.currentText())\ .replace("$SUPERCLASS$", self.__className()) sourceImpl = template.splitlines(True) appendAtIndex = -1 # determine indent string for line in sourceImpl: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break else: # extend existing file try: srcFile = open(self.srcFile, 'r', encoding="utf-8") sourceImpl = srcFile.readlines() srcFile.close() if not sourceImpl[-1].endswith("\n"): sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.srcFile, str(why))) return cls = self.__module.classes[self.classNameCombo.currentText()] if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: appendAtIndex = -1 # delete empty lines at end while not sourceImpl[-1].strip(): del sourceImpl[-1] else: appendAtIndex = cls.endlineno - 1 while not sourceImpl[appendAtIndex].strip(): appendAtIndex -= 1 appendAtIndex += 1 # determine indent string for line in sourceImpl[cls.lineno:cls.endlineno + 1]: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break # do the coding stuff if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' elif self.project.getProjectType() == "PyQt5": pyqtSignatureFormat = '@pyqtSlot({0})' else: pyqtSignatureFormat = '@pyqtSignature("{0}")' else: if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' else: pyqtSignatureFormat = '@pyqtSlot({0})' for row in range(self.slotsModel.rowCount()): topItem = self.slotsModel.item(row) for childRow in range(topItem.rowCount()): child = topItem.child(childRow) if child.checkState() and \ child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable): slotsCode.append('{0}\n'.format(indentStr)) slotsCode.append('{0}{1}\n'.format( indentStr, pyqtSignatureFormat.format( child.data(pyqtSignatureRole)))) slotsCode.append('{0}def {1}:\n'.format( indentStr, child.data(pythonSignatureRole))) slotsCode.append('{0}"""\n'.format(indentStr * 2)) slotsCode.append( '{0}Slot documentation goes here.\n'.format(indentStr * 2)) slotsCode.append('{0}"""\n'.format(indentStr * 2)) slotsCode.append('{0}# {1}: not implemented yet\n'.format( indentStr * 2, "TODO")) slotsCode.append('{0}raise NotImplementedError\n'.format( indentStr * 2)) if appendAtIndex == -1: sourceImpl.extend(slotsCode) else: sourceImpl[appendAtIndex:appendAtIndex] = slotsCode # write the new code try: if self.project.useSystemEol(): newline = None else: newline = self.project.getEolString() srcFile = open(self.filenameEdit.text(), 'w', encoding="utf-8", newline=newline) srcFile.write("".join(sourceImpl)) srcFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not write the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.filenameEdit.text(), str(why))) return self.project.appendFile(self.filenameEdit.text()) @pyqtSlot(int) def on_classNameCombo_activated(self, index): """ Private slot to handle the activated signal of the classname combo. @param index index of the activated item (integer) """ if (self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator): self.okButton.setEnabled(False) self.filterEdit.clear() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) else: self.okButton.setEnabled(True) self.__updateSlotsModel() def on_filterEdit_textChanged(self, text): """ Private slot called, when thext of the filter edit has changed. @param text changed text (string) """ re = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(re) @pyqtSlot() def on_newButton_clicked(self): """ Private slot called to enter the data for a new dialog class. """ path, file = os.path.split(self.srcFile) objName = self.__objectName() if objName: dlg = NewDialogClassDialog(objName, file, path, self) if dlg.exec_() == QDialog.Accepted: className, fileName = dlg.getData() self.classNameCombo.clear() self.classNameCombo.addItem(className) self.srcFile = fileName self.filenameEdit.setText(self.srcFile) self.__module = None self.okButton.setEnabled(self.classNameCombo.count() > 0) def on_buttonBox_clicked(self, button): """ Private slot to handle the buttonBox clicked signal. @param button reference to the button that was clicked (QAbstractButton) """ if button == self.okButton: self.__generateCode() self.accept()