26#include <QDesktopServices>
28#include <QPlainTextEdit>
32#include <QTableWidget>
36#include "moc_qgsmessagelogviewer.cpp"
38using namespace Qt::StringLiterals;
41 : QDialog( parent, fl )
52 connect( tabWidget, &QTabWidget::tabCloseRequested,
this, &QgsMessageLogViewer::closeTab );
54 connect( tabWidget, &QTabWidget::currentChanged,
this, [
this](
int index ) { tabWidget->setTabIcon( index, QIcon() ); } );
56 mTabBarContextMenu =
new QMenu(
this );
57 tabWidget->tabBar()->setContextMenuPolicy( Qt::CustomContextMenu );
58 connect( tabWidget->tabBar(), &QWidget::customContextMenuRequested,
this, &QgsMessageLogViewer::showContextMenuForTabBar );
61void QgsMessageLogViewer::showContextMenuForTabBar( QPoint point )
68 mTabBarContextMenu->clear();
70 const int tabIndex = tabWidget->tabBar()->tabAt( point );
72 QAction *actionCloseTab =
new QAction( tr(
"Close Tab" ), mTabBarContextMenu );
73 connect( actionCloseTab, &QAction::triggered,
this, [
this, tabIndex] { closeTab( tabIndex ); } );
74 mTabBarContextMenu->addAction( actionCloseTab );
76 QAction *actionCloseOtherTabs =
new QAction( tr(
"Close Other Tabs" ), mTabBarContextMenu );
77 actionCloseOtherTabs->setEnabled( tabWidget->tabBar()->count() > 1 );
78 connect( actionCloseOtherTabs, &QAction::triggered,
this, [
this, tabIndex] {
80 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
88 mTabBarContextMenu->addAction( actionCloseOtherTabs );
90 QAction *actionCloseAllTabs =
new QAction( tr(
"Close All Tabs" ), mTabBarContextMenu );
91 actionCloseAllTabs->setEnabled( tabWidget->tabBar()->count() > 0 );
92 connect( actionCloseAllTabs, &QAction::triggered,
this, [
this] {
94 for ( i = tabWidget->tabBar()->count() - 1; i >= 0; i-- )
99 mTabBarContextMenu->addAction( actionCloseAllTabs );
101 mTabBarContextMenu->exec( tabWidget->tabBar()->mapToGlobal( point ) );
114 constexpr int MESSAGE_COUNT_LIMIT = 10000;
116 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
118 ++mMessageLoggedCount;
120 QString cleanedTag = tag;
121 if ( cleanedTag.isNull() )
122 cleanedTag = tr(
"General" );
125 for ( i = 0; i < tabWidget->count() && tabWidget->tabText( i ).remove( QChar(
'&' ) ) != cleanedTag; i++ )
128 QPlainTextEdit *w =
nullptr;
129 if ( i < tabWidget->count() )
131 w = qobject_cast<QPlainTextEdit *>( tabWidget->widget( i ) );
132 if ( i != tabWidget->currentIndex() )
139 w =
new QPlainTextEdit(
this );
140 w->setReadOnly(
true );
141 w->viewport()->installEventFilter(
this );
147 const QPalette
pal = qApp->palette();
148 const QString defaultColorName =
pal.color( QPalette::WindowText ).name();
153 levelString = u
"INFO"_s;
154 colorName = settings.
value( u
"colors/info"_s, QString() ).toString();
157 levelString = u
"WARNING"_s;
158 colorName = settings.
value( u
"colors/warning"_s, QString() ).toString();
161 levelString = u
"CRITICAL"_s;
162 colorName = settings.
value( u
"colors/critical"_s, QString() ).toString();
165 levelString = u
"SUCCESS"_s;
166 colorName = settings.
value( u
"colors/success"_s, QString() ).toString();
169 levelString = u
"NONE"_s;
170 colorName = settings.
value( u
"colors/default"_s, QString() ).toString();
173 const QColor color = QColor( !colorName.isEmpty() ? colorName : defaultColorName );
175 const QString prefix = u
"<font color=\"%1\">%2 %3 </font>"_s.arg( color.name(), QDateTime::currentDateTime().toString( Qt::ISODate ), levelString );
176 QString cleanedMessage;
180 cleanedMessage = message.toHtmlEscaped();
183 cleanedMessage = message;
186 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
187 cleanedMessage = tr(
"Message log truncated" );
189 cleanedMessage = cleanedMessage.prepend( prefix ).replace(
'\n',
"<br> "_L1 );
190 w->appendHtml( cleanedMessage );
191 w->verticalScrollBar()->setValue( w->verticalScrollBar()->maximum() );
198 for (
int i = 0; i < tabWidget->count(); i++ )
200 if ( tabWidget->tabText( i ).remove( QChar(
'&' ) ) == tag )
202 tabWidget->setCurrentIndex( i );
208void QgsMessageLogViewer::closeTab(
int index )
210 tabWidget->removeTab( index );
211 if ( tabWidget->count() == 0 )
220 switch ( event->type() )
222 case QEvent::MouseButtonPress:
224 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
226 QMouseEvent *me =
static_cast<QMouseEvent *
>( event );
227 mClickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) : QString();
228 if ( !mClickedAnchor.isEmpty() )
234 case QEvent::MouseButtonRelease:
236 if ( QPlainTextEdit *te = qobject_cast<QPlainTextEdit *>( object->parent() ) )
238 QMouseEvent *me =
static_cast<QMouseEvent *
>( event );
239 const QString clickedAnchor = ( me->button() & Qt::LeftButton ) ? te->anchorAt( me->pos() ) : QString();
240 if ( !clickedAnchor.isEmpty() && clickedAnchor == mClickedAnchor )
242 QDesktopServices::openUrl( mClickedAnchor );
253 return QDialog::eventFilter(
object, event );
MessageLevel
Level for messages This will be used both for message log and message bar in application.
@ Warning
Warning message.
@ Critical
Critical/error message.
@ Info
Information message.
@ Success
Used for reporting a successful operation.
StringFormat
Format of log message.
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.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.