QGIS API Documentation  2.99.0-Master (e077efd)
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, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( clicked() ), this, SLOT( popWidget() ) );
89  mLayout->addWidget( mCloseBtn, 0, 3, 1, 1 );
90 
91  mCountdownTimer = new QTimer( this );
92  mCountdownTimer->setInterval( 1000 );
93  connect( mCountdownTimer, SIGNAL( timeout() ), this, SLOT( updateCountdown() ) );
94 
95  connect( this, SIGNAL( widgetAdded( QgsMessageBarItem* ) ), this, SLOT( updateItemCount() ) );
96  connect( this, SIGNAL( widgetRemoved( QgsMessageBarItem* ) ), this, SLOT( updateItemCount() ) );
97 
98  // start hidden
99  setVisible( false );
100 }
101 
103 {
104 }
105 
106 void QgsMessageBar::mousePressEvent( QMouseEvent * e )
107 {
108  if ( mCountProgress == childAt( e->pos() ) && e->button() == Qt::LeftButton )
109  {
110  if ( mCountdownTimer->isActive() )
111  {
112  mCountdownTimer->stop();
113  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerContinue.png" ) ) );
114  }
115  else
116  {
117  mCountdownTimer->start();
118  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
119  }
120  }
121 }
122 
123 void QgsMessageBar::popItem( QgsMessageBarItem *item )
124 {
125  Q_ASSERT( item );
126 
127  if ( item != mCurrentItem && !mItems.contains( item ) )
128  return;
129 
130  if ( item == mCurrentItem )
131  {
132  if ( mCurrentItem )
133  {
134  QWidget *widget = mCurrentItem;
135  mLayout->removeWidget( widget );
136  mCurrentItem->hide();
137  disconnect( mCurrentItem, SIGNAL( styleChanged( QString ) ), this, SLOT( setStyleSheet( QString ) ) );
138  delete mCurrentItem;
139  mCurrentItem = nullptr;
140  }
141 
142  if ( !mItems.isEmpty() )
143  {
144  showItem( mItems.at( 0 ) );
145  }
146  else
147  {
148  hide();
149  }
150  }
151  else
152  {
153  mItems.removeOne( item );
154  }
155 
156  emit widgetRemoved( item );
157 }
158 
160 {
161  if ( !item || !mCurrentItem )
162  return false;
163 
164  if ( item == mCurrentItem )
165  {
166  popItem( mCurrentItem );
167  return true;
168  }
169 
170  Q_FOREACH ( QgsMessageBarItem *existingItem, mItems )
171  {
172  if ( existingItem == item )
173  {
174  mItems.removeOne( existingItem );
175  delete existingItem;
176  return true;
177  }
178  }
179 
180  return false;
181 }
182 
184 {
185  if ( !mCurrentItem )
186  return false;
187 
188  resetCountdown();
189 
190  QgsMessageBarItem *item = mCurrentItem;
191  popItem( item );
192 
193  return true;
194 }
195 
197 {
198  if ( !mCurrentItem && mItems.empty() )
199  return true;
200 
201  while ( !mItems.isEmpty() )
202  {
203  popWidget();
204  }
205  popWidget();
206 
207  return !mCurrentItem && mItems.empty();
208 }
209 
210 void QgsMessageBar::pushSuccess( const QString& title, const QString& message )
211 {
212  pushMessage( title, message, SUCCESS );
213 }
214 
215 void QgsMessageBar::pushInfo( const QString& title, const QString& message )
216 {
217  pushMessage( title, message, INFO );
218 }
219 
220 void QgsMessageBar::pushWarning( const QString& title, const QString& message )
221 {
222  pushMessage( title, message, WARNING );
223 }
224 
225 void QgsMessageBar::pushCritical( const QString& title, const QString& message )
226 {
227  pushMessage( title, message, CRITICAL );
228 }
229 
230 void QgsMessageBar::showItem( QgsMessageBarItem *item )
231 {
232  Q_ASSERT( item );
233 
234  if ( mCurrentItem )
235  disconnect( mCurrentItem, SIGNAL( styleChanged( QString ) ), this, SLOT( setStyleSheet( QString ) ) );
236 
237  if ( item == mCurrentItem )
238  return;
239 
240  if ( mItems.contains( item ) )
241  mItems.removeOne( item );
242 
243  if ( mCurrentItem )
244  {
245  mItems.prepend( mCurrentItem );
246  mLayout->removeWidget( mCurrentItem );
247  mCurrentItem->hide();
248  }
249 
250  mCurrentItem = item;
251  mLayout->addWidget( item, 0, 1, 1, 1 );
252  mCurrentItem->show();
253 
254  if ( item->duration() > 0 )
255  {
256  mCountProgress->setRange( 0, item->duration() );
257  mCountProgress->setValue( item->duration() );
258  mCountProgress->setVisible( true );
259  mCountdownTimer->start();
260  }
261 
262  connect( mCurrentItem, SIGNAL( styleChanged( QString ) ), this, SLOT( setStyleSheet( QString ) ) );
263  setStyleSheet( item->getStyleSheet() );
264  show();
265 
266  emit widgetAdded( item );
267 }
268 
270 {
271  resetCountdown();
272  // avoid duplicated widget
273  popWidget( item );
274  showItem( item );
275 }
276 
278 {
279  QgsMessageBarItem *item;
280  item = dynamic_cast<QgsMessageBarItem*>( widget );
281  if ( item )
282  {
283  item->setLevel( level )->setDuration( duration );
284  }
285  else
286  {
287  item = new QgsMessageBarItem( widget, level, duration );
288  }
289  pushItem( item );
290  return item;
291 }
292 
293 void QgsMessageBar::pushMessage( const QString &title, const QString &text, QgsMessageBar::MessageLevel level, int duration )
294 {
295  QgsMessageBarItem *item = new QgsMessageBarItem( title, text, level, duration );
296  pushItem( item );
297 }
298 
299 QgsMessageBarItem* QgsMessageBar::createMessage( const QString &text, QWidget *parent )
300 {
301  QgsMessageBarItem* item = new QgsMessageBarItem( text, INFO, 0, parent );
302  return item;
303 }
304 
305 QgsMessageBarItem* QgsMessageBar::createMessage( const QString &title, const QString &text, QWidget *parent )
306 {
307  return new QgsMessageBarItem( title, text, QgsMessageBar::INFO, 0, parent );
308 }
309 
310 QgsMessageBarItem* QgsMessageBar::createMessage( QWidget *widget, QWidget *parent )
311 {
312  return new QgsMessageBarItem( widget, INFO, 0, parent );
313 }
314 
315 void QgsMessageBar::updateCountdown()
316 {
317  if ( !mCountdownTimer->isActive() )
318  {
319  resetCountdown();
320  return;
321  }
322  if ( mCountProgress->value() < 2 )
323  {
324  popWidget();
325  }
326  else
327  {
328  mCountProgress->setValue( mCountProgress->value() - 1 );
329  }
330 }
331 
332 void QgsMessageBar::resetCountdown()
333 {
334  if ( mCountdownTimer->isActive() )
335  mCountdownTimer->stop();
336 
337  mCountProgress->setStyleSheet( mCountStyleSheet.arg( QStringLiteral( "mIconTimerPause.png" ) ) );
338  mCountProgress->setVisible( false );
339 }
340 
341 void QgsMessageBar::updateItemCount()
342 {
343  mItemCount->setText( !mItems.isEmpty() ? tr( "%n more", "unread messages", mItems.count() ) : QString() );
344 
345  // do not show the down arrow for opening menu with "close all" if there is just one message
346  mCloseBtn->setMenu( !mItems.isEmpty() ? mCloseMenu : nullptr );
347  mCloseBtn->setPopupMode( !mItems.isEmpty() ? QToolButton::MenuButtonPopup : QToolButton::DelayedPopup );
348 }
QgsMessageBar(QWidget *parent=nullptr)
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
static QIcon getThemeIcon(const QString &theName)
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:90
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)
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.