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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2848 - (show annotations) (download)
Sat Oct 3 15:48:18 2015 UTC (8 years, 5 months ago) by capela
File size: 8911 byte(s)
* Messages standard output capture has been improved again, now
  in both ways a non-blocking pipe may get. (EXPERIMENTAL)
1 // qsamplerMessages.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2004-2015, 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 // Set stdout/stderr blocking mode.
117 bool Messages::stdoutBlock ( int fd, bool bBlock ) const
118 {
119 #if !defined(WIN32)
120 const int iFlags = ::fcntl(fd, F_GETFL, 0);
121 const bool bNonBlock = bool(iFlags & O_NONBLOCK);
122 if (bBlock && bNonBlock)
123 bBlock = (::fcntl(fd, F_SETFL, iFlags & ~O_NONBLOCK) == 0);
124 else
125 if (!bBlock && !bNonBlock)
126 bBlock = (::fcntl(fd, F_SETFL, iFlags | O_NONBLOCK) != 0);
127 #endif
128 return bBlock;
129 }
130
131
132 // Own stdout/stderr socket notifier slot.
133 void Messages::stdoutNotify ( int fd )
134 {
135 #if !defined(WIN32)
136 // Set non-blocking reads, if not already...
137 const bool bBlock = stdoutBlock(fd, false);
138 // Read as much as is available...
139 QString sTemp;
140 char achBuffer[1024];
141 const int cchBuffer = sizeof(achBuffer) - 1;
142 int cchRead = ::read(fd, achBuffer, cchBuffer);
143 while (cchRead > 0) {
144 achBuffer[cchRead] = (char) 0;
145 sTemp.append(achBuffer);
146 cchRead = (bBlock ? 0 : ::read(fd, achBuffer, cchBuffer));
147 }
148 // Needs to be non-empty...
149 if (!sTemp.isEmpty())
150 appendStdoutBuffer(sTemp);
151 #endif
152 }
153
154
155 // Stdout buffer handler -- now splitted by complete new-lines...
156 void Messages::appendStdoutBuffer ( const QString& s )
157 {
158 m_sStdoutBuffer.append(s);
159
160 const int iLength = m_sStdoutBuffer.lastIndexOf('\n');
161 if (iLength > 0) {
162 const QString& sTemp = m_sStdoutBuffer.left(iLength);
163 m_sStdoutBuffer.remove(0, iLength + 1);
164 QStringList list = sTemp.split('\n');
165 QStringListIterator iter(list);
166 while (iter.hasNext())
167 appendMessagesText(iter.next());
168 }
169 }
170
171
172 // Stdout flusher -- show up any unfinished line...
173 void Messages::flushStdoutBuffer (void)
174 {
175 if (!m_sStdoutBuffer.isEmpty()) {
176 appendMessagesText(m_sStdoutBuffer);
177 m_sStdoutBuffer.clear();
178 }
179 }
180
181
182 // Stdout capture accessors.
183 bool Messages::isCaptureEnabled (void)
184 {
185 return (m_pStdoutNotifier != NULL);
186 }
187
188 void Messages::setCaptureEnabled ( bool bCapture )
189 {
190 // Flush current buffer.
191 flushStdoutBuffer();
192
193 #if !defined(WIN32)
194 // Destroy if already enabled.
195 if (!bCapture && m_pStdoutNotifier) {
196 delete m_pStdoutNotifier;
197 m_pStdoutNotifier = NULL;
198 // Close the notification pipes.
199 if (m_fdStdout[QSAMPLER_MESSAGES_FDREAD] != QSAMPLER_MESSAGES_FDNIL) {
200 ::close(m_fdStdout[QSAMPLER_MESSAGES_FDREAD]);
201 m_fdStdout[QSAMPLER_MESSAGES_FDREAD] = QSAMPLER_MESSAGES_FDNIL;
202 }
203 }
204 // Are we going to make up the capture?
205 if (bCapture && m_pStdoutNotifier == NULL && ::pipe(m_fdStdout) == 0) {
206 ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDOUT_FILENO);
207 ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDERR_FILENO);
208 m_pStdoutNotifier = new QSocketNotifier(
209 m_fdStdout[QSAMPLER_MESSAGES_FDREAD], QSocketNotifier::Read, this);
210 QObject::connect(m_pStdoutNotifier,
211 SIGNAL(activated(int)),
212 SLOT(stdoutNotify(int)));
213 }
214 #endif
215 }
216
217
218 // Message font accessors.
219 QFont Messages::messagesFont (void)
220 {
221 return m_pMessagesTextView->font();
222 }
223
224 void Messages::setMessagesFont ( const QFont& font )
225 {
226 m_pMessagesTextView->setFont(font);
227 }
228
229
230 // Maximum number of message lines accessors.
231 int Messages::messagesLimit (void)
232 {
233 return m_iMessagesLimit;
234 }
235
236 void Messages::setMessagesLimit ( int iMessagesLimit )
237 {
238 m_iMessagesLimit = iMessagesLimit;
239 m_iMessagesHigh = iMessagesLimit + (iMessagesLimit / 3);
240 }
241
242 // Messages logging stuff.
243 bool Messages::isLogging (void) const
244 {
245 return (m_pMessagesLog != NULL);
246 }
247
248 void Messages::setLogging ( bool bEnabled, const QString& sFilename )
249 {
250 if (m_pMessagesLog) {
251 appendMessages(tr("Logging stopped --- %1 ---")
252 .arg(QDateTime::currentDateTime().toString()));
253 m_pMessagesLog->close();
254 delete m_pMessagesLog;
255 m_pMessagesLog = NULL;
256 }
257
258 if (bEnabled) {
259 m_pMessagesLog = new QFile(sFilename);
260 if (m_pMessagesLog->open(QIODevice::Text | QIODevice::Append)) {
261 appendMessages(tr("Logging started --- %1 ---")
262 .arg(QDateTime::currentDateTime().toString()));
263 } else {
264 delete m_pMessagesLog;
265 m_pMessagesLog = NULL;
266 }
267 }
268 }
269
270
271 // Messages log output method.
272 void Messages::appendMessagesLog ( const QString& s )
273 {
274 if (m_pMessagesLog) {
275 QTextStream(m_pMessagesLog) << s << endl;
276 m_pMessagesLog->flush();
277 }
278 }
279
280 // Messages widget output method.
281 void Messages::appendMessagesLine ( const QString& s )
282 {
283 // Check for message line limit...
284 if (m_iMessagesLines > m_iMessagesHigh) {
285 m_pMessagesTextView->setUpdatesEnabled(false);
286 QTextCursor textCursor(m_pMessagesTextView->document()->begin());
287 while (m_iMessagesLines > m_iMessagesLimit) {
288 // Move cursor extending selection
289 // from start to next line-block...
290 textCursor.movePosition(
291 QTextCursor::NextBlock, QTextCursor::KeepAnchor);
292 m_iMessagesLines--;
293 }
294 // Remove the excessive line-blocks...
295 textCursor.removeSelectedText();
296 m_pMessagesTextView->setUpdatesEnabled(true);
297 }
298
299 m_pMessagesTextView->append(s);
300 m_iMessagesLines++;
301 }
302
303
304 // The main utility methods.
305 void Messages::appendMessages ( const QString& s )
306 {
307 appendMessagesColor(s, "#999999");
308 }
309
310 void Messages::appendMessagesColor ( const QString& s, const QString &c )
311 {
312 const QString& sText
313 = QTime::currentTime().toString("hh:mm:ss.zzz") + ' ' + s;
314 appendMessagesLine("<font color=\"" + c + "\">" + sText + "</font>");
315 appendMessagesLog(sText);
316 }
317
318 void Messages::appendMessagesText ( const QString& s )
319 {
320 appendMessagesLine(s);
321 appendMessagesLog(s);
322 }
323
324
325 // History reset.
326 void Messages::clear (void)
327 {
328 m_iMessagesLines = 0;
329 m_pMessagesTextView->clear();
330 }
331
332 } // namespace QSampler
333
334
335 // end of qsamplerMessages.cpp

  ViewVC Help
Powered by ViewVC