--- a/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py Tue Feb 24 18:31:14 2015 +0100 +++ b/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py Tue Feb 24 18:55:07 2015 +0100 @@ -13,17 +13,16 @@ except NameError: pass -import os - -from PyQt5.QtCore import pyqtSlot, QProcess, QTimer, QFileInfo, Qt +from PyQt5.QtCore import pyqtSlot, QFileInfo, Qt from PyQt5.QtGui import QTextCursor, QCursor -from PyQt5.QtWidgets import QWidget, QDialogButtonBox, QLineEdit, QApplication +from PyQt5.QtWidgets import QWidget, QDialogButtonBox, QApplication from E5Gui import E5MessageBox, E5FileDialog from E5Gui.E5Application import e5App from .Ui_HgDiffDialog import Ui_HgDiffDialog from .HgDiffHighlighter import HgDiffHighlighter +from .HgDiffGenerator import HgDiffGenerator import Utilities import Preferences @@ -54,19 +53,14 @@ self.searchWidget.attachTextEdit(self.contents) - self.process = QProcess() - self.vcs = vcs - self.__hgClient = self.vcs.getClient() - font = Preferences.getEditorOtherFonts("MonospacedFont") self.contents.setFontFamily(font.family()) self.contents.setFontPointSize(font.pointSize()) self.highlighter = HgDiffHighlighter(self.contents.document()) - self.process.finished.connect(self.__procFinished) - self.process.readyReadStandardOutput.connect(self.__readStdout) - self.process.readyReadStandardError.connect(self.__readStderr) + self.__diffGenerator = HgDiffGenerator(vcs, self) + self.__diffGenerator.finished.connect(self.__generatorFinished) def closeEvent(self, e): """ @@ -74,30 +68,9 @@ @param e close event (QCloseEvent) """ - if self.__hgClient: - if self.__hgClient.isExecuting(): - self.__hgClient.cancel() - else: - if self.process is not None and \ - self.process.state() != QProcess.NotRunning: - self.process.terminate() - QTimer.singleShot(2000, self.process.kill) - self.process.waitForFinished(3000) - + self.__diffGenerator.stopProcess() e.accept() - def __getVersionArg(self, version): - """ - Private method to get a hg revision argument for the given revision. - - @param version revision (integer or string) - @return version argument (string) - """ - if version == "WORKING": - return None - else: - return str(version) - def start(self, fn, versions=None, bundle=None, qdiff=False, refreshable=False): """ @@ -113,126 +86,50 @@ self.refreshButton.setVisible(refreshable) self.errorGroup.hide() - self.inputGroup.show() - self.inputGroup.setEnabled(True) - self.intercept = False self.filename = fn self.contents.clear() - self.paras = 0 - self.filesCombo.clear() if qdiff: - args = self.vcs.initCommand("qdiff") self.setWindowTitle(self.tr("Patch Contents")) - else: - args = self.vcs.initCommand("diff") - - if self.vcs.hasSubrepositories(): - args.append("--subrepos") - - if bundle: - args.append('--repository') - args.append(bundle) - elif self.vcs.bundleFile and os.path.exists(self.vcs.bundleFile): - args.append('--repository') - args.append(self.vcs.bundleFile) - - if versions is not None: - self.raise_() - self.activateWindow() - - rev1 = self.__getVersionArg(versions[0]) - rev2 = None - if len(versions) == 2: - rev2 = self.__getVersionArg(versions[1]) - - if rev1 is not None or rev2 is not None: - args.append('-r') - if rev1 is not None and rev2 is not None: - args.append('{0}:{1}'.format(rev1, rev2)) - elif rev2 is None: - args.append(rev1) - elif rev1 is None: - args.append(':{0}'.format(rev2)) - if isinstance(fn, list): - dname, fnames = self.vcs.splitPathList(fn) - self.vcs.addArguments(args, fn) - else: - dname, fname = self.vcs.splitPath(fn) - args.append(fn) - - self.__oldFile = "" - self.__oldFileLine = -1 - self.__fileSeparators = [] + self.raise_() + self.activateWindow() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) - if self.__hgClient: - self.inputGroup.setEnabled(False) - self.inputGroup.hide() - - out, err = self.__hgClient.runcommand(args) - - if err: - self.__showError(err) - if out: - for line in out.splitlines(True): - self.__processOutputLine(line) - if self.__hgClient.wasCanceled(): - break - - self.__finish() - else: - # find the root of the repo - repodir = dname - while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)): - repodir = os.path.dirname(repodir) - if os.path.splitdrive(repodir)[1] == os.sep: - return - - self.process.kill() - - self.process.setWorkingDirectory(repodir) - - self.process.start('hg', args) - procStarted = self.process.waitForStarted(5000) - if not procStarted: - QApplication.restoreOverrideCursor() - self.inputGroup.setEnabled(False) - self.inputGroup.hide() - E5MessageBox.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('hg')) + procStarted = self.__diffGenerator.start( + fn, versions=versions, bundle=bundle, qdiff=qdiff) + if not procStarted: + E5MessageBox.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('hg')) - def __procFinished(self, exitCode, exitStatus): + def __generatorFinished(self): """ Private slot connected to the finished signal. - - @param exitCode exit code of the process (integer) - @param exitStatus exit status of the process (QProcess.ExitStatus) - """ - self.__finish() - - def __finish(self): - """ - Private slot called when the process finished or the user pressed - the button. """ QApplication.restoreOverrideCursor() - self.inputGroup.setEnabled(False) - self.inputGroup.hide() self.refreshButton.setEnabled(True) - if self.paras == 0: - self.contents.setPlainText(self.tr('There is no difference.')) + diff, errors, fileSeparators = self.__diffGenerator.getResult() - self.buttonBox.button(QDialogButtonBox.Save).setEnabled(self.paras > 0) + if diff: + self.contents.setPlainText("".join(diff)) + else: + self.contents.setPlainText( + self.tr('There is no difference.')) + + if errors: + self.errorGroup.show() + self.errors.setPlainText("".join(errors)) + self.errors.ensureCursorVisible() + + self.buttonBox.button(QDialogButtonBox.Save).setEnabled(bool(diff)) self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) self.buttonBox.button(QDialogButtonBox.Close).setFocus( @@ -245,7 +142,7 @@ self.filesCombo.addItem(self.tr("<Start>"), 0) self.filesCombo.addItem(self.tr("<End>"), -1) - for oldFile, newFile, pos in sorted(self.__fileSeparators): + for oldFile, newFile, pos in sorted(fileSeparators): if not oldFile: self.filesCombo.addItem(newFile, pos) elif oldFile != newFile: @@ -254,99 +151,6 @@ else: self.filesCombo.addItem(oldFile, pos) - def __appendText(self, txt): - """ - Private method to append text to the end of the contents pane. - - @param txt text to insert (string) - """ - tc = self.contents.textCursor() - tc.movePosition(QTextCursor.End) - self.contents.setTextCursor(tc) - self.contents.insertPlainText(txt) - - def __extractFileName(self, line): - """ - Private method to extract the file name out of a file separator line. - - @param line line to be processed (string) - @return extracted file name (string) - """ - f = line.split(None, 1)[1] - f = f.rsplit(None, 6)[0] - if f == "/dev/null": - f = "__NULL__" - else: - f = f.split("/", 1)[1] - return f - - def __processFileLine(self, line): - """ - Private slot to process a line giving the old/new file. - - @param line line to be processed (string) - """ - if line.startswith('---'): - self.__oldFileLine = self.paras - self.__oldFile = self.__extractFileName(line) - else: - newFile = self.__extractFileName(line) - if self.__oldFile == "__NULL__": - self.__fileSeparators.append( - (newFile, newFile, self.__oldFileLine)) - else: - self.__fileSeparators.append( - (self.__oldFile, newFile, self.__oldFileLine)) - - def __processOutputLine(self, line): - """ - Private method to process the lines of output. - - @param line output line to be processed (string) - """ - if line.startswith("--- ") or \ - line.startswith("+++ "): - self.__processFileLine(line) - - self.__appendText(line) - self.paras += 1 - - def __readStdout(self): - """ - Private slot to handle the readyReadStandardOutput signal. - - It reads the output of the process, formats it and inserts it into - the contents pane. - """ - self.process.setReadChannel(QProcess.StandardOutput) - - while self.process.canReadLine(): - line = str(self.process.readLine(), self.vcs.getEncoding(), - 'replace') - self.__processOutputLine(line) - - 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.process is not None: - s = str(self.process.readAllStandardError(), - self.vcs.getEncoding(), 'replace') - self.__showError(s) - - def __showError(self, out): - """ - Private slot to show some error. - - @param out error to be shown (string) - """ - self.errorGroup.show() - self.errors.insertPlainText(out) - self.errors.ensureCursorVisible() - def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. @@ -463,53 +267,3 @@ self.refreshButton.setEnabled(False) self.start(self.filename, refreshable=True) - - def on_passwordCheckBox_toggled(self, isOn): - """ - Private slot to handle the password checkbox toggled. - - @param isOn flag indicating the status of the check box (boolean) - """ - if isOn: - self.input.setEchoMode(QLineEdit.Password) - else: - self.input.setEchoMode(QLineEdit.Normal) - - @pyqtSlot() - def on_sendButton_clicked(self): - """ - Private slot to send the input to the subversion process. - """ - input = self.input.text() - input += os.linesep - - if self.passwordCheckBox.isChecked(): - self.errors.insertPlainText(os.linesep) - self.errors.ensureCursorVisible() - else: - self.errors.insertPlainText(input) - self.errors.ensureCursorVisible() - - self.process.write(input) - - 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 (QKeyEvent) - """ - if self.intercept: - self.intercept = False - evt.accept() - return - super(HgDiffDialog, self).keyPressEvent(evt)