Beispiel #1
0
    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)
Beispiel #2
0
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)
Beispiel #3
0
 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)) )
Beispiel #4
0
    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)
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #8
0
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)
Beispiel #9
0
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])
Beispiel #13
0
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)
Beispiel #14
0
 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)
Beispiel #15
0
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_())
Beispiel #16
0
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)
Beispiel #17
0
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)
Beispiel #18
0
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)
Beispiel #19
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")
Beispiel #20
0
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()
Beispiel #22
0
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
Beispiel #23
0
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")
Beispiel #24
0
 def sorted(self):
     proxy_model = QSortFilterProxyModel(self)
     proxy_model.setSourceModel(self)
     proxy_model.setDynamicSortFilter(True)
     proxy_model.sort(0)
     return proxy_model
Beispiel #25
0
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:
Beispiel #27
0
 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()
Beispiel #31
0
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()