Warning, file /sdk/cervisia/progressdialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  Copyright (c) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
0003  *  Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with this program; if not, write to the Free Software
0017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0018  */
0019 
0020 #include "progressdialog.h"
0021 
0022 #include <QApplication>
0023 #include <QDialogButtonBox>
0024 #include <QEventLoop>
0025 #include <QHBoxLayout>
0026 #include <QLabel>
0027 #include <QPlainTextEdit>
0028 #include <QProgressBar>
0029 #include <QString>
0030 #include <QStringList>
0031 #include <QTimer>
0032 #include <QVBoxLayout>
0033 
0034 #include "cervisiasettings.h"
0035 #include "debug.h"
0036 #include <cvsjobinterface.h>
0037 
0038 //---------------------------------------------------------------------
0039 
0040 struct ProgressDialog::Private {
0041     bool isCancelled;
0042     bool isShown;
0043     bool hasError;
0044     bool isDiff;
0045 
0046     OrgKdeCervisia5CvsserviceCvsjobInterface *cvsJob;
0047     QString jobPath;
0048     QString buffer;
0049     QString errorId1, errorId2;
0050     QStringList output;
0051     QEventLoop eventLoop;
0052 
0053     QTimer *timer;
0054     QProgressBar *busy;
0055     QPlainTextEdit *resultbox;
0056 };
0057 
0058 //---------------------------------------------------------------------
0059 
0060 ProgressDialog::ProgressDialog(QWidget *parent,
0061                                const QString &heading,
0062                                const QString &cvsServiceNameService,
0063                                const QDBusReply<QDBusObjectPath> &jobPath,
0064                                const QString &errorIndicator,
0065                                const QString &caption)
0066     : QDialog(parent)
0067     , d(new Private)
0068 {
0069     setWindowTitle(caption);
0070     setModal(true);
0071 
0072     setupGui(heading);
0073 
0074     d->isCancelled = false;
0075     d->isShown = false;
0076     d->hasError = false;
0077     d->isDiff = heading == QLatin1String("Diff"); // cvs returns error status when there is a difference
0078 
0079     QDBusObjectPath path = jobPath;
0080     d->jobPath = path.path();
0081     d->cvsJob = new OrgKdeCervisia5CvsserviceCvsjobInterface(cvsServiceNameService, path.path(), QDBusConnection::sessionBus(), this);
0082 
0083     qCDebug(log_cervisia) << "cvsServiceNameService:" << cvsServiceNameService << "CvsjobInterface" << path.path() << "valid:" << d->cvsJob->isValid();
0084 
0085     d->errorId1 = "cvs " + errorIndicator + ':';
0086     d->errorId2 = "cvs [" + errorIndicator + " aborted]:";
0087 }
0088 
0089 //---------------------------------------------------------------------
0090 
0091 ProgressDialog::~ProgressDialog()
0092 {
0093     delete d->cvsJob;
0094     delete d;
0095 }
0096 
0097 //---------------------------------------------------------------------
0098 
0099 void ProgressDialog::setupGui(const QString &heading)
0100 {
0101     auto mainLayout = new QVBoxLayout(this);
0102 
0103     auto textLabel = new QLabel(heading);
0104     mainLayout->addWidget(textLabel);
0105 
0106     d->resultbox = new QPlainTextEdit;
0107     d->resultbox->setReadOnly(true);
0108     QFontMetrics fm(d->resultbox->fontMetrics());
0109     d->resultbox->setMinimumSize(fm.width("0") * 70, fm.lineSpacing() * 8);
0110     mainLayout->addWidget(d->resultbox);
0111 
0112     auto hbox = new QHBoxLayout;
0113 
0114     d->busy = new QProgressBar;
0115     d->busy->setMinimum(0);
0116     d->busy->setMaximum(0); // min == max  =>  busy indicator
0117     hbox->addWidget(d->busy);
0118     d->busy->hide();
0119 
0120     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel);
0121     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0122     hbox->addWidget(buttonBox);
0123 
0124     mainLayout->addLayout(hbox);
0125 }
0126 
0127 //---------------------------------------------------------------------
0128 
0129 bool ProgressDialog::execute()
0130 {
0131     // get command line and display it
0132     QString cmdLine = d->cvsJob->cvsCommand();
0133     d->resultbox->insertPlainText(cmdLine);
0134     qCDebug(log_cervisia) << "cmdLine:" << cmdLine;
0135 
0136     QDBusConnection::sessionBus().connect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "jobExited", this, SLOT(slotJobExited(bool, int)));
0137 
0138     QDBusConnection::sessionBus()
0139         .connect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "receivedStdout", this, SLOT(slotReceivedOutputNonGui(QString)));
0140 
0141     QDBusConnection::sessionBus()
0142         .connect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "receivedStderr", this, SLOT(slotReceivedOutputNonGui(QString)));
0143 
0144     // we wait for 4 seconds (or the timeout set by the user) before we
0145     // force the dialog to show up
0146     d->timer = new QTimer(this);
0147     connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimeoutOccurred()));
0148     d->timer->setSingleShot(true);
0149     d->timer->start(CervisiaSettings::timeout());
0150 
0151     bool started = d->cvsJob->execute();
0152     if (!started)
0153         return false;
0154 
0155     QApplication::setOverrideCursor(Qt::WaitCursor);
0156 
0157     d->eventLoop.exec();
0158 
0159     if (QApplication::overrideCursor())
0160         QApplication::restoreOverrideCursor();
0161 
0162     return !d->isCancelled;
0163 }
0164 
0165 //---------------------------------------------------------------------
0166 
0167 bool ProgressDialog::getLine(QString &line)
0168 {
0169     if (d->output.isEmpty())
0170         return false;
0171 
0172     line = d->output.first();
0173     d->output.removeFirst();
0174 
0175     return true;
0176 }
0177 
0178 //---------------------------------------------------------------------
0179 
0180 QStringList ProgressDialog::getOutput() const
0181 {
0182     return d->output;
0183 }
0184 
0185 //---------------------------------------------------------------------
0186 
0187 void ProgressDialog::slotReceivedOutputNonGui(QString buffer)
0188 {
0189     qCDebug(log_cervisia) << buffer;
0190 
0191     d->buffer += buffer;
0192 
0193     processOutput();
0194     if (d->hasError) {
0195         stopNonGuiPart();
0196         startGuiPart();
0197     }
0198 }
0199 
0200 //---------------------------------------------------------------------
0201 
0202 void ProgressDialog::slotReceivedOutput(QString buffer)
0203 {
0204     qCDebug(log_cervisia) << buffer;
0205     d->buffer += buffer;
0206     processOutput();
0207 }
0208 
0209 //---------------------------------------------------------------------
0210 
0211 void ProgressDialog::slotJobExited(bool normalExit, int status)
0212 {
0213     Q_UNUSED(normalExit)
0214 
0215     if (!d->isShown)
0216         stopNonGuiPart();
0217 
0218     d->busy->hide();
0219 
0220     if (!d->buffer.isEmpty()) {
0221         d->buffer += '\n';
0222         processOutput();
0223     }
0224 
0225     if ((status != 0) && !d->isDiff) // cvs command exited with error -> show error text
0226     {
0227         QString line;
0228         while (getLine(line)) {
0229             d->resultbox->insertPlainText(QLatin1String("\n"));
0230             d->resultbox->insertPlainText(line);
0231         }
0232         startGuiPart();
0233         d->busy->hide();
0234         return;
0235     }
0236 
0237     // Close the dialog automatically if there are no
0238     // error messages or the process has been aborted
0239     // 'by hand' (e.g.  by clicking the cancel button)
0240     if (!d->hasError || d->isCancelled)
0241         d->eventLoop.exit();
0242 }
0243 
0244 //---------------------------------------------------------------------
0245 
0246 void ProgressDialog::reject()
0247 {
0248     d->isCancelled = true;
0249 
0250     bool isRunning = d->cvsJob->isRunning();
0251     if (isRunning)
0252         d->cvsJob->cancel();
0253     else
0254         d->eventLoop.exit();
0255 
0256     QDialog::reject();
0257 }
0258 
0259 //---------------------------------------------------------------------
0260 
0261 void ProgressDialog::slotTimeoutOccurred()
0262 {
0263     stopNonGuiPart();
0264     startGuiPart();
0265 }
0266 
0267 //---------------------------------------------------------------------
0268 
0269 void ProgressDialog::stopNonGuiPart()
0270 {
0271     d->timer->stop();
0272 
0273     QDBusConnection::sessionBus()
0274         .disconnect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "receivedStdout", this, SLOT(slotReceivedOutputNonGui(QString)));
0275 
0276     QDBusConnection::sessionBus()
0277         .disconnect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "receivedStderr", this, SLOT(slotReceivedOutputNonGui(QString)));
0278 }
0279 
0280 //---------------------------------------------------------------------
0281 
0282 void ProgressDialog::startGuiPart()
0283 {
0284     QDBusConnection::sessionBus()
0285         .connect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "receivedStdout", this, SLOT(slotReceivedOutput(QString)));
0286 
0287     QDBusConnection::sessionBus()
0288         .connect(QString(), d->jobPath, "org.kde.cervisia5.cvsservice.cvsjob", "receivedStderr", this, SLOT(slotReceivedOutput(QString)));
0289 
0290     show();
0291     d->isShown = true;
0292 
0293     d->busy->show();
0294     QApplication::restoreOverrideCursor();
0295 }
0296 
0297 //---------------------------------------------------------------------
0298 
0299 void ProgressDialog::processOutput()
0300 {
0301     int pos;
0302     while ((pos = d->buffer.indexOf('\n')) != -1) {
0303         QString item = d->buffer.left(pos);
0304         if (item.startsWith(d->errorId1) || item.startsWith(d->errorId2) || item.startsWith(QLatin1String("cvs [server aborted]:"))) {
0305             d->hasError = true;
0306             d->resultbox->insertPlainText(QLatin1String("\n"));
0307             d->resultbox->insertPlainText(item);
0308         } else if (item.startsWith(QLatin1String("cvs server:"))) {
0309             d->resultbox->insertPlainText(QLatin1String("\n"));
0310             d->resultbox->insertPlainText(item);
0311         } else
0312             d->output.append(item);
0313 
0314         // remove item from buffer
0315         d->buffer.remove(0, pos + 1);
0316     }
0317 }
0318 
0319 //---------------------------------------------------------------------