ProjectPyramid/PyramidRoutesDialog.py

Wed, 21 Sep 2022 16:24:54 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 21 Sep 2022 16:24:54 +0200
branch
eric7
changeset 159
d4e7f5a389e6
parent 156
62170c2682a3
child 160
41b23683d5a1
permissions
-rw-r--r--

Reformatted source code with 'Black'.

# -*- coding: utf-8 -*-

# Copyright (c) 2012 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog showing the available routes.
"""

import os

from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QTimer, QCoreApplication
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QLineEdit, QTreeWidgetItem

from EricWidgets import EricMessageBox

from .Ui_PyramidRoutesDialog import Ui_PyramidRoutesDialog

import Preferences
from Globals import strToQByteArray


class PyramidRoutesDialog(QDialog, Ui_PyramidRoutesDialog):
    """
    Class implementing a dialog showing the available routes.
    """

    def __init__(self, project, parent=None):
        """
        Constructor

        @param project reference to the project object
        @type Project
        @param parent reference to the parent widget
        @type QWidget
        """
        super().__init__(parent)
        self.setupUi(self)

        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)

        self.__project = project
        self.proc = None
        self.buffer = ""

        self.show()
        QCoreApplication.processEvents()

    def finish(self):
        """
        Public slot called when the process finished or the user pressed the
        button.
        """
        if (
            self.proc is not None
            and self.proc.state() != QProcess.ProcessState.NotRunning
        ):
            self.proc.terminate()
            QTimer.singleShot(2000, self.proc.kill)
            self.proc.waitForFinished(3000)

        self.inputGroup.setEnabled(False)
        self.inputGroup.hide()

        self.proc = None

        self.__processBuffer()

        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
            Qt.FocusReason.OtherFocusReason
        )

    def on_buttonBox_clicked(self, button):
        """
        Private slot called by a button of the button box clicked.

        @param button button that was clicked (QAbstractButton)
        """
        if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
            self.close()
        elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
            self.finish()

    def __procFinished(self, exitCode, exitStatus):
        """
        Private slot connected to the finished signal.

        @param exitCode exit code of the process
        @type int
        @param exitStatus exit status of the process
        @type QProcess.ExitStatus
        """
        self.normal = exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0
        self.finish()

    def __processBuffer(self):
        """
        Private slot to process the output buffer of the proutes command.
        """
        self.routes.clear()

        if not self.buffer:
            QTreeWidgetItem(self.routes, [self.tr("No routes found.")])
            self.routes.setHeaderHidden(True)
        else:
            lines = self.buffer.splitlines()
            row = 0
            headers = []
            while row < len(lines):
                if lines[row].strip().startswith("---"):
                    headerLine = lines[row - 1]
                    headers = headerLine.split()
                    break
                row += 1
            if headers:
                self.routes.setHeaderLabels(headers)
                self.routes.setHeaderHidden(False)
                row += 1
                splitCount = len(headers) - 1
                while row < len(lines):
                    line = lines[row].strip()
                    parts = line.split(None, splitCount)
                    QTreeWidgetItem(self.routes, parts)
                    row += 1
                for column in range(len(headers)):
                    self.routes.resizeColumnToContents(column)

    def start(self, projectPath):
        """
        Public slot used to start the process.

        @param projectPath path to the Pyramid project
        @type str
        @return flag indicating a successful start of the process
        @rtype bool
        """
        QTreeWidgetItem(self.routes, [self.tr("Getting routes...")])
        self.routes.setHeaderHidden(True)

        self.errorGroup.hide()
        self.normal = False
        self.intercept = False

        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus(
            Qt.FocusReason.OtherFocusReason
        )

        self.proc = QProcess()

        self.proc.finished.connect(self.__procFinished)
        self.proc.readyReadStandardOutput.connect(self.__readStdout)
        self.proc.readyReadStandardError.connect(self.__readStderr)

        cmd = self.__project.getPyramidCommand(
            "proutes", virtualEnv=self.__project.getProjectVirtualEnvironment()
        )
        args = []
        args.append("development.ini")

        if projectPath:
            self.proc.setWorkingDirectory(projectPath)
        self.proc.start(cmd, args)
        procStarted = self.proc.waitForStarted()
        if not procStarted:
            self.buttonBox.setFocus()
            self.inputGroup.setEnabled(False)
            EricMessageBox.critical(
                self,
                self.tr("Process Generation Error"),
                self.tr(
                    "The process {0} could not be started. "
                    "Ensure, that it is in the search path."
                ).format(cmd),
            )
        else:
            self.inputGroup.setEnabled(True)
            self.inputGroup.show()
        return procStarted

    def __readStdout(self):
        """
        Private slot to handle the readyReadStandardOutput signal.

        It reads the output of the process and appends it to a buffer for
        delayed processing.
        """
        if self.proc is not None:
            out = str(
                self.proc.readAllStandardOutput(),
                Preferences.getSystem("IOEncoding"),
                "replace",
            )
            self.buffer += out

    def __readStderr(self):
        """
        Private slot to handle the readyReadStandardError signal.

        It reads the error output of the process and inserts it into the
        error pane.
        """
        if self.proc is not None:
            err = str(
                self.proc.readAllStandardError(),
                Preferences.getSystem("IOEncoding"),
                "replace",
            )
            self.errorGroup.show()
            self.errors.insertPlainText(err)
            self.errors.ensureCursorVisible()

            QCoreApplication.processEvents()

    def on_passwordCheckBox_toggled(self, isOn):
        """
        Private slot to handle the password checkbox toggled.

        @param isOn flag indicating the status of the check box
        @type bool
        """
        if isOn:
            self.input.setEchoMode(QLineEdit.EchoMode.Password)
        else:
            self.input.setEchoMode(QLineEdit.EchoMode.Normal)

    @pyqtSlot()
    def on_sendButton_clicked(self):
        """
        Private slot to send the input to the subversion process.
        """
        inputTxt = self.input.text()
        inputTxt += os.linesep

        if self.passwordCheckBox.isChecked():
            self.errors.insertPlainText(os.linesep)
            self.errors.ensureCursorVisible()

        self.proc.write(strToQByteArray(inputTxt))

        self.passwordCheckBox.setChecked(False)
        self.input.clear()

    def on_input_returnPressed(self):
        """
        Private slot to handle the press of the return key in the input field.
        """
        self.intercept = True
        self.on_sendButton_clicked()

    def keyPressEvent(self, evt):
        """
        Protected slot to handle a key press event.

        @param evt the key press event
        @type QKeyEvent
        """
        if self.intercept:
            self.intercept = False
            evt.accept()
            return
        super().keyPressEvent(evt)

eric ide

mercurial