1//
2// configview.cpp
3//
4// Description: View for configuring the set of targets to be used with the debugger
5//
6//
7// Copyright (c) 2010 Kåre Särs <kare.sars@iki.fi>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Library General Public
11// License version 2 as published by the Free Software Foundation.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public License
19// along with this library; see the file COPYING.LIB. If not, write to
20// the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21// Boston, MA 02110-1301, USA.
22
23#include "ioview.h"
24#include "ioview.moc"
25
26#include <QtGui/QVBoxLayout>
27#include <QtCore/QFile>
28#include <QtGui/QTextEdit>
29#include <QtGui/QLineEdit>
30#include <QtGui/QScrollBar>
31#include <QSocketNotifier>
32
33#include <kglobalsettings.h>
34#include <kcolorscheme.h>
35#include <kdebug.h>
36#include <kstandarddirs.h>
37#include <krandom.h>
38
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <fcntl.h>
42#include <unistd.h>
43
44IOView::IOView(QWidget *parent)
45: QWidget(parent)
46{
47 m_output = new QTextEdit();
48 m_output->setReadOnly(true);
49 m_output->setUndoRedoEnabled(false);
50 m_output->setAcceptRichText(false);
51 // fixed wide font, like konsole
52 m_output->setFont(KGlobalSettings::fixedFont());
53 // alternate color scheme, like konsole
54 KColorScheme schemeView(QPalette::Active, KColorScheme::View);
55 m_output->setTextBackgroundColor(schemeView.foreground().color());
56 m_output->setTextColor(schemeView.background().color());
57 QPalette p = m_output->palette ();
58 p.setColor(QPalette::Base, schemeView.foreground().color());
59 m_output->setPalette(p);
60
61 m_input = new QLineEdit();
62 m_output->setFocusProxy(m_input); // take the focus from the output
63
64 QVBoxLayout *layout = new QVBoxLayout(this);
65 layout->addWidget(m_output, 10);
66 layout->addWidget(m_input, 0);
67 layout->setContentsMargins(0,0,0,0);
68 layout->setSpacing(0);
69
70 connect(m_input, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
71 createFifos();
72}
73
74IOView::~IOView()
75{
76 m_stdin.close();
77
78 m_stdout.close();
79 m_stdout.setFileName(m_stdoutFifo);
80 ::close(m_stdoutFD);
81
82 m_stderr.close();
83 m_stderr.setFileName(m_stderrFifo);
84 ::close(m_stderrFD);
85
86 m_stdin.remove();
87 m_stdout.remove();
88 m_stderr.remove();
89}
90
91void IOView::createFifos()
92{
93 m_stdinFifo = createFifo("stdInFifo");
94 m_stdoutFifo = createFifo("stdOutFifo");
95 m_stderrFifo = createFifo("stdErrFifo");
96
97 m_stdin.setFileName(m_stdinFifo);
98 if (!m_stdin.open(QIODevice::ReadWrite)) return;
99
100 m_stdoutD.setFileName(m_stdoutFifo);
101 m_stdoutD.open(QIODevice::ReadWrite);
102
103 m_stdout.setFileName(m_stdoutFifo);
104 m_stdoutFD = ::open(m_stdoutFifo.toLocal8Bit(), O_RDWR|O_NONBLOCK );
105 if (m_stdoutFD == -1) return;
106 if (!m_stdout.open(m_stdoutFD, QIODevice::ReadWrite)) return;
107
108 m_stdoutNotifier = new QSocketNotifier(m_stdoutFD, QSocketNotifier::Read, this);
109 connect(m_stdoutNotifier, SIGNAL(activated(int)), this, SLOT(readOutput()));
110 m_stdoutNotifier->setEnabled(true);
111
112
113 m_stderrD.setFileName(m_stderrFifo);
114 m_stderrD.open(QIODevice::ReadWrite);
115
116 m_stderr.setFileName(m_stderrFifo);
117 m_stderrFD = ::open(m_stderrFifo.toLocal8Bit(), O_RDONLY|O_NONBLOCK );
118 if (m_stderrFD == -1) return;
119 if (!m_stderr.open(m_stderrFD, QIODevice::ReadOnly)) return;
120
121 m_stderrNotifier = new QSocketNotifier(m_stderrFD, QSocketNotifier::Read, this);
122 connect(m_stderrNotifier, SIGNAL(activated(int)), this, SLOT(readErrors()));
123 m_stderrNotifier->setEnabled(true);
124
125 return;
126}
127
128void IOView::returnPressed()
129{
130 m_stdin.write(m_input->text().toLocal8Bit());
131 m_stdin.write("\n");
132 m_stdin.flush();
133 m_input->clear();
134}
135
136void IOView::readOutput()
137{
138 m_stdoutNotifier->setEnabled(false);
139 qint64 res;
140 char chData[256];
141 QByteArray data;
142
143 do {
144 res = m_stdout.read(chData, 255);
145 if (res <= 0) {
146 m_stdoutD.flush();
147 }
148 else {
149 data.append(chData, res);
150 }
151
152 } while (res == 255);
153
154 if (data.size() > 0) {
155 emit stdOutText(QString::fromLocal8Bit(data));
156 }
157 m_stdoutNotifier->setEnabled(true);
158}
159
160void IOView::readErrors()
161{
162 m_stderrNotifier->setEnabled(false);
163 qint64 res;
164 char chData[256];
165 QByteArray data;
166
167 do {
168 res = m_stderr.read(chData, 255);
169 if (res <= 0) {
170 m_stderrD.flush();
171 }
172 else {
173 data.append(chData, res);
174 }
175 } while (res == 255);
176
177 if (data.size() > 0) {
178 emit stdErrText(QString::fromLocal8Bit(data));
179 }
180 m_stderrNotifier->setEnabled(true);
181}
182
183void IOView::addStdOutText(const QString &text)
184{
185 QScrollBar *scrollb = m_output->verticalScrollBar();
186 if (!scrollb) return;
187 bool atEnd = (scrollb->value() == scrollb->maximum());
188
189 QTextCursor cursor = m_output->textCursor();
190 if (!cursor.atEnd()) cursor.movePosition(QTextCursor::End);
191 cursor.insertText(text);
192
193 if (atEnd) {
194 scrollb->setValue(scrollb->maximum());
195 }
196}
197
198void IOView::addStdErrText(const QString &text)
199{
200 m_output->setFontItalic(true);
201 addStdOutText(text);
202 m_output->setFontItalic(false);
203}
204
205QString IOView::createFifo(const QString &prefix)
206{
207 QString fifo = KStandardDirs::locateLocal("socket", prefix + KRandom::randomString(3));
208 int result = mkfifo(QFile::encodeName(fifo), 0666);
209 if (result != 0) return QString();
210 return fifo;
211}
212
213const QString IOView::stdinFifo() { return m_stdinFifo; }
214const QString IOView::stdoutFifo() { return m_stdoutFifo; }
215const QString IOView::stderrFifo() { return m_stderrFifo; }
216
217void IOView::enableInput(bool enable) { m_input->setEnabled(enable); }
218
219void IOView::clearOutput() { m_output->clear(); }
220