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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2848 - (hide 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 capela 94 // qsamplerMessages.cpp
2     //
3     /****************************************************************************
4 capela 2848 Copyright (C) 2004-2015, rncbc aka Rui Nuno Capela. All rights reserved.
5 capela 1464 Copyright (C) 2007, Christian Schoenebeck
6 capela 94
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 capela 920 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 capela 94
21     *****************************************************************************/
22    
23 capela 1465 #include "qsamplerAbout.h"
24 capela 94 #include "qsamplerMessages.h"
25    
26 capela 1465 #include <QSocketNotifier>
27 capela 1738
28     #include <QFile>
29 capela 1465 #include <QTextEdit>
30     #include <QTextCursor>
31 capela 1738 #include <QTextStream>
32 capela 1465 #include <QTextBlock>
33 schoenebeck 1461 #include <QScrollBar>
34 capela 1465 #include <QDateTime>
35     #include <QIcon>
36 schoenebeck 1461
37 capela 115 #if !defined(WIN32)
38     #include <unistd.h>
39 capela 2669 #include <fcntl.h>
40 capela 115 #endif
41    
42 capela 1558
43     namespace QSampler {
44    
45 capela 94 // 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 capela 2582
54 capela 94 //-------------------------------------------------------------------------
55 capela 1558 // QSampler::Messages - Messages log dockable window.
56 capela 94 //
57    
58     // Constructor.
59 capela 1558 Messages::Messages ( QWidget *pParent )
60 capela 1739 : QDockWidget(pParent)
61 capela 94 {
62 capela 1465 // Surely a name is crucial (e.g.for storing geometry settings)
63     QDockWidget::setObjectName("qsamplerMessages");
64    
65 capela 1739 // 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 capela 94
70 capela 1465 // Create local text view widget.
71 capela 1738 m_pMessagesTextView = new QTextEdit(this);
72     // QFont font(m_pMessagesTextView->font());
73 capela 94 // font.setFamily("Fixed");
74 capela 1738 // 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 capela 94
80 capela 1465 // Initialize default message limit.
81     m_iMessagesLines = 0;
82     setMessagesLimit(QSAMPLER_MESSAGES_MAXLINES);
83    
84 capela 1738 m_pMessagesLog = NULL;
85    
86 capela 1465 // Prepare the dockable window stuff.
87 capela 1738 QDockWidget::setWidget(m_pMessagesTextView);
88 capela 1465 QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
89     QDockWidget::setAllowedAreas(
90     Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
91 capela 772 // Some specialties to this kind of dock window...
92 capela 1465 QDockWidget::setMinimumHeight(120);
93 capela 94
94 capela 1465 // 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 capela 94 }
100    
101    
102     // Destructor.
103 capela 1558 Messages::~Messages (void)
104 capela 94 {
105 capela 1739 // Turn off and close logging.
106 capela 1738 setLogging(false);
107    
108 capela 1739 // No more notifications.
109     if (m_pStdoutNotifier)
110     delete m_pStdoutNotifier;
111 capela 94
112 capela 1739 // No need to delete child widgets, Qt does it all for us.
113 capela 94 }
114    
115    
116 capela 2848 // 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 capela 94 // Own stdout/stderr socket notifier slot.
133 capela 1558 void Messages::stdoutNotify ( int fd )
134 capela 94 {
135     #if !defined(WIN32)
136 capela 2669 // Set non-blocking reads, if not already...
137 capela 2848 const bool bBlock = stdoutBlock(fd, false);
138 capela 2669 // Read as much as is available...
139     QString sTemp;
140 capela 1739 char achBuffer[1024];
141 capela 2669 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 capela 2848 cchRead = (bBlock ? 0 : ::read(fd, achBuffer, cchBuffer));
147 capela 1739 }
148 capela 2669 // Needs to be non-empty...
149     if (!sTemp.isEmpty())
150     appendStdoutBuffer(sTemp);
151 capela 94 #endif
152     }
153    
154    
155     // Stdout buffer handler -- now splitted by complete new-lines...
156 capela 1558 void Messages::appendStdoutBuffer ( const QString& s )
157 capela 94 {
158 capela 1465 m_sStdoutBuffer.append(s);
159 capela 94
160 capela 2582 const int iLength = m_sStdoutBuffer.lastIndexOf('\n');
161 capela 1465 if (iLength > 0) {
162 capela 2582 const QString& sTemp = m_sStdoutBuffer.left(iLength);
163 schoenebeck 1474 m_sStdoutBuffer.remove(0, iLength + 1);
164 capela 1465 QStringList list = sTemp.split('\n');
165     QStringListIterator iter(list);
166     while (iter.hasNext())
167     appendMessagesText(iter.next());
168     }
169 capela 94 }
170    
171    
172     // Stdout flusher -- show up any unfinished line...
173 capela 1558 void Messages::flushStdoutBuffer (void)
174 capela 94 {
175 capela 1739 if (!m_sStdoutBuffer.isEmpty()) {
176     appendMessagesText(m_sStdoutBuffer);
177 capela 2669 m_sStdoutBuffer.clear();
178 capela 1739 }
179 capela 94 }
180    
181    
182     // Stdout capture accessors.
183 capela 1558 bool Messages::isCaptureEnabled (void)
184 capela 94 {
185 capela 2582 return (m_pStdoutNotifier != NULL);
186 capela 94 }
187    
188 capela 1558 void Messages::setCaptureEnabled ( bool bCapture )
189 capela 94 {
190 capela 1739 // Flush current buffer.
191     flushStdoutBuffer();
192 capela 94
193     #if !defined(WIN32)
194 capela 1465 // 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 capela 94 #endif
215     }
216    
217    
218     // Message font accessors.
219 capela 1558 QFont Messages::messagesFont (void)
220 capela 94 {
221 capela 1739 return m_pMessagesTextView->font();
222 capela 94 }
223    
224 capela 1738 void Messages::setMessagesFont ( const QFont& font )
225 capela 94 {
226 capela 1739 m_pMessagesTextView->setFont(font);
227 capela 94 }
228    
229    
230     // Maximum number of message lines accessors.
231 capela 1558 int Messages::messagesLimit (void)
232 capela 94 {
233 capela 1739 return m_iMessagesLimit;
234 capela 94 }
235    
236 capela 1558 void Messages::setMessagesLimit ( int iMessagesLimit )
237 capela 94 {
238 capela 1739 m_iMessagesLimit = iMessagesLimit;
239     m_iMessagesHigh = iMessagesLimit + (iMessagesLimit / 3);
240 capela 94 }
241    
242 capela 1738 // Messages logging stuff.
243     bool Messages::isLogging (void) const
244     {
245     return (m_pMessagesLog != NULL);
246     }
247 capela 94
248 capela 1738 void Messages::setLogging ( bool bEnabled, const QString& sFilename )
249 capela 94 {
250 capela 1738 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 capela 94 }
269    
270 capela 1738
271     // Messages log output method.
272     void Messages::appendMessagesLog ( const QString& s )
273 capela 94 {
274 capela 1738 if (m_pMessagesLog) {
275     QTextStream(m_pMessagesLog) << s << endl;
276     m_pMessagesLog->flush();
277     }
278 capela 94 }
279    
280 capela 1738 // Messages widget output method.
281     void Messages::appendMessagesLine ( const QString& s )
282 capela 94 {
283 capela 1738 // Check for message line limit...
284     if (m_iMessagesLines > m_iMessagesHigh) {
285     m_pMessagesTextView->setUpdatesEnabled(false);
286     QTextCursor textCursor(m_pMessagesTextView->document()->begin());
287 capela 1465 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 capela 1738 m_pMessagesTextView->setUpdatesEnabled(true);
297     }
298 capela 1465
299 capela 1738 m_pMessagesTextView->append(s);
300 capela 1465 m_iMessagesLines++;
301 capela 94 }
302    
303    
304 capela 1738 // The main utility methods.
305     void Messages::appendMessages ( const QString& s )
306     {
307 capela 1739 appendMessagesColor(s, "#999999");
308 capela 1738 }
309    
310     void Messages::appendMessagesColor ( const QString& s, const QString &c )
311     {
312 capela 2583 const QString& sText
313     = QTime::currentTime().toString("hh:mm:ss.zzz") + ' ' + s;
314 capela 1738 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 capela 1465 // History reset.
326 capela 1558 void Messages::clear (void)
327 capela 94 {
328 capela 1465 m_iMessagesLines = 0;
329 capela 1738 m_pMessagesTextView->clear();
330 capela 94 }
331    
332 capela 1558 } // namespace QSampler
333 capela 94
334 capela 1558
335 capela 94 // end of qsamplerMessages.cpp

  ViewVC Help
Powered by ViewVC