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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 772 by capela, Tue Sep 13 14:00:22 2005 UTC revision 3853 by capela, Mon Jan 25 10:07:17 2021 UTC
# Line 1  Line 1 
1  // qsamplerMessages.cpp  // qsamplerMessages.cpp
2  //  //
3  /****************************************************************************  /****************************************************************************
4     Copyright (C) 2003-2005, rncbc aka Rui Nuno Capela. All rights reserved.     Copyright (C) 2004-2021, 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     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License     modify it under the terms of the GNU General Public License
# Line 13  Line 14 
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License along
18     along with this program; if not, write to the Free Software     with this program; if not, write to the Free Software Foundation, Inc.,
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21  *****************************************************************************/  *****************************************************************************/
22    
23    #include "qsamplerAbout.h"
24  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
25    
26  #include <qsocketnotifier.h>  #include <QSocketNotifier>
 #include <qstringlist.h>  
 #include <qtextedit.h>  
 #include <qdatetime.h>  
 #include <qtooltip.h>  
 #include <qpixmap.h>  
27    
28  #include "config.h"  #include <QFile>
29    #include <QTextBrowser>
30    #include <QTextCursor>
31    #include <QTextStream>
32    #include <QTextBlock>
33    #include <QDateTime>
34    #include <QIcon>
35    
36  #if !defined(WIN32)  #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32)
37  #include <unistd.h>  #include <unistd.h>
38    #include <fcntl.h>
39  #endif  #endif
40    
41    
42    // Deprecated QTextStreamFunctions/Qt namespaces workaround.
43    #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
44    #define endl    Qt::endl
45    #endif
46    
47    
48    namespace QSampler {
49    
50  // The default maximum number of message lines.  // The default maximum number of message lines.
51  #define QSAMPLER_MESSAGES_MAXLINES  1000  #define QSAMPLER_MESSAGES_MAXLINES  1000
52    
# Line 44  Line 57 
57    
58    
59  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
60  // qsamplerMessages - Messages log dockable window.  // QSampler::Messages - Messages log dockable window.
61  //  //
62    
63  // Constructor.  // Constructor.
64  qsamplerMessages::qsamplerMessages ( QWidget *pParent, const char *pszName )  Messages::Messages ( QWidget *pParent )
65      : QDockWindow(pParent, pszName)          : QDockWidget(pParent)
66  {  {
67      // Intialize stdout capture stuff.          // Surely a name is crucial (e.g.for storing geometry settings)
68      m_pStdoutNotifier = NULL;          QDockWidget::setObjectName("qsamplerMessages");
69      m_fdStdout[QSAMPLER_MESSAGES_FDREAD]  = QSAMPLER_MESSAGES_FDNIL;  
70      m_fdStdout[QSAMPLER_MESSAGES_FDWRITE] = QSAMPLER_MESSAGES_FDNIL;          // Intialize stdout capture stuff.
71            m_pStdoutNotifier = nullptr;
72      // Surely a name is crucial (e.g.for storing geometry settings)          m_fdStdout[QSAMPLER_MESSAGES_FDREAD]  = QSAMPLER_MESSAGES_FDNIL;
73      if (pszName == 0)          m_fdStdout[QSAMPLER_MESSAGES_FDWRITE] = QSAMPLER_MESSAGES_FDNIL;
74          QDockWindow::setName("qsamplerMessages");  
75            // Create local text view widget.
76      // Create local text view widget.          m_pMessagesTextView = new QTextBrowser(this);
77      m_pTextView = new QTextEdit(this);  //  QFont font(m_pMessagesTextView->font());
 //  QFont font(m_pTextView->font());  
78  //  font.setFamily("Fixed");  //  font.setFamily("Fixed");
79  //  m_pTextView->setFont(font);  //  m_pMessagesTextView->setFont(font);
80      m_pTextView->setWordWrap(QTextEdit::NoWrap);          m_pMessagesTextView->setLineWrapMode(QTextEdit::NoWrap);
81      m_pTextView->setReadOnly(true);  //      m_pMessagesTextView->setReadOnly(true);
82      m_pTextView->setUndoRedoEnabled(false);  //      m_pMessagesTextView->setUndoRedoEnabled(false);
83  #if QT_VERSION >= 0x030200  //      m_pMessagesTextView->setTextFormat(Qt::LogText);
84      m_pTextView->setTextFormat(Qt::LogText);  
85  #endif          // Initialize default message limit.
86      // Initialize default message limit.          m_iMessagesLines = 0;
87      setMessagesLimit(QSAMPLER_MESSAGES_MAXLINES);          setMessagesLimit(QSAMPLER_MESSAGES_MAXLINES);
88    
89      // Prepare the dockable window stuff.          m_pMessagesLog = nullptr;
90      QDockWindow::setWidget(m_pTextView);  
91      QDockWindow::setOrientation(Qt::Horizontal);          // Prepare the dockable window stuff.
92      QDockWindow::setCloseMode(QDockWindow::Always);          QDockWidget::setWidget(m_pMessagesTextView);
93      QDockWindow::setResizeEnabled(true);  //      QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
94            QDockWidget::setAllowedAreas(
95                    Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
96          // Some specialties to this kind of dock window...          // Some specialties to this kind of dock window...
97          QDockWindow::setFixedExtentHeight(120);          QDockWidget::setMinimumHeight(120);
98    
99      // Finally set the default caption and tooltip.          // Finally set the default caption and tooltip.
100      QString sCaption = tr("Messages");          const QString& sCaption = tr("Messages");
101      QToolTip::add(this, sCaption);          QDockWidget::setWindowTitle(sCaption);
102      QDockWindow::setCaption(sCaption);  //      QDockWidget::setWindowIcon(QIcon(":/icons/qsamplerMessages.png"));
103            QDockWidget::setToolTip(sCaption);
104  }  }
105    
106    
107  // Destructor.  // Destructor.
108  qsamplerMessages::~qsamplerMessages (void)  Messages::~Messages (void)
109  {  {
110      // No more notifications.          // Turn off and close logging.
111      if (m_pStdoutNotifier)          setLogging(false);
112          delete m_pStdoutNotifier;  
113            // No more notifications.
114            if (m_pStdoutNotifier)
115                    delete m_pStdoutNotifier;
116    
117      // No need to delete child widgets, Qt does it all for us.          // No need to delete child widgets, Qt does it all for us.
118    }
119    
120    
121    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
122    #pragma GCC diagnostic push
123    #pragma GCC diagnostic ignored "-Wunused-parameter"
124    #endif
125    
126    // Set stdout/stderr blocking mode.
127    bool Messages::stdoutBlock ( int fd, bool bBlock ) const
128    {
129    #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32)
130            const int iFlags = ::fcntl(fd, F_GETFL, 0);
131            const bool bNonBlock = bool(iFlags & O_NONBLOCK);
132            if (bBlock && bNonBlock)
133                    bBlock = (::fcntl(fd, F_SETFL, iFlags & ~O_NONBLOCK) == 0);
134            else
135            if (!bBlock && !bNonBlock)
136                    bBlock = (::fcntl(fd, F_SETFL, iFlags |  O_NONBLOCK) != 0);
137    #endif
138            return bBlock;
139  }  }
140    
141    
142  // Own stdout/stderr socket notifier slot.  // Own stdout/stderr socket notifier slot.
143  void qsamplerMessages::stdoutNotify ( int fd )  void Messages::stdoutNotify ( int fd )
144  {  {
145  #if !defined(WIN32)  #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32)
146      char achBuffer[1024];          // Set non-blocking reads, if not already...
147      int  cchBuffer = ::read(fd, achBuffer, sizeof(achBuffer) - 1);          const bool bBlock = stdoutBlock(fd, false);
148      if (cchBuffer > 0) {          // Read as much as is available...
149          achBuffer[cchBuffer] = (char) 0;          QString sTemp;
150          appendStdoutBuffer(achBuffer);          char achBuffer[1024];
151      }          const int cchBuffer = sizeof(achBuffer) - 1;
152            int cchRead = ::read(fd, achBuffer, cchBuffer);
153            while (cchRead > 0) {
154                    achBuffer[cchRead] = (char) 0;
155                    sTemp.append(achBuffer);
156                    cchRead = (bBlock ? 0 : ::read(fd, achBuffer, cchBuffer));
157            }
158            // Needs to be non-empty...
159            if (!sTemp.isEmpty())
160                    appendStdoutBuffer(sTemp);
161  #endif  #endif
162  }  }
163    
164    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
165    #pragma GCC diagnostic pop
166    #endif
167    
168    
169  // Stdout buffer handler -- now splitted by complete new-lines...  // Stdout buffer handler -- now splitted by complete new-lines...
170  void qsamplerMessages::appendStdoutBuffer ( const QString& s )  void Messages::appendStdoutBuffer ( const QString& s )
171  {  {
172      m_sStdoutBuffer.append(s);          m_sStdoutBuffer.append(s);
173    
174            processStdoutBuffer();
175    }
176    
177      int iLength = m_sStdoutBuffer.findRev('\n') + 1;  void Messages::processStdoutBuffer (void)
178      if (iLength > 0) {  {
179          QString sTemp = m_sStdoutBuffer.left(iLength);          const int iLength = m_sStdoutBuffer.lastIndexOf('\n');
180          m_sStdoutBuffer.remove(0, iLength);          if (iLength > 0) {
181          QStringList list = QStringList::split('\n', sTemp, true);                  const QString& sTemp = m_sStdoutBuffer.left(iLength);
182          for (QStringList::Iterator iter = list.begin(); iter != list.end(); iter++)                  m_sStdoutBuffer.remove(0, iLength + 1);
183              appendMessagesText(*iter);                  QStringList list = sTemp.split('\n');
184      }                  QStringListIterator iter(list);
185                    while (iter.hasNext())
186                            appendMessagesText(iter.next());
187            }
188  }  }
189    
190    
191  // Stdout flusher -- show up any unfinished line...  // Stdout flusher -- show up any unfinished line...
192  void qsamplerMessages::flushStdoutBuffer (void)  void Messages::flushStdoutBuffer (void)
193  {  {
194      if (!m_sStdoutBuffer.isEmpty()) {          if (!m_sStdoutBuffer.isEmpty()) {
195          appendMessagesText(m_sStdoutBuffer);                  processStdoutBuffer();
196          m_sStdoutBuffer.truncate(0);                  m_sStdoutBuffer.clear();
197      }          }
198  }  }
199    
200    
201  // Stdout capture accessors.  // Stdout capture accessors.
202  bool qsamplerMessages::isCaptureEnabled (void)  bool Messages::isCaptureEnabled (void)
203  {  {
204      return (bool) (m_pStdoutNotifier != NULL);          return (m_pStdoutNotifier != nullptr);
205  }  }
206    
207  void qsamplerMessages::setCaptureEnabled ( bool bCapture )  void Messages::setCaptureEnabled ( bool bCapture )
208  {  {
209      // Flush current buffer.          // Flush current buffer.
210      flushStdoutBuffer();          flushStdoutBuffer();
211    
212  #if !defined(WIN32)  #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32)
213      // Destroy if already enabled.          // Destroy if already enabled.
214      if (!bCapture && m_pStdoutNotifier) {          if (!bCapture && m_pStdoutNotifier) {
215          delete m_pStdoutNotifier;                  delete m_pStdoutNotifier;
216          m_pStdoutNotifier = NULL;                  m_pStdoutNotifier = nullptr;
217          // Close the notification pipes.                  // Close the notification pipes.
218          if (m_fdStdout[QSAMPLER_MESSAGES_FDREAD] != QSAMPLER_MESSAGES_FDNIL) {                  if (m_fdStdout[QSAMPLER_MESSAGES_FDREAD] != QSAMPLER_MESSAGES_FDNIL) {
219              ::close(m_fdStdout[QSAMPLER_MESSAGES_FDREAD]);                          ::close(m_fdStdout[QSAMPLER_MESSAGES_FDREAD]);
220              m_fdStdout[QSAMPLER_MESSAGES_FDREAD]  = QSAMPLER_MESSAGES_FDNIL;                          m_fdStdout[QSAMPLER_MESSAGES_FDREAD]  = QSAMPLER_MESSAGES_FDNIL;
221          }                  }
222          if (m_fdStdout[QSAMPLER_MESSAGES_FDREAD] != QSAMPLER_MESSAGES_FDNIL) {          }
223              ::close(m_fdStdout[QSAMPLER_MESSAGES_FDREAD]);          // Are we going to make up the capture?
224              m_fdStdout[QSAMPLER_MESSAGES_FDREAD]  = QSAMPLER_MESSAGES_FDNIL;          if (bCapture && m_pStdoutNotifier == nullptr && ::pipe(m_fdStdout) == 0) {
225          }                  ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDOUT_FILENO);
226      }                  ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDERR_FILENO);
227      // Are we going to make up the capture?                  m_pStdoutNotifier = new QSocketNotifier(
228      if (bCapture && m_pStdoutNotifier == NULL && ::pipe(m_fdStdout) == 0) {                          m_fdStdout[QSAMPLER_MESSAGES_FDREAD], QSocketNotifier::Read, this);
229          ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDOUT_FILENO);                  QObject::connect(m_pStdoutNotifier,
230          ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDERR_FILENO);                          SIGNAL(activated(int)),
231          m_pStdoutNotifier = new QSocketNotifier(m_fdStdout[QSAMPLER_MESSAGES_FDREAD], QSocketNotifier::Read, this);                          SLOT(stdoutNotify(int)));
232          QObject::connect(m_pStdoutNotifier, SIGNAL(activated(int)), this, SLOT(stdoutNotify(int)));          }
     }  
233  #endif  #endif
234  }  }
235    
236    
237  // Message font accessors.  // Message font accessors.
238  QFont qsamplerMessages::messagesFont (void)  QFont Messages::messagesFont (void)
239  {  {
240      return m_pTextView->font();          return m_pMessagesTextView->font();
241  }  }
242    
243  void qsamplerMessages::setMessagesFont( const QFont& font )  void Messages::setMessagesFont ( const QFont& font )
244  {  {
245      m_pTextView->setFont(font);          m_pMessagesTextView->setFont(font);
246  }  }
247    
248    
249  // Maximum number of message lines accessors.  // Maximum number of message lines accessors.
250  int qsamplerMessages::messagesLimit (void)  int Messages::messagesLimit (void)
251  {  {
252      return m_iMessagesLimit;          return m_iMessagesLimit;
253  }  }
254    
255  void qsamplerMessages::setMessagesLimit ( int iMessagesLimit )  void Messages::setMessagesLimit ( int iMessagesLimit )
256  {  {
257      m_iMessagesLimit = iMessagesLimit;          m_iMessagesLimit = iMessagesLimit;
258      m_iMessagesHigh  = iMessagesLimit + (iMessagesLimit / 3);          m_iMessagesHigh  = iMessagesLimit + (iMessagesLimit / 3);
259  #if QT_VERSION >= 0x030200  }
260          m_pTextView->setMaxLogLines(iMessagesLimit);  
261  #endif  // Messages logging stuff.
262    bool Messages::isLogging (void) const
263    {
264            return (m_pMessagesLog != nullptr);
265    }
266    
267    void Messages::setLogging ( bool bEnabled, const QString& sFilename )
268    {
269            if (m_pMessagesLog) {
270                    appendMessages(tr("Logging stopped --- %1 ---")
271                            .arg(QDateTime::currentDateTime().toString()));
272                    m_pMessagesLog->close();
273                    delete m_pMessagesLog;
274                    m_pMessagesLog = nullptr;
275            }
276    
277            if (bEnabled) {
278                    m_pMessagesLog = new QFile(sFilename);
279                    if (m_pMessagesLog->open(QIODevice::Text | QIODevice::Append)) {
280                            appendMessages(tr("Logging started --- %1 ---")
281                                    .arg(QDateTime::currentDateTime().toString()));
282                    } else {
283                            delete m_pMessagesLog;
284                            m_pMessagesLog = nullptr;
285                    }
286            }
287    }
288    
289    
290    // Messages log output method.
291    void Messages::appendMessagesLog ( const QString& s )
292    {
293            if (m_pMessagesLog) {
294                    QTextStream(m_pMessagesLog)
295                            << QTime::currentTime().toString("hh:mm:ss.zzz")
296                            << ' ' << s << endl;
297                    m_pMessagesLog->flush();
298            }
299    }
300    
301    // Messages widget output method.
302    void Messages::appendMessagesLine ( const QString& s )
303    {
304            // Check for message line limit...
305            if (m_iMessagesLines > m_iMessagesHigh) {
306                    m_pMessagesTextView->setUpdatesEnabled(false);
307                    QTextCursor textCursor(m_pMessagesTextView->document()->begin());
308                    while (m_iMessagesLines > m_iMessagesLimit) {
309                            // Move cursor extending selection
310                            // from start to next line-block...
311                            textCursor.movePosition(
312                                    QTextCursor::NextBlock, QTextCursor::KeepAnchor);
313                            m_iMessagesLines--;
314                    }
315                    // Remove the excessive line-blocks...
316                    textCursor.removeSelectedText();
317                    m_pMessagesTextView->setUpdatesEnabled(true);
318            }
319    
320            m_pMessagesTextView->append(s);
321            m_iMessagesLines++;
322  }  }
323    
324    
325  // The main utility methods.  // The main utility methods.
326  void qsamplerMessages::appendMessages ( const QString& s )  void Messages::appendMessages ( const QString& s )
327  {  {
328      appendMessagesColor(s, "#999999");          appendMessagesColor(s, Qt::gray);
329  }  }
330    
331  void qsamplerMessages::appendMessagesColor ( const QString& s, const QString &c )  void Messages::appendMessagesColor ( const QString& s, const QColor& rgb )
332  {  {
333      appendMessagesText("<font color=\"" + c + "\">" + QTime::currentTime().toString("hh:mm:ss.zzz") + " " + s + "</font>");          appendMessagesLine("<font color=\"" + rgb.name() + "\">" + s + "</font>");
334            appendMessagesLog(s);
335  }  }
336    
337  void qsamplerMessages::appendMessagesText ( const QString& s )  void Messages::appendMessagesText ( const QString& s )
338  {  {
339  #if QT_VERSION < 0x030200          appendMessagesLine(s);
340      // Check for message line limit...          appendMessagesLog(s);
     if (m_iMessagesLimit > 0) {  
         int iParagraphs = m_pTextView->paragraphs();  
         if (iParagraphs > m_iMessagesHigh) {  
             m_pTextView->setUpdatesEnabled(false);  
             while (iParagraphs > m_iMessagesLimit) {  
                 m_pTextView->removeParagraph(0);  
                 iParagraphs--;  
             }  
             m_pTextView->scrollToBottom();  
             m_pTextView->setUpdatesEnabled(true);  
         }  
     }  
 #endif  
     m_pTextView->append(s);  
341  }  }
342    
343    
344  // One time scroll to the most recent message.  // History reset.
345  void qsamplerMessages::scrollToBottom (void)  void Messages::clear (void)
346  {  {
347      flushStdoutBuffer();          m_iMessagesLines = 0;
348      m_pTextView->scrollToBottom();          m_pMessagesTextView->clear();
349  }  }
350    
351    } // namespace QSampler
352    
353    
354  // end of qsamplerMessages.cpp  // end of qsamplerMessages.cpp

Legend:
Removed from v.772  
changed lines
  Added in v.3853

  ViewVC Help
Powered by ViewVC