1 /****************************************************************************************
2  * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>                                *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #include "CompoundProgressBar.h"
18 
19 #include "core/support/Debug.h"
20 
21 #include <QIcon>
22 #include <QMutexLocker>
23 
24 #include <KLocalizedString>
25 
26 
CompoundProgressBar(QWidget * parent)27 CompoundProgressBar::CompoundProgressBar( QWidget *parent )
28         : ProgressBar( parent )
29         , m_mutex( QMutex::Recursive )
30 {
31     m_progressDetailsWidget = new PopupWidget();
32     m_progressDetailsWidget->hide();
33 
34     connect( cancelButton(), &QAbstractButton::clicked, this, &CompoundProgressBar::cancelAll );
35 }
36 
~CompoundProgressBar()37 CompoundProgressBar::~CompoundProgressBar()
38 {
39     delete m_progressDetailsWidget;
40     m_progressDetailsWidget = 0;
41 }
42 
addProgressBar(ProgressBar * childBar,QObject * owner)43 void CompoundProgressBar::addProgressBar( ProgressBar *childBar, QObject *owner )
44 {
45     QMutexLocker locker( &m_mutex );
46 
47     m_progressMap.insert( owner, childBar );
48     m_progressDetailsWidget->layout()->addWidget( childBar );
49     if( m_progressDetailsWidget->width() < childBar->width() )
50         m_progressDetailsWidget->setMinimumWidth( childBar->width() );
51 
52     m_progressDetailsWidget->setMinimumHeight( childBar->height() * m_progressMap.count()  + 8 );
53 
54     m_progressDetailsWidget->reposition();
55 
56     connect( childBar, &ProgressBar::percentageChanged,
57              this, &CompoundProgressBar::childPercentageChanged );
58     connect( childBar, &ProgressBar::cancelled,
59              this, &CompoundProgressBar::childBarCancelled );
60     connect( childBar, &ProgressBar::complete,
61              this, &CompoundProgressBar::childBarComplete );
62     connect( owner, &QObject::destroyed, this, &CompoundProgressBar::slotObjectDestroyed );
63 
64     if( m_progressMap.count() == 1 )
65     {
66         setDescription( childBar->descriptionLabel()->text() );
67         cancelButton()->setToolTip( i18n( "Abort" ) );
68     }
69     else
70     {
71         setDescription( i18n( "Multiple background tasks running (click to show)" ) );
72         cancelButton()->setToolTip( i18n( "Abort all background tasks" ) );
73     }
74 
75     cancelButton()->setHidden( false );
76 }
77 
endProgressOperation(QObject * owner)78 void CompoundProgressBar::endProgressOperation( QObject *owner )
79 {
80     QMutexLocker locker( &m_mutex );
81 
82     if( !m_progressMap.contains( owner ) )
83         return ;
84 
85     childBarComplete( m_progressMap.value( owner ) );
86 }
87 
88 void
slotIncrementProgress()89 CompoundProgressBar::slotIncrementProgress()
90 {
91     incrementProgress( sender() );
92 }
93 
incrementProgress(const QObject * owner)94 void CompoundProgressBar::incrementProgress( const QObject *owner )
95 {
96     QMutexLocker locker( &m_mutex );
97 
98     if( !m_progressMap.contains( owner ) )
99         return ;
100 
101     m_progressMap.value( owner )->setValue( m_progressMap.value( owner )->value() + 1 );
102 }
103 
setProgress(const QObject * owner,int steps)104 void CompoundProgressBar::setProgress( const QObject *owner, int steps )
105 {
106     QMutexLocker locker( &m_mutex );
107 
108     if( !m_progressMap.contains( owner ) )
109         return ;
110 
111     m_progressMap.value( owner )->setValue( steps );
112 }
113 
114 void
mousePressEvent(QMouseEvent * event)115 CompoundProgressBar::mousePressEvent( QMouseEvent *event )
116 {
117     QMutexLocker locker( &m_mutex );
118 
119     if( m_progressDetailsWidget->isHidden() )
120     {
121         if( m_progressMap.count() )
122             showDetails();
123     }
124     else
125     {
126         hideDetails();
127     }
128 
129     event->accept();
130 }
131 
setProgressTotalSteps(const QObject * owner,int value)132 void CompoundProgressBar::setProgressTotalSteps( const QObject *owner, int value )
133 {
134     QMutexLocker locker( &m_mutex );
135 
136     if( !m_progressMap.contains( owner ) )
137         return ;
138 
139     m_progressMap.value( owner )->setMaximum( value );
140 }
141 
setProgressStatus(const QObject * owner,const QString & text)142 void CompoundProgressBar::setProgressStatus( const QObject *owner, const QString &text )
143 {
144     QMutexLocker locker( &m_mutex );
145 
146     if( !m_progressMap.contains( owner ) )
147         return ;
148 
149     m_progressMap.value( owner )->setDescription( text );
150 }
151 
childPercentageChanged()152 void CompoundProgressBar::childPercentageChanged()
153 {
154     progressBar()->setValue( calcCompoundPercentage() );
155 }
156 
childBarCancelled(ProgressBar * childBar)157 void CompoundProgressBar::childBarCancelled( ProgressBar *childBar )
158 {
159     childBarFinished( childBar );
160 }
161 
childBarComplete(ProgressBar * childBar)162 void CompoundProgressBar::childBarComplete( ProgressBar *childBar )
163 {
164     childBarFinished( childBar );
165 }
166 
slotObjectDestroyed(QObject * object)167 void CompoundProgressBar::slotObjectDestroyed( QObject *object )
168 {
169     QMutexLocker locker( &m_mutex );
170 
171     if( m_progressMap.contains( object ) )
172     {
173         childBarFinished( m_progressMap.value( object ) );
174     }
175 }
176 
childBarFinished(ProgressBar * bar)177 void CompoundProgressBar::childBarFinished( ProgressBar *bar )
178 {
179     QMutexLocker locker( &m_mutex );
180 
181     QObject *owner = const_cast<QObject *>( m_progressMap.key( bar ) );
182     owner->disconnect( this );
183     owner->disconnect( bar );
184     m_progressMap.remove( owner );
185     m_progressDetailsWidget->layout()->removeWidget( bar );
186     m_progressDetailsWidget->setFixedHeight( bar->height() * m_progressMap.count() + 8 );
187     m_progressDetailsWidget->reposition();
188     delete bar;
189 
190     if( m_progressMap.count() == 1 )
191     {
192         //only one job still running, so no need to use the details widget any more.
193         //Also set the text to the description of
194         //the job instead of the "Multiple background tasks running" text.
195         setDescription( m_progressMap.values().at( 0 )->descriptionLabel()->text() );
196         cancelButton()->setToolTip( i18n( "Abort" ) );
197         hideDetails();
198     }
199     else if( m_progressMap.empty() )
200     {
201         progressBar()->setValue( 0 );
202         hideDetails();
203         Q_EMIT( allDone() );
204         return;
205     }
206     else
207     {
208         setDescription( i18n( "Multiple background tasks running (click to show)" ) );
209         cancelButton()->setToolTip( i18n( "Abort all background tasks" ) );
210     }
211 
212     progressBar()->setValue( calcCompoundPercentage() );
213 }
214 
calcCompoundPercentage()215 int CompoundProgressBar::calcCompoundPercentage()
216 {
217     QMutexLocker locker( &m_mutex );
218 
219     int count = m_progressMap.count();
220     int total = 0;
221 
222     foreach( ProgressBar *currentBar, m_progressMap )
223         total += currentBar->percentage();
224 
225     return count == 0 ? 0 : total / count;
226 }
227 
cancelAll()228 void CompoundProgressBar::cancelAll()
229 {
230     QMutexLocker locker( &m_mutex );
231 
232     foreach( ProgressBar *currentBar, m_progressMap )
233         currentBar->cancel();
234 }
235 
showDetails()236 void CompoundProgressBar::showDetails()
237 {
238     QMutexLocker locker( &m_mutex );
239 
240     m_progressDetailsWidget->raise();
241 
242     //Hack to make sure it has the right height first time it is shown...
243     m_progressDetailsWidget->setFixedHeight(
244                 m_progressMap.values().at( 0 )->height() * m_progressMap.count() + 8 );
245     m_progressDetailsWidget->reposition();
246     m_progressDetailsWidget->show();
247 }
248 
hideDetails()249 void CompoundProgressBar::hideDetails()
250 {
251     m_progressDetailsWidget->hide();
252 }
253 
toggleDetails()254 void CompoundProgressBar::toggleDetails()
255 {
256     if( m_progressDetailsWidget->isVisible() )
257         hideDetails();
258     else
259         showDetails();
260 }
261