1 /***************************************************************************
2                           qgsmessagebaritem.h  -  description
3                              -------------------
4     begin                : August 2013
5     copyright            : (C) 2013 by Denis Rouzaud
6     email                : denis.rouzaud@gmail.com
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 "qgsapplication.h"
19 #include "qgsmessagebaritem.h"
20 #include "qgsmessagebar.h"
21 #include "qgsgui.h"
22 #include "qgsnative.h"
23 #include <QHBoxLayout>
24 #include <QLabel>
25 #include <QTextBrowser>
26 #include <QDesktopServices>
27 #include <QFileInfo>
28 
QgsMessageBarItem(const QString & text,Qgis::MessageLevel level,int duration,QWidget * parent)29 QgsMessageBarItem::QgsMessageBarItem( const QString &text, Qgis::MessageLevel level, int duration, QWidget *parent )
30   : QWidget( parent )
31   , mText( text )
32   , mLevel( level )
33   , mDuration( duration )
34 {
35   writeContent();
36 }
37 
QgsMessageBarItem(const QString & title,const QString & text,Qgis::MessageLevel level,int duration,QWidget * parent)38 QgsMessageBarItem::QgsMessageBarItem( const QString &title, const QString &text, Qgis::MessageLevel level, int duration, QWidget *parent )
39   : QWidget( parent )
40   , mTitle( title )
41   , mText( text )
42   , mLevel( level )
43   , mDuration( duration )
44 {
45   writeContent();
46 }
47 
QgsMessageBarItem(const QString & title,const QString & text,QWidget * widget,Qgis::MessageLevel level,int duration,QWidget * parent)48 QgsMessageBarItem::QgsMessageBarItem( const QString &title, const QString &text, QWidget *widget, Qgis::MessageLevel level, int duration, QWidget *parent )
49   : QWidget( parent )
50   , mTitle( title )
51   , mText( text )
52   , mLevel( level )
53   , mDuration( duration )
54   , mWidget( widget )
55   , mUserIcon( QIcon() )
56 
57 {
58   writeContent();
59 }
60 
QgsMessageBarItem(QWidget * widget,Qgis::MessageLevel level,int duration,QWidget * parent)61 QgsMessageBarItem::QgsMessageBarItem( QWidget *widget, Qgis::MessageLevel level, int duration, QWidget *parent )
62   : QWidget( parent )
63   , mLevel( level )
64   , mDuration( duration )
65   , mWidget( widget )
66   , mUserIcon( QIcon() )
67 
68 {
69   writeContent();
70 }
71 
writeContent()72 void QgsMessageBarItem::writeContent()
73 {
74   if ( !mLayout )
75   {
76     mLayout = new QHBoxLayout( this );
77     mLayout->setContentsMargins( 0, 0, 0, 0 );
78     mTextBrowser = nullptr;
79     mLblIcon = nullptr;
80   }
81 
82   // ICON
83   if ( !mLblIcon )
84   {
85     mLblIcon = new QLabel( this );
86     mLayout->addWidget( mLblIcon );
87   }
88   QIcon icon;
89   if ( !mUserIcon.isNull() )
90   {
91     icon = mUserIcon;
92   }
93   else
94   {
95     QString msgIcon( QStringLiteral( "/mIconInfo.svg" ) );
96     switch ( mLevel )
97     {
98       case Qgis::Critical:
99         msgIcon = QStringLiteral( "/mIconCritical.svg" );
100         break;
101       case Qgis::Warning:
102         msgIcon = QStringLiteral( "/mIconWarning.svg" );
103         break;
104       case Qgis::Success:
105         msgIcon = QStringLiteral( "/mIconSuccess.svg" );
106         break;
107       default:
108         break;
109     }
110     icon = QgsApplication::getThemeIcon( msgIcon );
111   }
112   const int iconSize = std::max( 24.0, fontMetrics().height() * 1.2 );
113   mLblIcon->setPixmap( icon.pixmap( iconSize ) );
114 
115 
116   // STYLESHEETS
117   QString contentStyleSheet;
118   if ( mLevel == Qgis::Success )
119   {
120     mStyleSheet = QStringLiteral( "QgsMessageBar { background-color: #dff0d8; border: 1px solid #8e998a; } "
121                                   "QLabel,QTextEdit { color: black; } " );
122     contentStyleSheet = QStringLiteral( "<style> a, a:visited, a:hover { color:#268300; } </style>" );
123   }
124   else if ( mLevel == Qgis::Critical )
125   {
126     mStyleSheet = QStringLiteral( "QgsMessageBar { background-color: #d65253; border: 1px solid #9b3d3d; } "
127                                   "QLabel,QTextEdit { color: white; } " );
128     contentStyleSheet = QStringLiteral( "<style>a, a:visited, a:hover { color:#4e0001; }</style>" );
129   }
130   else if ( mLevel == Qgis::Warning )
131   {
132     mStyleSheet = QStringLiteral( "QgsMessageBar { background-color: #ffc800; border: 1px solid #e0aa00; } "
133                                   "QLabel,QTextEdit { color: black; } " );
134     contentStyleSheet = QStringLiteral( "<style>a, a:visited, a:hover { color:#945a00; }</style>" );
135   }
136   else if ( mLevel == Qgis::Info )
137   {
138     mStyleSheet = QStringLiteral( "QgsMessageBar { background-color: #e7f5fe; border: 1px solid #b9cfe4; } "
139                                   "QLabel,QTextEdit { color: #2554a1; } " );
140     contentStyleSheet = QStringLiteral( "<style>a, a:visited, a:hover { color:#3bb2fe; }</style>" );
141   }
142   mStyleSheet += QLatin1String( "QLabel#mItemCount { font-style: italic; }" );
143 
144   // TITLE AND TEXT
145   if ( mTitle.isEmpty() && mText.isEmpty() )
146   {
147     if ( mTextBrowser )
148     {
149       delete mTextBrowser;
150       mTextBrowser = nullptr;
151     }
152   }
153   else
154   {
155     if ( !mTextBrowser )
156     {
157       mTextBrowser = new QTextBrowser( this );
158       mTextBrowser->setObjectName( QStringLiteral( "textEdit" ) );
159       mTextBrowser->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Maximum );
160       mTextBrowser->setReadOnly( true );
161       mTextBrowser->setOpenLinks( false );
162       connect( mTextBrowser, &QTextBrowser::anchorClicked, this, &QgsMessageBarItem::urlClicked );
163 
164       mTextBrowser->setFrameShape( QFrame::NoFrame );
165       // stylesheet set here so Qt-style substitued scrollbar arrows can show within limited height
166       // adjusts to height of font set in app options
167       mTextBrowser->setStyleSheet( "QTextEdit { background-color: rgba(0,0,0,0); margin-top: 0.25em; max-height: 1.75em; min-height: 1.75em; } "
168                                    "QScrollBar { background-color: rgba(0,0,0,0); } "
169                                    "QScrollBar::add-page,QScrollBar::sub-page,QScrollBar::handle { background-color: rgba(0,0,0,0); color: rgba(0,0,0,0); } "
170                                    "QScrollBar::up-arrow,QScrollBar::down-arrow { color: rgb(0,0,0); } " );
171       mLayout->addWidget( mTextBrowser );
172     }
173     QString content = mText;
174     if ( !mTitle.isEmpty() )
175     {
176       // add ':' to end of title
177       QString t = mTitle.trimmed();
178       if ( !content.isEmpty() && !t.endsWith( ':' ) && !t.endsWith( QLatin1String( ": " ) ) )
179         t += QLatin1String( ": " );
180       content.prepend( QStringLiteral( "<b>" ) + t + " </b>" );
181     }
182     content.prepend( contentStyleSheet );
183     mTextBrowser->setText( content );
184   }
185 
186   // WIDGET
187   if ( mWidget )
188   {
189     QLayoutItem *item = mLayout->itemAt( 2 );
190     if ( !item || item->widget() != mWidget )
191     {
192       mLayout->addWidget( mWidget );
193     }
194   }
195 }
196 
setText(const QString & text)197 QgsMessageBarItem *QgsMessageBarItem::setText( const QString &text )
198 {
199   mText = text;
200   writeContent();
201   return this;
202 }
203 
text() const204 QString QgsMessageBarItem::text() const
205 {
206   return mText;
207 }
208 
setTitle(const QString & title)209 QgsMessageBarItem *QgsMessageBarItem::setTitle( const QString &title )
210 {
211   mTitle = title;
212   writeContent();
213   return this;
214 }
215 
title() const216 QString QgsMessageBarItem::title() const
217 {
218   return mTitle;
219 }
220 
setLevel(Qgis::MessageLevel level)221 QgsMessageBarItem *QgsMessageBarItem::setLevel( Qgis::MessageLevel level )
222 {
223   if ( level != mLevel )
224   {
225     mLevel = level;
226     writeContent();
227     emit styleChanged( mStyleSheet );
228   }
229 
230   return this;
231 }
232 
level() const233 Qgis::MessageLevel QgsMessageBarItem::level() const
234 {
235   return mLevel;
236 }
237 
setWidget(QWidget * widget)238 QgsMessageBarItem *QgsMessageBarItem::setWidget( QWidget *widget )
239 {
240   if ( mWidget )
241   {
242     QLayoutItem *item = nullptr;
243     item = mLayout->itemAt( 2 );
244     if ( item->widget() == mWidget )
245     {
246       delete item->widget();
247     }
248   }
249   mWidget = widget;
250   writeContent();
251   return this;
252 }
253 
widget() const254 QWidget *QgsMessageBarItem::widget() const
255 {
256   return mWidget;
257 }
258 
setIcon(const QIcon & icon)259 QgsMessageBarItem *QgsMessageBarItem::setIcon( const QIcon &icon )
260 {
261   mUserIcon = icon;
262   return this;
263 }
264 
icon() const265 QIcon QgsMessageBarItem::icon() const
266 {
267   return mUserIcon;
268 }
269 
270 
setDuration(int duration)271 QgsMessageBarItem *QgsMessageBarItem::setDuration( int duration )
272 {
273   mDuration = duration;
274   return this;
275 }
276 
dismiss()277 void QgsMessageBarItem::dismiss()
278 {
279   if ( !mMessageBar )
280     return;
281 
282   mMessageBar->popWidget( this );
283 }
284 
urlClicked(const QUrl & url)285 void QgsMessageBarItem::urlClicked( const QUrl &url )
286 {
287   QFileInfo file( url.toLocalFile() );
288   if ( file.exists() && !file.isDir() )
289     QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
290   else
291     QDesktopServices::openUrl( url );
292   dismiss();
293 }
294