/[svn]/qsampler/trunk/src/qsamplerMessages.cpp
ViewVC logotype

Contents of /qsampler/trunk/src/qsamplerMessages.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2669 - (show annotations) (download)
Sun Aug 3 16:56:18 2014 UTC (6 years, 1 month ago) by capela
File size: 8600 byte(s)
* Messages standard output capture has been slightly improved
  as for non-blocking i/o, whenever available. (EXPERIMENTAL)
1 // qsamplerMessages.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2004-2014, rncbc aka Rui Nuno Capela. All rights reserved.
5 Copyright (C) 2007, Christian Schoenebeck
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 *****************************************************************************/
22
23 #include "qsamplerAbout.h"
24 #include "qsamplerMessages.h"
25
26 #include <QSocketNotifier>
27
28 #include <QFile>
29 #include <QTextEdit>
30 #include <QTextCursor>
31 #include <QTextStream>
32 #include <QTextBlock>
33 #include <QScrollBar>
34 #include <QDateTime>
35 #include <QIcon>
36
37 #if !defined(WIN32)
38 #include <unistd.h>
39 #include <fcntl.h>
40 #endif
41
42
43 namespace QSampler {
44
45 // The default maximum number of message lines.
46 #define QSAMPLER_MESSAGES_MAXLINES 1000
47
48 // Notification pipe descriptors
49 #define QSAMPLER_MESSAGES_FDNIL -1
50 #define QSAMPLER_MESSAGES_FDREAD 0
51 #define QSAMPLER_MESSAGES_FDWRITE 1
52
53
54 //-------------------------------------------------------------------------
55 // QSampler::Messages - Messages log dockable window.
56 //
57
58 // Constructor.
59 Messages::Messages ( QWidget *pParent )
60 : QDockWidget(pParent)
61 {
62 // Surely a name is crucial (e.g.for storing geometry settings)
63 QDockWidget::setObjectName("qsamplerMessages");
64
65 // Intialize stdout capture stuff.
66 m_pStdoutNotifier = NULL;
67 m_fdStdout[QSAMPLER_MESSAGES_FDREAD] = QSAMPLER_MESSAGES_FDNIL;
68 m_fdStdout[QSAMPLER_MESSAGES_FDWRITE] = QSAMPLER_MESSAGES_FDNIL;
69
70 // Create local text view widget.
71 m_pMessagesTextView = new QTextEdit(this);
72 // QFont font(m_pMessagesTextView->font());
73 // font.setFamily("Fixed");
74 // m_pMessagesTextView->setFont(font);
75 m_pMessagesTextView->setLineWrapMode(QTextEdit::NoWrap);
76 m_pMessagesTextView->setReadOnly(true);
77 m_pMessagesTextView->setUndoRedoEnabled(false);
78 // m_pMessagesTextView->setTextFormat(Qt::LogText);
79
80 // Initialize default message limit.
81 m_iMessagesLines = 0;
82 setMessagesLimit(QSAMPLER_MESSAGES_MAXLINES);
83
84 m_pMessagesLog = NULL;
85
86 // Prepare the dockable window stuff.
87 QDockWidget::setWidget(m_pMessagesTextView);
88 QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
89 QDockWidget::setAllowedAreas(
90 Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
91 // Some specialties to this kind of dock window...
92 QDockWidget::setMinimumHeight(120);
93
94 // Finally set the default caption and tooltip.
95 const QString& sCaption = tr("Messages");
96 QDockWidget::setWindowTitle(sCaption);
97 // QDockWidget::setWindowIcon(QIcon(":/icons/qsamplerMessages.png"));
98 QDockWidget::setToolTip(sCaption);
99 }
100
101
102 // Destructor.
103 Messages::~Messages (void)
104 {
105 // Turn off and close logging.
106 setLogging(false);
107
108 // No more notifications.
109 if (m_pStdoutNotifier)
110 delete m_pStdoutNotifier;
111
112 // No need to delete child widgets, Qt does it all for us.
113 }
114
115
116 // Own stdout/stderr socket notifier slot.
117 void Messages::stdoutNotify ( int fd )
118 {
119 #if !defined(WIN32)
120 // Set non-blocking reads, if not already...
121 const int iFlags = ::fcntl(fd, F_GETFL, 0);
122 int iBlock = ((iFlags & O_NONBLOCK) == 0);
123 if (iBlock)
124 iBlock = ::fcntl(fd, F_SETFL, iFlags | O_NONBLOCK);
125 // Read as much as is available...
126 QString sTemp;
127 char achBuffer[1024];
128 const int cchBuffer = sizeof(achBuffer) - 1;
129 int cchRead = ::read(fd, achBuffer, cchBuffer);
130 while (cchRead > 0) {
131 achBuffer[cchRead] = (char) 0;
132 sTemp.append(achBuffer);
133 cchRead = (iBlock ? 0 : ::read(fd, achBuffer, cchBuffer));
134 }
135 // Needs to be non-empty...
136 if (!sTemp.isEmpty())
137 appendStdoutBuffer(sTemp);
138 #endif
139 }
140
141
142 // Stdout buffer handler -- now splitted by complete new-lines...
143 void Messages::appendStdoutBuffer ( const QString& s )
144 {
145 m_sStdoutBuffer.append(s);
146
147 const int iLength = m_sStdoutBuffer.lastIndexOf('\n');
148 if (iLength > 0) {
149 const QString& sTemp = m_sStdoutBuffer.left(iLength);
150 m_sStdoutBuffer.remove(0, iLength + 1);
151 QStringList list = sTemp.split('\n');
152 QStringListIterator iter(list);
153 while (iter.hasNext())
154 appendMessagesText(iter.next());
155 }
156 }
157
158
159 // Stdout flusher -- show up any unfinished line...
160 void Messages::flushStdoutBuffer (void)
161 {
162 if (!m_sStdoutBuffer.isEmpty()) {
163 appendMessagesText(m_sStdoutBuffer);
164 m_sStdoutBuffer.clear();
165 }
166 }
167
168
169 // Stdout capture accessors.
170 bool Messages::isCaptureEnabled (void)
171 {
172 return (m_pStdoutNotifier != NULL);
173 }
174
175 void Messages::setCaptureEnabled ( bool bCapture )
176 {
177 // Flush current buffer.
178 flushStdoutBuffer();
179
180 #if !defined(WIN32)
181 // Destroy if already enabled.
182 if (!bCapture && m_pStdoutNotifier) {
183 delete m_pStdoutNotifier;
184 m_pStdoutNotifier = NULL;
185 // Close the notification pipes.
186 if (m_fdStdout[QSAMPLER_MESSAGES_FDREAD] != QSAMPLER_MESSAGES_FDNIL) {
187 ::close(m_fdStdout[QSAMPLER_MESSAGES_FDREAD]);
188 m_fdStdout[QSAMPLER_MESSAGES_FDREAD] = QSAMPLER_MESSAGES_FDNIL;
189 }
190 }
191 // Are we going to make up the capture?
192 if (bCapture && m_pStdoutNotifier == NULL && ::pipe(m_fdStdout) == 0) {
193 ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDOUT_FILENO);
194 ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDERR_FILENO);
195 m_pStdoutNotifier = new QSocketNotifier(
196 m_fdStdout[QSAMPLER_MESSAGES_FDREAD], QSocketNotifier::Read, this);
197 QObject::connect(m_pStdoutNotifier,
198 SIGNAL(activated(int)),
199 SLOT(stdoutNotify(int)));
200 }
201 #endif
202 }
203
204
205 // Message font accessors.
206 QFont Messages::messagesFont (void)
207 {
208 return m_pMessagesTextView->font();
209 }
210
211 void Messages::setMessagesFont ( const QFont& font )
212 {
213 m_pMessagesTextView->setFont(font);
214 }
215
216
217 // Maximum number of message lines accessors.
218 int Messages::messagesLimit (void)
219 {
220 return m_iMessagesLimit;
221 }
222
223 void Messages::setMessagesLimit ( int iMessagesLimit )
224 {
225 m_iMessagesLimit = iMessagesLimit;
226 m_iMessagesHigh = iMessagesLimit + (iMessagesLimit / 3);
227 }
228
229 // Messages logging stuff.
230 bool Messages::isLogging (void) const
231 {
232 return (m_pMessagesLog != NULL);
233 }
234
235 void Messages::setLogging ( bool bEnabled, const QString& sFilename )
236 {
237 if (m_pMessagesLog) {
238 appendMessages(tr("Logging stopped --- %1 ---")
239 .arg(QDateTime::currentDateTime().toString()));
240 m_pMessagesLog->close();
241 delete m_pMessagesLog;
242 m_pMessagesLog = NULL;
243 }
244
245 if (bEnabled) {
246 m_pMessagesLog = new QFile(sFilename);
247 if (m_pMessagesLog->open(QIODevice::Text | QIODevice::Append)) {
248 appendMessages(tr("Logging started --- %1 ---")
249 .arg(QDateTime::currentDateTime().toString()));
250 } else {
251 delete m_pMessagesLog;
252 m_pMessagesLog = NULL;
253 }
254 }
255 }
256
257
258 // Messages log output method.
259 void Messages::appendMessagesLog ( const QString& s )
260 {
261 if (m_pMessagesLog) {
262 QTextStream(m_pMessagesLog) << s << endl;
263 m_pMessagesLog->flush();
264 }
265 }
266
267 // Messages widget output method.
268 void Messages::appendMessagesLine ( const QString& s )
269 {
270 // Check for message line limit...
271 if (m_iMessagesLines > m_iMessagesHigh) {
272 m_pMessagesTextView->setUpdatesEnabled(false);
273 QTextCursor textCursor(m_pMessagesTextView->document()->begin());
274 while (m_iMessagesLines > m_iMessagesLimit) {
275 // Move cursor extending selection
276 // from start to next line-block...
277 textCursor.movePosition(
278 QTextCursor::NextBlock, QTextCursor::KeepAnchor);
279 m_iMessagesLines--;
280 }
281 // Remove the excessive line-blocks...
282 textCursor.removeSelectedText();
283 m_pMessagesTextView->setUpdatesEnabled(true);
284 }
285
286 m_pMessagesTextView->append(s);
287 m_iMessagesLines++;
288 }
289
290
291 // The main utility methods.
292 void Messages::appendMessages ( const QString& s )
293 {
294 appendMessagesColor(s, "#999999");
295 }
296
297 void Messages::appendMessagesColor ( const QString& s, const QString &c )
298 {
299 const QString& sText
300 = QTime::currentTime().toString("hh:mm:ss.zzz") + ' ' + s;
301 appendMessagesLine("<font color=\"" + c + "\">" + sText + "</font>");
302 appendMessagesLog(sText);
303 }
304
305 void Messages::appendMessagesText ( const QString& s )
306 {
307 appendMessagesLine(s);
308 appendMessagesLog(s);
309 }
310
311
312 // History reset.
313 void Messages::clear (void)
314 {
315 m_iMessagesLines = 0;
316 m_pMessagesTextView->clear();
317 }
318
319 } // namespace QSampler
320
321
322 // end of qsamplerMessages.cpp

  ViewVC Help
Powered by ViewVC