File indexing completed on 2025-01-05 03:59:26
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org> 0004 // SPDX-FileCopyrightText: 2010, 2011 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0005 // 0006 0007 #include "ProgressFloatItem.h" 0008 0009 #include <QRect> 0010 #include <QColor> 0011 #include <QPaintDevice> 0012 #include <QPainter> 0013 #include <QPainterPath> 0014 #include <QThread> 0015 0016 #include <klocalizedstring.h> 0017 0018 #include "MarbleDirs.h" 0019 #include "MarbleModel.h" 0020 #include "MarbleWidget.h" 0021 #include "ViewportParams.h" 0022 #include "HttpDownloadManager.h" 0023 #include "digikam_debug.h" 0024 0025 namespace Marble 0026 { 0027 0028 ProgressFloatItem::ProgressFloatItem( const MarbleModel *marbleModel ) 0029 : AbstractFloatItem( marbleModel, QPointF( -10.5, -150.5 ), QSizeF( 40.0, 40.0 ) ), 0030 m_isInitialized( false ), 0031 m_totalJobs( 0 ), 0032 m_completedJobs ( 0 ), 0033 m_completed( 1 ), 0034 m_progressHideTimer(), 0035 m_progressShowTimer(), 0036 m_active( false ), 0037 m_fontSize( 0 ), 0038 m_repaintTimer() 0039 { 0040 // This timer is responsible to activate the automatic display with a small delay 0041 m_progressShowTimer.setInterval( 250 ); 0042 m_progressShowTimer.setSingleShot( true ); 0043 0044 connect(&m_progressShowTimer, SIGNAL(timeout()), 0045 this, SLOT(show()) ); 0046 0047 // This timer is responsible to hide the automatic display when downloads are finished 0048 m_progressHideTimer.setInterval( 750 ); 0049 m_progressHideTimer.setSingleShot( true ); 0050 0051 connect(&m_progressHideTimer, SIGNAL(timeout()), 0052 this, SLOT(hideProgress()) ); 0053 0054 // Repaint timer 0055 m_repaintTimer.setSingleShot( true ); 0056 m_repaintTimer.setInterval( 1000 ); 0057 0058 connect(&m_repaintTimer, SIGNAL(timeout()), 0059 this, SIGNAL(repaintNeeded()) ); 0060 0061 // Plugin is enabled by default 0062 setEnabled( true ); 0063 0064 // Plugin is visible by default on devices with small screens only 0065 setVisible( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ); 0066 } 0067 0068 ProgressFloatItem::~ProgressFloatItem () 0069 { 0070 // nothing to do 0071 } 0072 0073 QStringList ProgressFloatItem::backendTypes() const 0074 { 0075 return QStringList(QStringLiteral("progress")); 0076 } 0077 0078 QString ProgressFloatItem::name() const 0079 { 0080 return i18n( "Download Progress Indicator" ); 0081 } 0082 0083 QString ProgressFloatItem::guiString() const 0084 { 0085 return i18n( "&Download Progress" ); 0086 } 0087 0088 QString ProgressFloatItem::nameId() const 0089 { 0090 return QStringLiteral("progress"); 0091 } 0092 0093 QString ProgressFloatItem::version() const 0094 { 0095 return QStringLiteral("1.0"); 0096 } 0097 0098 QString ProgressFloatItem::description() const 0099 { 0100 return i18n( "A plugin to show a pie chart download progress indicator over the map" ); 0101 } 0102 0103 QString ProgressFloatItem::copyrightYears() const 0104 { 0105 return QStringLiteral("2010, 2011"); 0106 } 0107 0108 QVector<PluginAuthor> ProgressFloatItem::pluginAuthors() const 0109 { 0110 return QVector<PluginAuthor>() 0111 << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org")) 0112 << PluginAuthor(QStringLiteral("Bernhard Beschow"), QStringLiteral("bbeschow@cs.tu-berlin.de")); 0113 } 0114 0115 QIcon ProgressFloatItem::icon() const 0116 { 0117 return QIcon::fromTheme(QStringLiteral("download-later")); 0118 } 0119 0120 void ProgressFloatItem::initialize() 0121 { 0122 const HttpDownloadManager* manager = marbleModel()->downloadManager(); 0123 0124 Q_ASSERT( manager ); 0125 0126 connect( manager, SIGNAL(progressChanged(int,int)), this, SLOT(handleProgress(int,int)) , Qt::UniqueConnection ); 0127 connect( manager, SIGNAL(jobRemoved()), this, SLOT(removeProgressItem()), Qt::UniqueConnection ); 0128 0129 // Calculate font size 0130 QFont myFont = font(); 0131 const QString text = QLatin1String("100%"); 0132 int fontSize = myFont.pointSize(); 0133 while( QFontMetrics( myFont ).boundingRect( text ).width() < contentRect().width() - 2 ) { 0134 ++fontSize; 0135 myFont.setPointSize( fontSize ); 0136 } 0137 m_fontSize = fontSize - 1; 0138 0139 m_isInitialized = true; 0140 } 0141 0142 bool ProgressFloatItem::isInitialized() const 0143 { 0144 return m_isInitialized; 0145 } 0146 0147 QPainterPath ProgressFloatItem::backgroundShape() const 0148 { 0149 QPainterPath path; 0150 0151 if ( active() ) { 0152 // Circular shape if active, invisible otherwise 0153 QRectF rect = contentRect(); 0154 qreal width = rect.width(); 0155 qreal height = rect.height(); 0156 path.addEllipse( marginLeft() + 2 * padding(), marginTop() + 2 * padding(), width, height ); 0157 } 0158 0159 return path; 0160 } 0161 0162 void ProgressFloatItem::paintContent( QPainter *painter ) 0163 { 0164 // Timers cannot be stopped from another thread (e.g. from QtQuick RenderThread). 0165 if (QThread::currentThread() == QCoreApplication::instance()->thread()) { 0166 // Stop repaint timer if it is already running 0167 if (m_repaintTimer.isActive()) { 0168 m_repaintTimer.stop(); 0169 } 0170 } 0171 0172 if ( !active() ) { 0173 return; 0174 } 0175 0176 painter->save(); 0177 0178 // Paint progress pie 0179 int startAngle = 90 * 16; // 12 o' clock 0180 int spanAngle = -ceil ( 360 * 16 * m_completed ); 0181 QRectF rect( contentRect() ); 0182 rect.adjust( 1, 1, -1, -1 ); 0183 0184 painter->setBrush( QColor( Qt::white ) ); 0185 painter->setPen( Qt::NoPen ); 0186 painter->drawPie( rect, startAngle, spanAngle ); 0187 0188 // Paint progress label 0189 QFont myFont = font(); 0190 myFont.setPointSize( m_fontSize ); 0191 const QString done = QString::number((int) (m_completed * 100)) + QLatin1Char('%'); 0192 int fontWidth = QFontMetrics( myFont ).boundingRect( done ).width(); 0193 QPointF baseline( padding() + 0.5 * ( rect.width() - fontWidth ), 0.75 * rect.height() ); 0194 QPainterPath path; 0195 path.addText( baseline, myFont, done ); 0196 0197 painter->setFont( myFont ); 0198 painter->setBrush( QBrush() ); 0199 painter->setPen( QPen() ); 0200 painter->drawPath( path ); 0201 0202 painter->restore(); 0203 } 0204 0205 void ProgressFloatItem::removeProgressItem() 0206 { 0207 m_jobMutex.lock(); 0208 ++m_completedJobs; 0209 m_jobMutex.unlock(); 0210 0211 if ( enabled() ) { 0212 if ( !active() && !m_progressShowTimer.isActive() ) { 0213 m_progressShowTimer.start(); 0214 m_progressHideTimer.stop(); 0215 } else if ( active() ) { 0216 update(); 0217 scheduleRepaint(); 0218 } 0219 } 0220 } 0221 0222 void ProgressFloatItem::handleProgress( int current, int queued ) 0223 { 0224 m_jobMutex.lock(); 0225 if ( current < 1 ) { 0226 m_totalJobs = 0; 0227 m_completedJobs = 0; 0228 } else { 0229 m_totalJobs = qMax<int>( m_totalJobs, queued + current ); 0230 } 0231 m_jobMutex.unlock(); 0232 0233 if ( enabled() ) { 0234 if ( !active() && !m_progressShowTimer.isActive() && m_totalJobs > 0 ) { 0235 m_progressShowTimer.start(); 0236 m_progressHideTimer.stop(); 0237 } else if ( active() ) { 0238 if ( m_totalJobs < 1 || m_completedJobs == m_totalJobs ) { 0239 m_progressShowTimer.stop(); 0240 m_progressHideTimer.start(); 0241 } 0242 update(); 0243 scheduleRepaint(); 0244 } 0245 0246 m_completed = 1.0; 0247 if ( m_totalJobs && m_completedJobs <= m_totalJobs ) { 0248 m_completed = (qreal) m_completedJobs / (qreal) m_totalJobs; 0249 } 0250 } 0251 } 0252 0253 void ProgressFloatItem::hideProgress() 0254 { 0255 if ( enabled() ) { 0256 setActive( false ); 0257 0258 update(); 0259 Q_EMIT repaintNeeded( QRegion() ); 0260 } 0261 } 0262 0263 bool ProgressFloatItem::active() const 0264 { 0265 return m_active; 0266 } 0267 0268 void ProgressFloatItem::setActive( bool active ) 0269 { 0270 m_active = active; 0271 update(); 0272 } 0273 0274 void ProgressFloatItem::show() 0275 { 0276 setActive( true ); 0277 0278 update(); 0279 0280 Q_EMIT repaintNeeded( QRegion() ); 0281 } 0282 0283 void ProgressFloatItem::scheduleRepaint() 0284 { 0285 if ( !m_repaintTimer.isActive() ) { 0286 m_repaintTimer.start(); 0287 } 0288 } 0289 0290 } // namespace Marble 0291 0292 #include "moc_ProgressFloatItem.cpp"