QGIS API Documentation
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 
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( "mIconTimerPause.png" ) );
55  mCountProgress->setObjectName( "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( "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( "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( "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( "/mIconClose.png" ) );
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 
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( "mIconTimerContinue.png" ) );
114  }
115  else
116  {
117  mCountdownTimer->start();
118  mCountProgress->setStyleSheet( mCountStyleSheet.arg( "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 
300 {
301  QgsMessageBarItem* item = new QgsMessageBarItem( text, INFO, 0, parent );
302  return item;
303 }
304 
306 {
307  return new QgsMessageBarItem( title, text, QgsMessageBar::INFO, 0, parent );
308 }
309 
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( "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 }
void setInterval(int msec)
void setBrush(ColorRole role, const QBrush &brush)
void pushMessage(const QString &text, MessageLevel level=INFO, int duration=0)
convenience method for pushing a message to the bar
Definition: qgsmessagebar.h:90
void setStyleSheet(const QString &styleSheet)
QgsMessageBar(QWidget *parent=nullptr)
void setMenu(QMenu *menu)
void setContentsMargins(int left, int top, int right, int bottom)
const QPalette & palette() const
void setCursor(const QCursor &)
void mousePressEvent(QMouseEvent *e) override
void addWidget(QWidget *widget, int row, int column, QFlags< Qt::AlignmentFlag > alignment)
void pushInfo(const QString &title, const QString &message)
Pushes a information message with default timeout to the message bar.
void setFrameShape(Shape)
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.
void setMinimumWidth(int minw)
QWidget * childAt(int x, int y) const
const T & at(int i) const
void addAction(QAction *action)
virtual void setVisible(bool visible)
bool clearWidgets()
Remove all items from the bar&#39;s widget list.
void setValue(int value)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void setIcon(const QIcon &icon)
QString tr(const char *sourceText, const char *disambiguation, int n)
void pushSuccess(const QString &title, const QString &message)
Pushes a success message with default timeout to the message bar.
void removeWidget(QWidget *widget)
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
make out a widget containing a message to be displayed on the bar
void pushWarning(const QString &title, const QString &message)
Pushes a warning with default timeout to the message bar.
int count(const T &value) const
void setLayout(QLayout *layout)
bool empty() const
void setIconSize(const QSize &size)
Qt::MouseButton button() const
QPalette::ColorRole backgroundRole() const
bool isEmpty() const
void setObjectName(const QString &name)
int duration() const
returns the duration in second of the message
void widgetAdded(QgsMessageBarItem *item)
emitted when a message widget is added to the bar
void setText(const QString &)
void hide()
void setSizePolicy(QSizePolicy)
void setFixedSize(const QSize &s)
bool contains(const T &value) const
void stop()
void setFrameShadow(Shadow)
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)
void setPopupMode(ToolButtonPopupMode mode)
void start(int msec)
void prepend(const T &value)
void setAutoFillBackground(bool enabled)
void show()
const QPoint & pos() const
void setToolTip(const QString &)
const QBrush & window() const
bool isActive() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
void setTextVisible(bool visible)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void setRange(int minimum, int maximum)
bool removeOne(const T &value)
void setHidden(bool hidden)
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.