QGIS API Documentation 3.43.0-Master (8fc5848dca1)
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#include "moc_qgsmessagelogviewer.cpp"
20#include "qgsmessagelog.h"
21#include "qgssettings.h"
22#include "qgsapplication.h"
23
24#include <QFile>
25#include <QDateTime>
26#include <QTableWidget>
27#include <QToolButton>
28#include <QStatusBar>
29#include <QToolTip>
30#include <QPlainTextEdit>
31#include <QScrollBar>
32#include <QDebug>
33#include <QDesktopServices>
34
35QgsMessageLogViewer::QgsMessageLogViewer( QWidget *parent, Qt::WindowFlags fl )
36 : QDialog( parent, fl )
37{
38 setupUi( this );
39
40 connect( QgsApplication::messageLog(), static_cast<void ( QgsMessageLog::* )( const QString &, const QString &, Qgis::MessageLevel )>( &QgsMessageLog::messageReceived ), this, static_cast<void ( QgsMessageLogViewer::* )( const QString &, const QString &, Qgis::MessageLevel )>( &QgsMessageLogViewer::logMessage ) );
41
42 connect( tabWidget, &QTabWidget::tabCloseRequested, this, &QgsMessageLogViewer::closeTab );
43
44 connect( tabWidget, &QTabWidget::currentChanged, this, [this]( int index ) {
45 tabWidget->setTabIcon( index, QIcon() );
46 } );
47
48 mTabBarContextMenu = new QMenu( this );
49 tabWidget->tabBar()->setContextMenuPolicy( Qt::CustomContextMenu );
50 connect( tabWidget->tabBar(), &QWidget::customContextMenuRequested, this, &QgsMessageLogViewer::showContextMenuForTabBar );
51}
52
53void QgsMessageLogViewer::showContextMenuForTabBar( QPoint point )
54{
55 if ( point.isNull() )
56 {
57 return;
58 }
59
60 mTabBarContextMenu->clear();
61
62 const int tabIndex = tabWidget->tabBar()->tabAt( point );
63
64 QAction *actionCloseTab = new QAction( tr( "Close Tab" ), mTabBarContextMenu );
65 connect( actionCloseTab, &QAction::triggered, this, [this, tabIndex] {
66 closeTab( tabIndex );
67 } );
68 mTabBarContextMenu->addAction( actionCloseTab );
69
70 QAction *actionCloseOtherTabs = new QAction( tr( "Close Other Tabs" ), mTabBarContextMenu );
71 actionCloseOtherTabs->setEnabled( tabWidget->tabBar()->count() > 1 );
72 connect( actionCloseOtherTabs, &QAction::triggered, this, [this, tabIndex] {
73 int i;
74 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
75 {
76 if ( i != tabIndex )
77 {
78 closeTab( i );
79 }
80 }
81 } );
82 mTabBarContextMenu->addAction( actionCloseOtherTabs );
83
84 QAction *actionCloseAllTabs = new QAction( tr( "Close All Tabs" ), mTabBarContextMenu );
85 actionCloseAllTabs->setEnabled( tabWidget->tabBar()->count() > 0 );
86 connect( actionCloseAllTabs, &QAction::triggered, this, [this] {
87 int i;
88 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
89 {
90 closeTab( i );
91 }
92 } );
93 mTabBarContextMenu->addAction( actionCloseAllTabs );
94
95 mTabBarContextMenu->exec( tabWidget->tabBar()->mapToGlobal( point ) );
96}
97
98void QgsMessageLogViewer::closeEvent( QCloseEvent *e )
99{
100 e->ignore();
101}
102
106
107void QgsMessageLogViewer::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
108{
109 constexpr int MESSAGE_COUNT_LIMIT = 10000;
110 // Avoid logging too many messages, which might blow memory.
111 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
112 return;
113 ++mMessageLoggedCount;
114
115 QString cleanedTag = tag;
116 if ( cleanedTag.isNull() )
117 cleanedTag = tr( "General" );
118
119 int i;
120 for ( i = 0; i < tabWidget->count() && tabWidget->tabText( i ).remove( QChar( '&' ) ) != cleanedTag; i++ )
121 ;
122
123 QPlainTextEdit *w = nullptr;
124 if ( i < tabWidget->count() )
125 {
126 w = qobject_cast<QPlainTextEdit *>( tabWidget->widget( i ) );
127 if ( i != tabWidget->currentIndex() )
128 {
129 tabWidget->setTabIcon( i, QgsApplication::getThemeIcon( QStringLiteral( "mMessageLog.svg" ) ) );
130 }
131 }
132 else
133 {
134 w = new QPlainTextEdit( this );
135 w->setReadOnly( true );
136 w->viewport()->installEventFilter( this );
137 i = tabWidget->addTab( w, QgsApplication::getThemeIcon( QStringLiteral( "mMessageLog.svg" ) ), cleanedTag );
138 }
139
140 QString levelString;
141 const QgsSettings settings;
142 const QPalette pal = qApp->palette();
143 const QString defaultColorName = pal.color( QPalette::WindowText ).name();
144 QString colorName;
145 switch ( level )
146 {
148 levelString = QStringLiteral( "INFO" );
149 colorName = settings.value( QStringLiteral( "colors/info" ), QString() ).toString();
150 break;
152 levelString = QStringLiteral( "WARNING" );
153 colorName = settings.value( QStringLiteral( "colors/warning" ), QString() ).toString();
154 break;
156 levelString = QStringLiteral( "CRITICAL" );
157 colorName = settings.value( QStringLiteral( "colors/critical" ), QString() ).toString();
158 break;
160 levelString = QStringLiteral( "SUCCESS" );
161 colorName = settings.value( QStringLiteral( "colors/success" ), QString() ).toString();
162 break;
164 levelString = QStringLiteral( "NONE" );
165 colorName = settings.value( QStringLiteral( "colors/default" ), QString() ).toString();
166 break;
167 }
168 const QColor color = QColor( !colorName.isEmpty() ? colorName : defaultColorName );
169
170 const QString prefix = QStringLiteral( "<font color=\"%1\">%2 &nbsp;&nbsp;&nbsp; %3 &nbsp;&nbsp;&nbsp;</font>" )
171 .arg( color.name(), QDateTime::currentDateTime().toString( Qt::ISODate ), levelString );
172 QString cleanedMessage = message.toHtmlEscaped();
173 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
174 cleanedMessage = tr( "Message log truncated" );
175
176 cleanedMessage = cleanedMessage.prepend( prefix ).replace( '\n', QLatin1String( "<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;" ) );
177 w->appendHtml( cleanedMessage );
178 w->verticalScrollBar()->setValue( w->verticalScrollBar()->maximum() );
179 tabWidget->show();
180 emptyLabel->hide();
181}
182
183void QgsMessageLogViewer::showTab( const QString &tag )
184{
185 for ( int i = 0; i < tabWidget->count(); i++ )
186 {
187 if ( tabWidget->tabText( i ).remove( QChar( '&' ) ) == tag )
188 {
189 tabWidget->setCurrentIndex( i );
190 return;
191 }
192 }
193}
194
195void QgsMessageLogViewer::closeTab( int index )
196{
197 tabWidget->removeTab( index );
198 if ( tabWidget->count() == 0 )
199 {
200 tabWidget->hide();
201 emptyLabel->show();
202 }
203}
204
205bool QgsMessageLogViewer::eventFilter( QObject *object, QEvent *event )
206{
207 switch ( event->type() )
208 {
209 case QEvent::MouseButtonPress:
210 {
211 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
212 {
213 QMouseEvent *me = static_cast<QMouseEvent *>( event );
214 mClickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) : QString();
215 if ( !mClickedAnchor.isEmpty() )
216 return true;
217 }
218 break;
219 }
220
221 case QEvent::MouseButtonRelease:
222 {
223 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
224 {
225 QMouseEvent *me = static_cast<QMouseEvent *>( event );
226 const QString clickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) : QString();
227 if ( !clickedAnchor.isEmpty() && clickedAnchor == mClickedAnchor )
228 {
229 QDesktopServices::openUrl( mClickedAnchor );
230 return true;
231 }
232 }
233 break;
234 }
235
236 default:
237 break;
238 }
239
240 return QDialog::eventFilter( object, event );
241}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:154
@ NoLevel
No level.
Definition qgis.h:159
@ Warning
Warning message.
Definition qgis.h:156
@ Critical
Critical/error message.
Definition qgis.h:157
@ Info
Information message.
Definition qgis.h:155
@ Success
Used for reporting a successful operation.
Definition qgis.h:158
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.
A generic dialog widget for displaying QGIS log messages.
void closeEvent(QCloseEvent *e) override
bool eventFilter(QObject *obj, QEvent *ev) override
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.
void logMessage(const QString &message, const QString &tag, Qgis::MessageLevel level)
Logs a message to the viewer.
Interface for logging messages from QGIS in GUI independent way.
void messageReceived(const QString &message, const QString &tag, Qgis::MessageLevel level)
Emitted whenever the log receives a message.
Stores settings for use within QGIS.
Definition qgssettings.h:65
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.