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