QGIS API Documentation 3.99.0-Master (7d2ca374f2d)
Loading...
Searching...
No Matches
qgsmessagelogviewer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmessagelogviewer.cpp - description
3 -------------------
4 begin : October 2011
5 copyright : (C) 2011 by Juergen E. Fischer
6 email : jef at norbit dot de
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsmessagelogviewer.h"
19
20#include "qgsapplication.h"
21#include "qgsmessagelog.h"
22#include "qgssettings.h"
23
24#include <QDateTime>
25#include <QDebug>
26#include <QDesktopServices>
27#include <QFile>
28#include <QPlainTextEdit>
29#include <QScrollBar>
30#include <QStatusBar>
31#include <QString>
32#include <QTableWidget>
33#include <QToolButton>
34#include <QToolTip>
35
36#include "moc_qgsmessagelogviewer.cpp"
37
38using namespace Qt::StringLiterals;
39
40QgsMessageLogViewer::QgsMessageLogViewer( QWidget *parent, Qt::WindowFlags fl )
41 : QDialog( parent, fl )
42{
43 setupUi( this );
44
45 connect( QgsApplication::messageLog(), static_cast<void ( QgsMessageLog::* )( const QString &, const QString &, Qgis::MessageLevel, Qgis::StringFormat )>( &QgsMessageLog::messageReceivedWithFormat ), this, static_cast<void ( QgsMessageLogViewer::* )( const QString &, const QString &, Qgis::MessageLevel, Qgis::StringFormat )>( &QgsMessageLogViewer::logMessage ) );
46
47 connect( tabWidget, &QTabWidget::tabCloseRequested, this, &QgsMessageLogViewer::closeTab );
48
49 connect( tabWidget, &QTabWidget::currentChanged, this, [this]( int index ) {
50 tabWidget->setTabIcon( index, QIcon() );
51 } );
52
53 mTabBarContextMenu = new QMenu( this );
54 tabWidget->tabBar()->setContextMenuPolicy( Qt::CustomContextMenu );
55 connect( tabWidget->tabBar(), &QWidget::customContextMenuRequested, this, &QgsMessageLogViewer::showContextMenuForTabBar );
56}
57
58void QgsMessageLogViewer::showContextMenuForTabBar( QPoint point )
59{
60 if ( point.isNull() )
61 {
62 return;
63 }
64
65 mTabBarContextMenu->clear();
66
67 const int tabIndex = tabWidget->tabBar()->tabAt( point );
68
69 QAction *actionCloseTab = new QAction( tr( "Close Tab" ), mTabBarContextMenu );
70 connect( actionCloseTab, &QAction::triggered, this, [this, tabIndex] {
71 closeTab( tabIndex );
72 } );
73 mTabBarContextMenu->addAction( actionCloseTab );
74
75 QAction *actionCloseOtherTabs = new QAction( tr( "Close Other Tabs" ), mTabBarContextMenu );
76 actionCloseOtherTabs->setEnabled( tabWidget->tabBar()->count() > 1 );
77 connect( actionCloseOtherTabs, &QAction::triggered, this, [this, tabIndex] {
78 int i;
79 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
80 {
81 if ( i != tabIndex )
82 {
83 closeTab( i );
84 }
85 }
86 } );
87 mTabBarContextMenu->addAction( actionCloseOtherTabs );
88
89 QAction *actionCloseAllTabs = new QAction( tr( "Close All Tabs" ), mTabBarContextMenu );
90 actionCloseAllTabs->setEnabled( tabWidget->tabBar()->count() > 0 );
91 connect( actionCloseAllTabs, &QAction::triggered, this, [this] {
92 int i;
93 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
94 {
95 closeTab( i );
96 }
97 } );
98 mTabBarContextMenu->addAction( actionCloseAllTabs );
99
100 mTabBarContextMenu->exec( tabWidget->tabBar()->mapToGlobal( point ) );
101}
102
104{
105 e->ignore();
106}
107
111
112void QgsMessageLogViewer::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level, Qgis::StringFormat format )
113{
114 constexpr int MESSAGE_COUNT_LIMIT = 10000;
115 // Avoid logging too many messages, which might blow memory.
116 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
117 return;
118 ++mMessageLoggedCount;
119
120 QString cleanedTag = tag;
121 if ( cleanedTag.isNull() )
122 cleanedTag = tr( "General" );
123
124 int i;
125 for ( i = 0; i < tabWidget->count() && tabWidget->tabText( i ).remove( QChar( '&' ) ) != cleanedTag; i++ )
126 ;
127
128 QPlainTextEdit *w = nullptr;
129 if ( i < tabWidget->count() )
130 {
131 w = qobject_cast<QPlainTextEdit *>( tabWidget->widget( i ) );
132 if ( i != tabWidget->currentIndex() )
133 {
134 tabWidget->setTabIcon( i, QgsApplication::getThemeIcon( u"mMessageLog.svg"_s ) );
135 }
136 }
137 else
138 {
139 w = new QPlainTextEdit( this );
140 w->setReadOnly( true );
141 w->viewport()->installEventFilter( this );
142 i = tabWidget->addTab( w, QgsApplication::getThemeIcon( u"mMessageLog.svg"_s ), cleanedTag );
143 }
144
145 QString levelString;
146 const QgsSettings settings;
147 const QPalette pal = qApp->palette();
148 const QString defaultColorName = pal.color( QPalette::WindowText ).name();
149 QString colorName;
150 switch ( level )
151 {
153 levelString = u"INFO"_s;
154 colorName = settings.value( u"colors/info"_s, QString() ).toString();
155 break;
157 levelString = u"WARNING"_s;
158 colorName = settings.value( u"colors/warning"_s, QString() ).toString();
159 break;
161 levelString = u"CRITICAL"_s;
162 colorName = settings.value( u"colors/critical"_s, QString() ).toString();
163 break;
165 levelString = u"SUCCESS"_s;
166 colorName = settings.value( u"colors/success"_s, QString() ).toString();
167 break;
169 levelString = u"NONE"_s;
170 colorName = settings.value( u"colors/default"_s, QString() ).toString();
171 break;
172 }
173 const QColor color = QColor( !colorName.isEmpty() ? colorName : defaultColorName );
174
175 const QString prefix = u"<font color=\"%1\">%2 &nbsp;&nbsp;&nbsp; %3 &nbsp;&nbsp;&nbsp;</font>"_s
176 .arg( color.name(), QDateTime::currentDateTime().toString( Qt::ISODate ), levelString );
177 QString cleanedMessage;
178 switch ( format )
179 {
181 cleanedMessage = message.toHtmlEscaped();
182 break;
184 cleanedMessage = message;
185 break;
186 }
187 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
188 cleanedMessage = tr( "Message log truncated" );
189
190 cleanedMessage = cleanedMessage.prepend( prefix ).replace( '\n', "<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"_L1 );
191 w->appendHtml( cleanedMessage );
192 w->verticalScrollBar()->setValue( w->verticalScrollBar()->maximum() );
193 tabWidget->show();
194 emptyLabel->hide();
195}
196
197void QgsMessageLogViewer::showTab( const QString &tag )
198{
199 for ( int i = 0; i < tabWidget->count(); i++ )
200 {
201 if ( tabWidget->tabText( i ).remove( QChar( '&' ) ) == tag )
202 {
203 tabWidget->setCurrentIndex( i );
204 return;
205 }
206 }
207}
208
209void QgsMessageLogViewer::closeTab( int index )
210{
211 tabWidget->removeTab( index );
212 if ( tabWidget->count() == 0 )
213 {
214 tabWidget->hide();
215 emptyLabel->show();
216 }
217}
218
219bool QgsMessageLogViewer::eventFilter( QObject *object, QEvent *event )
220{
221 switch ( event->type() )
222 {
223 case QEvent::MouseButtonPress:
224 {
225 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
226 {
227 QMouseEvent *me = static_cast<QMouseEvent *>( event );
228 mClickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) : QString();
229 if ( !mClickedAnchor.isEmpty() )
230 return true;
231 }
232 break;
233 }
234
235 case QEvent::MouseButtonRelease:
236 {
237 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
238 {
239 QMouseEvent *me = static_cast<QMouseEvent *>( event );
240 const QString clickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) : QString();
241 if ( !clickedAnchor.isEmpty() && clickedAnchor == mClickedAnchor )
242 {
243 QDesktopServices::openUrl( mClickedAnchor );
244 return true;
245 }
246 }
247 break;
248 }
249
250 default:
251 break;
252 }
253
254 return QDialog::eventFilter( object, event );
255}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:158
@ NoLevel
No level.
Definition qgis.h:163
@ Warning
Warning message.
Definition qgis.h:160
@ Critical
Critical/error message.
Definition qgis.h:161
@ Info
Information message.
Definition qgis.h:159
@ Success
Used for reporting a successful operation.
Definition qgis.h:162
StringFormat
Format of log message.
Definition qgis.h:173
@ Html
HTML message.
Definition qgis.h:175
@ PlainText
Text message.
Definition qgis.h:174
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsMessageLog * messageLog()
Returns the application's message log.
void closeEvent(QCloseEvent *e) override
bool eventFilter(QObject *obj, QEvent *ev) override
void logMessage(const QString &message, const QString &tag, Qgis::MessageLevel level, Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Logs a message to the viewer.
void showTab(const QString &tag)
Activates the tab whose title matches the given tag, if any.
QgsMessageLogViewer(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Create a new message log viewer.
Interface for logging messages from QGIS in GUI independent way.
void messageReceivedWithFormat(const QString &message, const QString &tag, Qgis::MessageLevel level, Qgis::StringFormat)
Emitted whenever the log receives a message.
Stores settings for use within QGIS.
Definition qgssettings.h:68
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.