QGIS API Documentation  2.99.0-Master (cd0ba91)
qgsmessagebar.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmessagebar.cpp - description
3  -------------------
4  begin : June 2012
5  copyright : (C) 2012 by Giuseppe Sucameli
6  email : sucameli at faunalia dot it
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 "qgsmessagebar.h"
19 #include "qgsmessagebaritem.h"
20 #include "qgsapplication.h"
21 #include "qgsmessagelog.h"
22 
23 #include <QWidget>
24 #include <QPalette>
25 #include <QStackedWidget>
26 #include <QProgressBar>
27 #include <QToolButton>
28 #include <QTimer>
29 #include <QGridLayout>
30 #include <QMenu>
31 #include <QMouseEvent>
32 #include <QLabel>
33 
34 QgsMessageBar::QgsMessageBar( QWidget *parent )
35  : QFrame( parent )
36 
37 {
38  QPalette pal = palette();
39  pal.setBrush( backgroundRole(), pal.window() );
40  setPalette( pal );
41  setAutoFillBackground( true );
42  setFrameShape( QFrame::StyledPanel );
43  setFrameShadow( QFrame::Plain );
44 
45  mLayout = new QGridLayout( this );
46  mLayout->setContentsMargins( 9, 1, 9, 1 );
47  setLayout( mLayout );
48 
49  mCountProgress = new QProgressBar( this );
50  mCountStyleSheet = QString( "QProgressBar { border: 1px solid rgba(0, 0, 0, 75%);"
51  " border-radius: 2px; background: rgba(0, 0, 0, 0);"
52  " image: url(:/images/themes/default/%1) }"
53  "QProgressBar::chunk { background-color: rgba(0, 0, 0, 30%); width: 5px; }" );
54 
55  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
56  mCountProgress->setObjectName( QStringLiteral( "mCountdown" ) );
57  mCountProgress->setFixedSize( 25, 14 );
58  mCountProgress->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
59  mCountProgress->setTextVisible( false );
60  mCountProgress->setRange( 0, 5 );
61  mCountProgress->setHidden( true );
62  mLayout->addWidget( mCountProgress, 0, 0, 1, 1 );
63 
64  mItemCount = new QLabel( this );
65  mItemCount->setObjectName( QStringLiteral( "mItemCount" ) );
66  mItemCount->setToolTip( tr( "Remaining messages" ) );
67  mItemCount->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
68  mLayout->addWidget( mItemCount, 0, 2, 1, 1 );
69 
70  mCloseMenu = new QMenu( this );
71  mCloseMenu->setObjectName( QStringLiteral( "mCloseMenu" ) );
72  mActionCloseAll = new QAction( tr( "Close all" ), this );
73  mCloseMenu->addAction( mActionCloseAll );
74  connect( mActionCloseAll, &QAction::triggered, this, &QgsMessageBar::clearWidgets );
75 
76  mCloseBtn = new QToolButton( this );
77  mCloseMenu->setObjectName( QStringLiteral( "mCloseMenu" ) );
78  mCloseBtn->setToolTip( tr( "Close" ) );
79  mCloseBtn->setMinimumWidth( 40 );
80  mCloseBtn->setStyleSheet(
81  "QToolButton { background-color: rgba(0, 0, 0, 0); }"
82  "QToolButton::menu-button { background-color: rgba(0, 0, 0, 0); }" );
83  mCloseBtn->setCursor( Qt::PointingHandCursor );
84  mCloseBtn->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconClose.svg" ) ) );
85  mCloseBtn->setIconSize( QSize( 18, 18 ) );
86  mCloseBtn->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum );
87  mCloseBtn->setMenu( mCloseMenu );
88  mCloseBtn->setPopupMode( QToolButton::MenuButtonPopup );
89  connect( mCloseBtn, &QAbstractButton::clicked, this, static_cast < bool ( QgsMessageBar::* )() > ( &QgsMessageBar::popWidget ) );
90  mLayout->addWidget( mCloseBtn, 0, 3, 1, 1 );
91 
92  mCountdownTimer = new QTimer( this );
93  mCountdownTimer->setInterval( 1000 );
94  connect( mCountdownTimer, &QTimer::timeout, this, &QgsMessageBar::updateCountdown );
95 
96  connect( this, &QgsMessageBar::widgetAdded, this, &QgsMessageBar::updateItemCount );
97  connect( this, &QgsMessageBar::widgetRemoved, this, &QgsMessageBar::updateItemCount );
98 
99  // start hidden
100  setVisible( false );
101 }
102 
103 void QgsMessageBar::mousePressEvent( QMouseEvent *e )
104 {
105  if ( mCountProgress == childAt( e->pos() ) && e->button() == Qt::LeftButton )
106  {
107  if ( mCountdownTimer->isActive() )
108  {
109  mCountdownTimer->stop();
110  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerContinue.png" ) ) );
111  }
112  else
113  {
114  mCountdownTimer->start();
115  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
116  }
117  }
118 }
119 
120 void QgsMessageBar::popItem( QgsMessageBarItem *item )
121 {
122  Q_ASSERT( item );
123 
124  if ( item != mCurrentItem && !mItems.contains( item ) )
125  return;
126 
127  if ( item == mCurrentItem )
128  {
129  if ( mCurrentItem )
130  {
131  QWidget *widget = mCurrentItem;
132  mLayout->removeWidget( widget );
133  mCurrentItem->hide();
134  disconnect( mCurrentItem, &QgsMessageBarItem::styleChanged, this, &QWidget::setStyleSheet );
135  mCurrentItem->deleteLater();
136  mCurrentItem = nullptr;
137  }
138 
139  if ( !mItems.isEmpty() )
140  {
141  showItem( mItems.at( 0 ) );
142  }
143  else
144  {
145  hide();
146  }
147  }
148  else
149  {
150  mItems.removeOne( item );
151  }
152 
153  emit widgetRemoved( item );
154 }
155 
157 {
158  if ( !item || !mCurrentItem )
159  return false;
160 
161  if ( item == mCurrentItem )
162  {
163  popItem( mCurrentItem );
164  return true;
165  }
166 
167  Q_FOREACH ( QgsMessageBarItem *existingItem, mItems )
168  {
169  if ( existingItem == item )
170  {
171  mItems.removeOne( existingItem );
172  existingItem->deleteLater();
173  return true;
174  }
175  }
176 
177  return false;
178 }
179 
181 {
182  if ( !mCurrentItem )
183  return false;
184 
185  resetCountdown();
186 
187  QgsMessageBarItem *item = mCurrentItem;
188  popItem( item );
189 
190  return true;
191 }
192 
194 {
195  if ( !mCurrentItem && mItems.empty() )
196  return true;
197 
198  while ( !mItems.isEmpty() )
199  {
200  popWidget();
201  }
202  popWidget();
203 
204  return !mCurrentItem && mItems.empty();
205 }
206 
207 void QgsMessageBar::pushSuccess( const QString &title, const QString &message )
208 {
209  pushMessage( title, message, SUCCESS );
210 }
211 
212 void QgsMessageBar::pushInfo( const QString &title, const QString &message )
213 {
214  pushMessage( title, message, INFO );
215 }
216 
217 void QgsMessageBar::pushWarning( const QString &title, const QString &message )
218 {
219  pushMessage( title, message, WARNING );
220 }
221 
222 void QgsMessageBar::pushCritical( const QString &title, const QString &message )
223 {
224  pushMessage( title, message, CRITICAL );
225 }
226 
227 void QgsMessageBar::showItem( QgsMessageBarItem *item )
228 {
229  Q_ASSERT( item );
230 
231  if ( mCurrentItem )
232  disconnect( mCurrentItem, &QgsMessageBarItem::styleChanged, this, &QWidget::setStyleSheet );
233 
234  if ( item == mCurrentItem )
235  return;
236 
237  if ( mItems.contains( item ) )
238  mItems.removeOne( item );
239 
240  if ( mCurrentItem )
241  {
242  mItems.prepend( mCurrentItem );
243  mLayout->removeWidget( mCurrentItem );
244  mCurrentItem->hide();
245  }
246 
247  mCurrentItem = item;
248  mLayout->addWidget( item, 0, 1, 1, 1 );
249  mCurrentItem->show();
250 
251  if ( item->duration() > 0 )
252  {
253  mCountProgress->setRange( 0, item->duration() );
254  mCountProgress->setValue( item->duration() );
255  mCountProgress->setVisible( true );
256  mCountdownTimer->start();
257  }
258 
259  connect( mCurrentItem, &QgsMessageBarItem::styleChanged, this, &QWidget::setStyleSheet );
260  setStyleSheet( item->getStyleSheet() );
261  show();
262 
263  emit widgetAdded( item );
264 }
265 
267 {
268  resetCountdown();
269  // avoid duplicated widget
270  popWidget( item );
271  showItem( item );
272 
273  // Log all messages that are sent to the message bar into the message log so the
274  // user can get them back easier.
275  QString formattedTitle = QStringLiteral( "%1 : %2" ).arg( item->title(), item->text() );
277  switch ( item->level() )
278  {
279  case QgsMessageBar::INFO:
280  level = QgsMessageLog::INFO;
281  break;
283  level = QgsMessageLog::WARNING;
284  break;
286  level = QgsMessageLog::CRITICAL;
287  break;
288  default:
289  level = QgsMessageLog::NONE;
290  break;
291  }
292  QgsMessageLog::logMessage( formattedTitle, tr( "Messages" ), level );
293 }
294 
296 {
297  QgsMessageBarItem *item = nullptr;
298  item = dynamic_cast<QgsMessageBarItem *>( widget );
299  if ( item )
300  {
301  item->setLevel( level )->setDuration( duration );
302  }
303  else
304  {
305  item = new QgsMessageBarItem( widget, level, duration );
306  }
307  pushItem( item );
308  return item;
309 }
310 
311 void QgsMessageBar::pushMessage( const QString &title, const QString &text, QgsMessageBar::MessageLevel level, int duration )
312 {
313  QgsMessageBarItem *item = new QgsMessageBarItem( title, text, level, duration );
314  pushItem( item );
315 }
316 
317 QgsMessageBarItem *QgsMessageBar::createMessage( const QString &text, QWidget *parent )
318 {
319  QgsMessageBarItem *item = new QgsMessageBarItem( text, INFO, 0, parent );
320  return item;
321 }
322 
323 QgsMessageBarItem *QgsMessageBar::createMessage( const QString &title, const QString &text, QWidget *parent )
324 {
325  return new QgsMessageBarItem( title, text, QgsMessageBar::INFO, 0, parent );
326 }
327 
328 QgsMessageBarItem *QgsMessageBar::createMessage( QWidget *widget, QWidget *parent )
329 {
330  return new QgsMessageBarItem( widget, INFO, 0, parent );
331 }
332 
333 void QgsMessageBar::updateCountdown()
334 {
335  if ( !mCountdownTimer->isActive() )
336  {
337  resetCountdown();
338  return;
339  }
340  if ( mCountProgress->value() < 2 )
341  {
342  popWidget();
343  }
344  else
345  {
346  mCountProgress->setValue( mCountProgress->value() - 1 );
347  }
348 }
349 
350 void QgsMessageBar::resetCountdown()
351 {
352  if ( mCountdownTimer->isActive() )
353  mCountdownTimer->stop();
354 
355  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
356  mCountProgress->setVisible( false );
357 }
358 
359 void QgsMessageBar::updateItemCount()
360 {
361  mItemCount->setText( !mItems.isEmpty() ? tr( "%n more", "unread messages", mItems.count() ) : QString() );
362 
363  // do not show the down arrow for opening menu with "close all" if there is just one message
364  mCloseBtn->setMenu( !mItems.isEmpty() ? mCloseMenu : nullptr );
365  mCloseBtn->setPopupMode( !mItems.isEmpty() ? QToolButton::MenuButtonPopup : QToolButton::DelayedPopup );
366 }
void mousePressEvent(QMouseEvent *e) override
void pushInfo(const QString &title, const QString &message)
Pushes a information message with default timeout to the message bar.
QString title() const
Returns the title for the message.
void widgetRemoved(QgsMessageBarItem *item)
emitted when a message widget was removed from the bar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:45
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
bool clearWidgets()
Remove all items from the bar&#39;s widget list.
int duration() const
returns the duration in second of the message
void pushSuccess(const QString &title, const QString &message)
Pushes a success message with default timeout to the message bar.
QgsMessageBar::MessageLevel level() const
Returns the message level for the message.
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
make out a widget containing a message to be displayed on the bar
void pushMessage(const QString &text, MessageLevel level=INFO, int duration=5)
convenience method for pushing a message to the bar
Definition: qgsmessagebar.h:94
void pushWarning(const QString &title, const QString &message)
Pushes a warning with default timeout to the message bar.
QString text() const
Returns the text for the message.
void widgetAdded(QgsMessageBarItem *item)
emitted when a message widget is added to the bar
QgsMessageBarItem * pushWidget(QWidget *widget, MessageLevel level=INFO, int duration=0)
Display a widget as a message on the bar after hiding the currently visible one and putting it in a s...
QString getStyleSheet()
returns the styleSheet
static void logMessage(const QString &message, const QString &tag=QString(), MessageLevel level=QgsMessageLog::WARNING)
add a message to the instance (and create it if necessary)
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar after hiding the currently visible one and putting it in a stack...
QgsMessageBarItem * setLevel(QgsMessageBar::MessageLevel level)
QgsMessageBarItem * setDuration(int duration)
QgsMessageBar(QWidget *parent=0)
void styleChanged(const QString &styleSheet)
emitted when the message level has changed
bool popWidget()
Remove the currently displayed widget from the bar and display the next in the stack if any or hide t...
void pushCritical(const QString &title, const QString &message)
Pushes a critical warning with default timeout to the message bar.