QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 "qgsmessagelog.h"
20#include "qgssettings.h"
21#include "qgsapplication.h"
22#include "qgsdockwidget.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 ),
41 this, static_cast<void ( QgsMessageLogViewer::* )( const QString &, const QString &, Qgis::MessageLevel )>( &QgsMessageLogViewer::logMessage ) );
42
43 connect( tabWidget, &QTabWidget::tabCloseRequested, this, &QgsMessageLogViewer::closeTab );
44
45 mTabBarContextMenu = new QMenu( this );
46 tabWidget->tabBar()->setContextMenuPolicy( Qt::CustomContextMenu );
47 connect( tabWidget->tabBar(), &QWidget::customContextMenuRequested, this, &QgsMessageLogViewer::showContextMenuForTabBar );
48}
49
50void QgsMessageLogViewer::showContextMenuForTabBar( QPoint point )
51{
52 if ( point.isNull() )
53 {
54 return;
55 }
56
57 mTabBarContextMenu->clear();
58
59 const int tabIndex = tabWidget->tabBar()->tabAt( point );
60
61 QAction *actionCloseTab = new QAction( tr( "Close Tab" ), mTabBarContextMenu );
62 connect( actionCloseTab, &QAction::triggered, this, [this, tabIndex]
63 {
64 closeTab( tabIndex );
65 }
66 );
67 mTabBarContextMenu->addAction( actionCloseTab );
68
69 QAction *actionCloseOtherTabs = new QAction( tr( "Close Other Tabs" ), mTabBarContextMenu );
70 actionCloseOtherTabs->setEnabled( tabWidget->tabBar()->count() > 1 );
71 connect( actionCloseOtherTabs, &QAction::triggered, this, [this, tabIndex]
72 {
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 );
83 mTabBarContextMenu->addAction( actionCloseOtherTabs );
84
85 QAction *actionCloseAllTabs = new QAction( tr( "Close All Tabs" ), mTabBarContextMenu );
86 actionCloseAllTabs->setEnabled( tabWidget->tabBar()->count() > 0 );
87 connect( actionCloseAllTabs, &QAction::triggered, this, [this]
88 {
89 int i;
90 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
91 {
92 closeTab( i );
93 }
94 }
95 );
96 mTabBarContextMenu->addAction( actionCloseAllTabs );
97
98 mTabBarContextMenu->exec( tabWidget->tabBar()->mapToGlobal( point ) );
99}
100
102{
103 e->ignore();
104}
105
107{
108}
109
110void QgsMessageLogViewer::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
111{
112 constexpr int MESSAGE_COUNT_LIMIT = 10000;
113 // Avoid logging too many messages, which might blow memory.
114 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
115 return;
116 ++mMessageLoggedCount;
117
118 QString cleanedTag = tag;
119 if ( cleanedTag.isNull() )
120 cleanedTag = tr( "General" );
121
122 int i;
123 for ( i = 0; i < tabWidget->count() && tabWidget->tabText( i ).remove( QChar( '&' ) ) != cleanedTag; i++ );
124
125 QPlainTextEdit *w = nullptr;
126 if ( i < tabWidget->count() )
127 {
128 w = qobject_cast<QPlainTextEdit *>( tabWidget->widget( i ) );
129 tabWidget->setCurrentIndex( i );
130 }
131 else
132 {
133 w = new QPlainTextEdit( this );
134 w->setReadOnly( true );
135 w->viewport()->installEventFilter( this );
136 tabWidget->addTab( w, cleanedTag );
137 tabWidget->setCurrentIndex( tabWidget->count() - 1 );
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 {
147 case Qgis::MessageLevel::Info:
148 levelString = QStringLiteral( "INFO" );
149 colorName = settings.value( QStringLiteral( "colors/info" ), QString() ).toString();
150 break;
151 case Qgis::MessageLevel::Warning:
152 levelString = QStringLiteral( "WARNING" );
153 colorName = settings.value( QStringLiteral( "colors/warning" ), QString() ).toString();
154 break;
155 case Qgis::MessageLevel::Critical:
156 levelString = QStringLiteral( "CRITICAL" );
157 colorName = settings.value( QStringLiteral( "colors/critical" ), QString() ).toString();
158 break;
159 case Qgis::MessageLevel::Success:
160 levelString = QStringLiteral( "SUCCESS" );
161 colorName = settings.value( QStringLiteral( "colors/success" ), QString() ).toString();
162 break;
163 case Qgis::MessageLevel::NoLevel:
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;
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::closeTab( int index )
184{
185 tabWidget->removeTab( index );
186 if ( tabWidget->count() == 0 )
187 {
188 tabWidget->hide();
189 emptyLabel->show();
190 }
191}
192
193bool QgsMessageLogViewer::eventFilter( QObject *object, QEvent *event )
194{
195 switch ( event->type() )
196 {
197 case QEvent::MouseButtonPress:
198 {
199 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
200 {
201 QMouseEvent *me = static_cast< QMouseEvent *>( event );
202 mClickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) :
203 QString();
204 if ( !mClickedAnchor.isEmpty() )
205 return true;
206 }
207 break;
208 }
209
210 case QEvent::MouseButtonRelease:
211 {
212 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
213 {
214 QMouseEvent *me = static_cast< QMouseEvent *>( event );
215 const QString clickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) :
216 QString();
217 if ( !clickedAnchor.isEmpty() && clickedAnchor == mClickedAnchor )
218 {
219 QDesktopServices::openUrl( mClickedAnchor );
220 return true;
221 }
222 }
223 break;
224 }
225
226 default:
227 break;
228 }
229
230 return QDialog::eventFilter( object, event );
231}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:115
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
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.
Definition: qgsmessagelog.h:40
void messageReceived(const QString &message, const QString &tag, Qgis::MessageLevel level)
Emitted whenever the log receives a message.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.