QGIS API Documentation  2.99.0-Master (f1383e2)
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 
22 #include <QWidget>
23 #include <QPalette>
24 #include <QStackedWidget>
25 #include <QProgressBar>
26 #include <QToolButton>
27 #include <QTimer>
28 #include <QGridLayout>
29 #include <QMenu>
30 #include <QMouseEvent>
31 #include <QLabel>
32 
33 QgsMessageBar::QgsMessageBar( QWidget *parent )
34  : QFrame( parent )
35  , mCurrentItem( nullptr )
36 {
37  QPalette pal = palette();
38  pal.setBrush( backgroundRole(), pal.window() );
39  setPalette( pal );
40  setAutoFillBackground( true );
41  setFrameShape( QFrame::StyledPanel );
42  setFrameShadow( QFrame::Plain );
43 
44  mLayout = new QGridLayout( this );
45  mLayout->setContentsMargins( 9, 1, 9, 1 );
46  setLayout( mLayout );
47 
48  mCountProgress = new QProgressBar( this );
49  mCountStyleSheet = QString( "QProgressBar { border: 1px solid rgba(0, 0, 0, 75%);"
50  " border-radius: 2px; background: rgba(0, 0, 0, 0);"
51  " image: url(:/images/themes/default/%1) }"
52  "QProgressBar::chunk { background-color: rgba(0, 0, 0, 30%); width: 5px; }" );
53 
54  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
55  mCountProgress->setObjectName( QStringLiteral( "mCountdown" ) );
56  mCountProgress->setFixedSize( 25, 14 );
57  mCountProgress->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
58  mCountProgress->setTextVisible( false );
59  mCountProgress->setRange( 0, 5 );
60  mCountProgress->setHidden( true );
61  mLayout->addWidget( mCountProgress, 0, 0, 1, 1 );
62 
63  mItemCount = new QLabel( this );
64  mItemCount->setObjectName( QStringLiteral( "mItemCount" ) );
65  mItemCount->setToolTip( tr( "Remaining messages" ) );
66  mItemCount->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
67  mLayout->addWidget( mItemCount, 0, 2, 1, 1 );
68 
69  mCloseMenu = new QMenu( this );
70  mCloseMenu->setObjectName( QStringLiteral( "mCloseMenu" ) );
71  mActionCloseAll = new QAction( tr( "Close all" ), this );
72  mCloseMenu->addAction( mActionCloseAll );
73  connect( mActionCloseAll, &QAction::triggered, this, &QgsMessageBar::clearWidgets );
74 
75  mCloseBtn = new QToolButton( this );
76  mCloseMenu->setObjectName( QStringLiteral( "mCloseMenu" ) );
77  mCloseBtn->setToolTip( tr( "Close" ) );
78  mCloseBtn->setMinimumWidth( 40 );
79  mCloseBtn->setStyleSheet(
80  "QToolButton { background-color: rgba(0, 0, 0, 0); }"
81  "QToolButton::menu-button { background-color: rgba(0, 0, 0, 0); }" );
82  mCloseBtn->setCursor( Qt::PointingHandCursor );
83  mCloseBtn->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconClose.svg" ) ) );
84  mCloseBtn->setIconSize( QSize( 18, 18 ) );
85  mCloseBtn->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum );
86  mCloseBtn->setMenu( mCloseMenu );
87  mCloseBtn->setPopupMode( QToolButton::MenuButtonPopup );
88  connect( mCloseBtn, &QAbstractButton::clicked, this, static_cast < bool ( QgsMessageBar::* )( ) > ( &QgsMessageBar::popWidget ) );
89  mLayout->addWidget( mCloseBtn, 0, 3, 1, 1 );
90 
91  mCountdownTimer = new QTimer( this );
92  mCountdownTimer->setInterval( 1000 );
93  connect( mCountdownTimer, &QTimer::timeout, this, &QgsMessageBar::updateCountdown );
94 
95  connect( this, &QgsMessageBar::widgetAdded, this, &QgsMessageBar::updateItemCount );
96  connect( this, &QgsMessageBar::widgetRemoved, this, &QgsMessageBar::updateItemCount );
97 
98  // start hidden
99  setVisible( false );
100 }
101 
102 void QgsMessageBar::mousePressEvent( QMouseEvent *e )
103 {
104  if ( mCountProgress == childAt( e->pos() ) && e->button() == Qt::LeftButton )
105  {
106  if ( mCountdownTimer->isActive() )
107  {
108  mCountdownTimer->stop();
109  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerContinue.png" ) ) );
110  }
111  else
112  {
113  mCountdownTimer->start();
114  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
115  }
116  }
117 }
118 
119 void QgsMessageBar::popItem( QgsMessageBarItem *item )
120 {
121  Q_ASSERT( item );
122 
123  if ( item != mCurrentItem && !mItems.contains( item ) )
124  return;
125 
126  if ( item == mCurrentItem )
127  {
128  if ( mCurrentItem )
129  {
130  QWidget *widget = mCurrentItem;
131  mLayout->removeWidget( widget );
132  mCurrentItem->hide();
133  disconnect( mCurrentItem, &QgsMessageBarItem::styleChanged, this, &QWidget::setStyleSheet );
134  delete mCurrentItem;
135  mCurrentItem = nullptr;
136  }
137 
138  if ( !mItems.isEmpty() )
139  {
140  showItem( mItems.at( 0 ) );
141  }
142  else
143  {
144  hide();
145  }
146  }
147  else
148  {
149  mItems.removeOne( item );
150  }
151 
152  emit widgetRemoved( item );
153 }
154 
156 {
157  if ( !item || !mCurrentItem )
158  return false;
159 
160  if ( item == mCurrentItem )
161  {
162  popItem( mCurrentItem );
163  return true;
164  }
165 
166  Q_FOREACH ( QgsMessageBarItem *existingItem, mItems )
167  {
168  if ( existingItem == item )
169  {
170  mItems.removeOne( existingItem );
171  delete existingItem;
172  return true;
173  }
174  }
175 
176  return false;
177 }
178 
180 {
181  if ( !mCurrentItem )
182  return false;
183 
184  resetCountdown();
185 
186  QgsMessageBarItem *item = mCurrentItem;
187  popItem( item );
188 
189  return true;
190 }
191 
193 {
194  if ( !mCurrentItem && mItems.empty() )
195  return true;
196 
197  while ( !mItems.isEmpty() )
198  {
199  popWidget();
200  }
201  popWidget();
202 
203  return !mCurrentItem && mItems.empty();
204 }
205 
206 void QgsMessageBar::pushSuccess( const QString &title, const QString &message )
207 {
208  pushMessage( title, message, SUCCESS );
209 }
210 
211 void QgsMessageBar::pushInfo( const QString &title, const QString &message )
212 {
213  pushMessage( title, message, INFO );
214 }
215 
216 void QgsMessageBar::pushWarning( const QString &title, const QString &message )
217 {
218  pushMessage( title, message, WARNING );
219 }
220 
221 void QgsMessageBar::pushCritical( const QString &title, const QString &message )
222 {
223  pushMessage( title, message, CRITICAL );
224 }
225 
226 void QgsMessageBar::showItem( QgsMessageBarItem *item )
227 {
228  Q_ASSERT( item );
229 
230  if ( mCurrentItem )
231  disconnect( mCurrentItem, &QgsMessageBarItem::styleChanged, this, &QWidget::setStyleSheet );
232 
233  if ( item == mCurrentItem )
234  return;
235 
236  if ( mItems.contains( item ) )
237  mItems.removeOne( item );
238 
239  if ( mCurrentItem )
240  {
241  mItems.prepend( mCurrentItem );
242  mLayout->removeWidget( mCurrentItem );
243  mCurrentItem->hide();
244  }
245 
246  mCurrentItem = item;
247  mLayout->addWidget( item, 0, 1, 1, 1 );
248  mCurrentItem->show();
249 
250  if ( item->duration() > 0 )
251  {
252  mCountProgress->setRange( 0, item->duration() );
253  mCountProgress->setValue( item->duration() );
254  mCountProgress->setVisible( true );
255  mCountdownTimer->start();
256  }
257 
258  connect( mCurrentItem, &QgsMessageBarItem::styleChanged, this, &QWidget::setStyleSheet );
259  setStyleSheet( item->getStyleSheet() );
260  show();
261 
262  emit widgetAdded( item );
263 }
264 
266 {
267  resetCountdown();
268  // avoid duplicated widget
269  popWidget( item );
270  showItem( item );
271 }
272 
274 {
275  QgsMessageBarItem *item = nullptr;
276  item = dynamic_cast<QgsMessageBarItem *>( widget );
277  if ( item )
278  {
279  item->setLevel( level )->setDuration( duration );
280  }
281  else
282  {
283  item = new QgsMessageBarItem( widget, level, duration );
284  }
285  pushItem( item );
286  return item;
287 }
288 
289 void QgsMessageBar::pushMessage( const QString &title, const QString &text, QgsMessageBar::MessageLevel level, int duration )
290 {
291  QgsMessageBarItem *item = new QgsMessageBarItem( title, text, level, duration );
292  pushItem( item );
293 }
294 
295 QgsMessageBarItem *QgsMessageBar::createMessage( const QString &text, QWidget *parent )
296 {
297  QgsMessageBarItem *item = new QgsMessageBarItem( text, INFO, 0, parent );
298  return item;
299 }
300 
301 QgsMessageBarItem *QgsMessageBar::createMessage( const QString &title, const QString &text, QWidget *parent )
302 {
303  return new QgsMessageBarItem( title, text, QgsMessageBar::INFO, 0, parent );
304 }
305 
306 QgsMessageBarItem *QgsMessageBar::createMessage( QWidget *widget, QWidget *parent )
307 {
308  return new QgsMessageBarItem( widget, INFO, 0, parent );
309 }
310 
311 void QgsMessageBar::updateCountdown()
312 {
313  if ( !mCountdownTimer->isActive() )
314  {
315  resetCountdown();
316  return;
317  }
318  if ( mCountProgress->value() < 2 )
319  {
320  popWidget();
321  }
322  else
323  {
324  mCountProgress->setValue( mCountProgress->value() - 1 );
325  }
326 }
327 
328 void QgsMessageBar::resetCountdown()
329 {
330  if ( mCountdownTimer->isActive() )
331  mCountdownTimer->stop();
332 
333  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
334  mCountProgress->setVisible( false );
335 }
336 
337 void QgsMessageBar::updateItemCount()
338 {
339  mItemCount->setText( !mItems.isEmpty() ? tr( "%n more", "unread messages", mItems.count() ) : QString() );
340 
341  // do not show the down arrow for opening menu with "close all" if there is just one message
342  mCloseBtn->setMenu( !mItems.isEmpty() ? mCloseMenu : nullptr );
343  mCloseBtn->setPopupMode( !mItems.isEmpty() ? QToolButton::MenuButtonPopup : QToolButton::DelayedPopup );
344 }
void mousePressEvent(QMouseEvent *e) override
void pushInfo(const QString &title, const QString &message)
Pushes a information message with default timeout to the message bar.
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:44
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.
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:91
void pushWarning(const QString &title, const QString &message)
Pushes a warning with default timeout to the message bar.
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
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.