QGIS API Documentation  2.99.0-Master (314842d)
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 
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, SIGNAL( styleChanged( QString ) ), this, SLOT( setStyleSheet( QString ) ) );
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, SIGNAL( styleChanged( QString ) ), this, SLOT( setStyleSheet( QString ) ) );
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, SIGNAL( styleChanged( QString ) ), this, SLOT( setStyleSheet( QString ) ) );
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 }
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 &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: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.