summaryrefslogtreecommitdiffstats
path: root/lib/widgets/processwidget.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch)
treeacaf47eb0fa12142d3896416a69e74cbf5a72242 /lib/widgets/processwidget.cpp
downloadtdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz
tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/widgets/processwidget.cpp')
-rw-r--r--lib/widgets/processwidget.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/lib/widgets/processwidget.cpp b/lib/widgets/processwidget.cpp
new file mode 100644
index 00000000..54dd1751
--- /dev/null
+++ b/lib/widgets/processwidget.cpp
@@ -0,0 +1,283 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999-2001 Bernd Gehrmann <bernd@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "processwidget.h"
+#include "processlinemaker.h"
+
+#include <kdeversion.h>
+#include <qdir.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <qpainter.h>
+#include <qapplication.h>
+
+
+ProcessListBoxItem::ProcessListBoxItem(const QString &s, Type type)
+ : QListBoxText(s), t(type)
+{
+ QString clean = s;
+ clean.replace( QChar('\t'), QString(" ") );
+ clean.replace( QChar('\n'), QString() );
+ clean.replace( QChar('\r'), QString() );
+ setText( clean );
+
+ setCustomHighlighting(true);
+}
+
+
+bool ProcessListBoxItem::isCustomItem()
+{
+ return false;
+}
+
+static inline unsigned char normalize(int a)
+{
+ return (a < 0 ? 0 : a > 255 ? 255 : a);
+}
+
+static inline double blend1(double a, double b, double k)
+{
+ return a + (b - a) * k;
+}
+
+QColor ProcessListBoxItem::blend(const QColor &c1, const QColor &c2, double k) const
+{
+ if (k < 0.0) return c1;
+ if (k > 1.0) return c2;
+
+ int r = normalize((int)blend1((double)c1.red(), (double)c2.red(), k));
+ int g = normalize((int)blend1((double)c1.green(), (double)c2.green(), k));
+ int b = normalize((int)blend1((double)c1.blue(), (double)c2.blue(), k));
+
+ return QColor(qRgb(r, g, b));
+}
+
+void ProcessListBoxItem::paint(QPainter *p)
+{
+ QColor dim, warn, err, back;
+ if (listBox()) {
+ const QColorGroup& group = listBox()->palette().active();
+ if (isSelected()) {
+ back = group.button();
+ warn = group.buttonText();
+ }
+ else
+ {
+ back = group.base();
+ warn = group.text();
+ }
+ err = group.linkVisited();
+ dim = blend(warn, back);
+ }
+ else
+ {
+ warn = Qt::black;
+ dim = Qt::darkBlue;
+ err = Qt::darkRed;
+ if (isSelected())
+ back = Qt::lightGray;
+ else
+ back = Qt::white;
+ }
+ p->fillRect(p->window(), QBrush(back));
+ p->setPen((t==Error)? err :
+ (t==Diagnostic)? warn : dim);
+ QListBoxText::paint(p);
+}
+
+
+ProcessWidget::ProcessWidget(QWidget *parent, const char *name)
+ : KListBox(parent, name)
+{
+ setFocusPolicy(QWidget::NoFocus);
+
+ // Don't override the palette, as that can mess up styles. Instead, draw
+ // the background ourselves (see ProcessListBoxItem::paint).
+
+
+ childproc = new KProcess();
+ childproc->setUseShell(true);
+
+ procLineMaker = new ProcessLineMaker( childproc );
+
+ connect( procLineMaker, SIGNAL(receivedStdoutLine(const QCString&)),
+ this, SLOT(insertStdoutLine(const QCString&) ));
+ connect( procLineMaker, SIGNAL(receivedStderrLine(const QCString&)),
+ this, SLOT(insertStderrLine(const QCString&) ));
+ connect( procLineMaker, SIGNAL(receivedPartialStdoutLine(const QCString&)),
+ this, SLOT(addPartialStdoutLine(const QCString&) ));
+ connect( procLineMaker, SIGNAL(receivedPartialStderrLine(const QCString&)),
+ this, SLOT(addPartialStderrLine(const QCString&) ));
+
+ connect(childproc, SIGNAL(processExited(KProcess*)),
+ this, SLOT(slotProcessExited(KProcess*) )) ;
+}
+
+
+ProcessWidget::~ProcessWidget()
+{
+ delete childproc;
+ delete procLineMaker;
+}
+
+
+void ProcessWidget::startJob(const QString &dir, const QString &command)
+{
+ procLineMaker->clearBuffers();
+ procLineMaker->blockSignals( false );
+
+ clear();
+ insertItem(new ProcessListBoxItem(command, ProcessListBoxItem::Diagnostic));
+ childproc->clearArguments();
+ if (!dir.isNull()) {
+ childproc->setWorkingDirectory( dir );
+ }
+
+ *childproc << command;
+ childproc->start(KProcess::OwnGroup, KProcess::AllOutput);
+}
+
+
+void ProcessWidget::killJob( int signo )
+{
+ procLineMaker->blockSignals( true );
+
+ childproc->kill( signo );
+}
+
+
+bool ProcessWidget::isRunning()
+{
+ return childproc->isRunning();
+}
+
+
+void ProcessWidget::slotProcessExited(KProcess *)
+{
+ procLineMaker->flush();
+ if( !stdoutbuf.isEmpty() )
+ insertStdoutLine("");
+ if( !stderrbuf.isEmpty() )
+ insertStderrLine("");
+ childFinished(childproc->normalExit(), childproc->exitStatus());
+ maybeScrollToBottom();
+ emit processExited(childproc);
+}
+
+
+void ProcessWidget::insertStdoutLine(const QCString &line)
+{
+ if( !stdoutbuf.isEmpty() )
+ {
+ stdoutbuf += line;
+ insertItem( new ProcessListBoxItem( QString::fromLocal8Bit(stdoutbuf),
+ ProcessListBoxItem::Normal ),
+ lastRowStdout+1 );
+ stdoutbuf.truncate( 0 );
+ }else
+ {
+ insertItem( new ProcessListBoxItem( QString::fromLocal8Bit( line ),
+ ProcessListBoxItem::Normal) );
+ }
+ lastRowStdout = count() - 1;
+ maybeScrollToBottom();
+}
+
+
+void ProcessWidget::insertStderrLine(const QCString &line)
+{
+ if( !stderrbuf.isEmpty() )
+ {
+ stderrbuf += line;
+ insertItem( new ProcessListBoxItem( QString::fromLocal8Bit( stderrbuf ),
+ ProcessListBoxItem::Error ),
+ lastRowStderr+1 );
+ stderrbuf.truncate( 0 );
+ } else
+ {
+ insertItem( new ProcessListBoxItem( QString::fromLocal8Bit( line ),
+ ProcessListBoxItem::Error) );
+ }
+ lastRowStderr = count() - 1;
+ maybeScrollToBottom();
+}
+
+
+void ProcessWidget::childFinished(bool normal, int status)
+{
+ QString s;
+ ProcessListBoxItem::Type t;
+
+ if (normal) {
+ if (status) {
+ s = i18n("*** Exited with status: %1 ***").arg(status);
+ t = ProcessListBoxItem::Error;
+ } else {
+ s = i18n("*** Exited normally ***");
+ t = ProcessListBoxItem::Diagnostic;
+ }
+ } else {
+ if ( childproc->signalled() && childproc->exitSignal() == SIGSEGV )
+ {
+ s = i18n("*** Process aborted. Segmentation fault ***");
+ }
+ else
+ {
+ s = i18n("*** Process aborted ***");
+ }
+ t = ProcessListBoxItem::Error;
+ }
+
+ insertItem(new ProcessListBoxItem(s, t));
+}
+
+
+QSize ProcessWidget::minimumSizeHint() const
+{
+ // I'm not sure about this, but when I don't use override minimumSizeHint(),
+ // the initial size in clearly too small
+
+ return QSize( QListBox::sizeHint().width(),
+ (fontMetrics().lineSpacing()+2)*4 );
+}
+
+/** Should be called right after an insertItem(),
+ will automatic scroll the listbox if it is already at the bottom
+ to prevent automatic scrolling when the user has scrolled up
+*/
+void ProcessWidget::maybeScrollToBottom()
+{
+ if ( verticalScrollBar()->value() == verticalScrollBar()->maxValue() )
+ {
+ setBottomItem( count() -1 );
+ }
+}
+
+void ProcessWidget::addPartialStderrLine(const QCString& linepart)
+{
+ stderrbuf += linepart;
+}
+
+void ProcessWidget::addPartialStdoutLine(const QCString& linepart)
+{
+ stdoutbuf += linepart;
+}
+
+#include "processwidget.moc"