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