1 /***************************************************************************
5 * begin : Tue Jan 29 2002
6 * copyright : (C) 2002, 2003, 2004, 2005 by Patrick Charbonnier
7 * : Based On Caitoo v.0.7.3 (c) 1998 - 2000, Matej Koss
8 * email : pch@freeshell.org
10 ****************************************************************************/
12 /***************************************************************************
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public Lkio/global.h:icense as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 ***************************************************************************/
29 #include <kmessagebox.h>
31 #include <ksimpleconfig.h>
33 #include <kiconloader.h>
34 #include <kstandarddirs.h>
38 #include "safedelete.h"
40 #include "logwindow.h"
41 #include "kmainwidget.h"
42 #include "dlgIndividual.h"
43 #include "transferlist.h"
46 #include <kapplication.h>
47 #include <kio/passdlg.h>
48 #include <kio/global.h>
49 #include <kio/netaccess.h>
52 extern Settings ksettings
;
55 Transfer::Transfer(TransferList
* _view
, const KURL
& _src
, const KURL
& _dest
, const uint _id
)
72 Transfer::Transfer(TransferList
* _view
, Transfer
* after
, const KURL
& _src
, const KURL
& _dest
, const uint _id
)
74 KListViewItem(_view
, (QListViewItem
*) after
),
75 src(_src
), dest(_dest
), view(_view
),
101 Transfer::init(const uint _id
)
109 m_pSlave
= new Slave(this, src
, dest
);
111 startTime
= QDateTime::currentDateTime();
113 // retryCount = ksettings.reconnectRetries-1;
115 //first off all we need to know if resume is supported...
120 connect(this, SIGNAL(statusChanged(Transfer
*, int)), kmain
, SLOT(slotStatusChanged(Transfer
*, int)));
121 connect(this, SIGNAL(statusChanged(Transfer
*, int)), this, SLOT(slotUpdateActions()));
123 connect(this, SIGNAL(log(uint
, const QString
&, const QString
&)), kmain
->logwin(), SLOT(logTransfer(uint
, const QString
&, const QString
&)));
126 m_paResume
= new KAction(i18n("&Resume"), "tool_resume", 0, this, SLOT(slotResume()), this, "resume");
128 m_paPause
= new KAction(i18n("&Pause"), "tool_pause", 0, this, SLOT(slotRequestPause()), this, "pause");
130 m_paDelete
= new KAction(i18n("&Delete"), "editdelete", 0, this, SLOT(slotRequestRemove()), this, "delete");
132 m_paRestart
= new KAction(i18n("Re&start"), "tool_restart", 0, this, SLOT(slotRequestRestart()), this, "restart");
134 m_paQueue
= new KRadioAction(i18n("&Queue"), "tool_queue", 0, this, SLOT(slotQueue()), this, "queue");
136 m_paTimer
= new KRadioAction(i18n("&Timer"), "tool_timer", 0, this, SLOT(slotRequestSchedule()), this, "timer");
138 m_paDelay
= new KRadioAction(i18n("De&lay"), "tool_delay", 0, this, SLOT(slotRequestDelay()), this, "delay");
140 m_paQueue
->setExclusiveGroup("TransferMode");
141 m_paTimer
->setExclusiveGroup("TransferMode");
142 m_paDelay
->setExclusiveGroup("TransferMode");
146 // m_paDock = new KAction(i18n("&Dock"),"tool_dock", 0, this,SLOT(slotRequestDelay()), this, "dockIndividual");
148 // setup individual transfer dialog
156 void Transfer::synchronousAbort()
160 if ( m_pSlave
->running() )
162 m_pSlave
->Op(Slave::KILL
);
166 if ( m_pSlave
->running() )
167 m_pSlave
->terminate();
178 void Transfer::slotUpdateActions()
180 sDebugIn
<< "the item Status is =" << status
<< "offline=" << ksettings
.b_offline
<< endl
;
181 //if we are offline just disable Resume and Pause and return
182 if (ksettings
.b_offline
) {
183 m_paResume
->setEnabled(false);
184 m_paPause
->setEnabled(false);
185 m_paRestart
->setEnabled(false);
187 dlgIndividual
->update();
195 case ST_TRYING
://fall-through
197 m_paResume
->setEnabled(false);
198 m_paPause
->setEnabled(true);
199 m_paRestart
->setEnabled(true);
203 m_paResume
->setEnabled(true);
204 m_paPause
->setEnabled(false);
205 m_paRestart
->setEnabled(false);
208 m_paResume
->setEnabled(false);
209 m_paPause
->setEnabled(false);
210 m_paRestart
->setEnabled(false);
214 // disable all signals
215 m_paQueue
->blockSignals(true);
216 m_paTimer
->blockSignals(true);
217 m_paDelay
->blockSignals(true);
221 m_paQueue
->setChecked(true);
224 m_paTimer
->setChecked(true);
227 m_paDelay
->setChecked(true);
229 case MD_NEW
: //fall through
231 m_paQueue
->setChecked(false);
232 m_paTimer
->setChecked(false);
233 m_paDelay
->setChecked(false);
235 m_paQueue
->setEnabled(false);
236 m_paTimer
->setEnabled(false);
237 m_paDelay
->setEnabled(false);
243 // enable all signals
244 m_paQueue
->blockSignals(false);
245 m_paTimer
->blockSignals(false);
246 m_paDelay
->blockSignals(false);
249 dlgIndividual
->update();
256 void Transfer::setSpeed(unsigned long _speed
)
261 remainingTime
= KIO::calculateRemaining(totalSize
, processedSize
, speed
);
267 void Transfer::updateAll()
271 updateStatus(status
); // first phase of animation
273 logMessage(i18n("Copy file from: %1").arg(src
.prettyURL()));
274 logMessage(i18n("To: %1").arg(dest
.prettyURL()));
277 setText(view
->lv_url
, src
.prettyURL());
280 setText(view
->lv_filename
, dest
.fileName());
284 dlgIndividual
->setCopying(src
, dest
);
285 dlgIndividual
->setCanResume(canResume
);
286 dlgIndividual
->setTotalSize(totalSize
);
287 dlgIndividual
->setPercent(0);
288 dlgIndividual
->setProcessedSize(0);
291 if (totalSize
!= 0) {
292 //logMessage(i18n("Total size is %1 bytes").arg((double)totalSize));
293 setText(view
->lv_total
, KIO::convertSize(totalSize
));
295 //logMessage(i18n("Total size is unknown"));
296 setText(view
->lv_total
, i18n("unknown"));
304 bool Transfer::updateStatus(int counter
)
306 //sDebug<< ">>>>Entering"<<endl;
309 bool isTransfer
= false;
311 view
->setUpdatesEnabled(false);
316 pix
= view
->animConn
.at(counter
);
320 pix
= view
->animTry
.at(counter
);
324 if(mode
== MD_QUEUED
)
325 pix
= &view
->pixQueued
;
326 else if(mode
== MD_SCHEDULED
)
327 pix
= &view
->pixScheduled
;
329 pix
= &view
->pixDelayed
;
332 pix
= &view
->pixFinished
;
335 setPixmap(view
->lv_pixmap
, *pix
);
336 view
->setUpdatesEnabled(true);
338 if(prevStatus
!=status
|| prevMode
!= mode
|| status
==ST_RUNNING
|| status
==ST_TRYING
)
340 QRect rect
= view
->header()->sectionRect(view
->lv_pixmap
);
343 int y
= view
->itemRect(this).y();
344 int w
= rect
.width();
345 int h
= rect
.height();
347 view
->QScrollView::updateContents(x
,y
,w
,h
);
357 void Transfer::UpdateRetry()
362 retry
.setNum(retryCount
);
363 MaxRetry
.setNum(ksettings
.reconnectRetries
);
364 retry
+= " / " + MaxRetry
;
366 setText(view
->lv_count
, retry
);
370 void Transfer::slotResume()
372 sDebugIn
<< " state =" << status
<< endl
;
375 if (retryCount
> ksettings
.reconnectRetries
)
378 assert(status
== ST_STOPPED
);
380 sDebug
<< "src: " << src
.prettyURL() << endl
;
381 sDebug
<< "dest " << dest
.prettyURL() << endl
;
383 m_paResume
->setEnabled(false);
387 logMessage(i18n("Attempt number %1").arg(retryCount
));
389 sDebug
<< "sending Resume to slave " << endl
;
390 m_pSlave
->Op(Slave::RETR
);
396 void Transfer::slotStop()
400 logMessage(i18n("Stopping"));
402 assert(status
<= ST_RUNNING
&& ksettings
.b_offline
);
404 m_pSlave
->Op(Slave::KILL
); // KILL doesn't post a Message
405 sDebug
<< "Killing Slave" << endl
;
410 m_paQueue
->setChecked(true);
418 void Transfer::slotRequestPause()
422 logMessage(i18n("Pausing"));
424 assert(status
<= ST_RUNNING
);
428 m_paPause
->setEnabled(false);
429 m_paRestart
->setEnabled(false);
432 m_pSlave
->Op(Slave::PAUSE
);
433 sDebug
<< "Requesting Pause.." << endl
;
441 void Transfer::slotRequestRestart()
444 m_pSlave
->Op(Slave::RESTART
);
450 void Transfer::slotRequestRemove()
453 m_paDelete
->setEnabled(false);
454 m_paPause
->setEnabled(false);
456 dlgIndividual
->close();
459 if ( status
!= ST_FINISHED
)
462 // delete the partly downloaded file, if any
463 file
.setFileName( dest
.fileName() + ".part" ); // ### get it from the job?
465 if ( KIO::NetAccess::exists( file
, false, view
) ) // don't pollute user with warnings
467 SafeDelete::deleteFile( file
); // ### messagebox on failure?
470 if (status
== ST_RUNNING
)
471 m_pSlave
->Op(Slave::REMOVE
);
473 emit
statusChanged(this, OP_REMOVED
);
479 void Transfer::slotQueue()
481 sDebug
<< ">>>>Entering with mode = " << mode
<< endl
;
483 logMessage(i18n("Queueing"));
485 assert(!(mode
== MD_QUEUED
));
488 m_paQueue
->setChecked(true);
489 emit
statusChanged(this, OP_QUEUED
);
494 void Transfer::slotRequestSchedule()
498 logMessage(i18n("Scheduling"));
499 assert(!(mode
== MD_SCHEDULED
));
501 // if the time was already set somewhere in the future, keep it
502 // otherwise set it to the current time + 60 seconds
503 if (startTime
< QDateTime::currentDateTime()) {
504 QDateTime dt
= QDateTime::currentDateTime();
505 startTime
= dt
.addSecs(60);
507 if (status
== ST_RUNNING
) {
508 m_paPause
->setEnabled(false);
509 m_paRestart
->setEnabled(false);
510 m_pSlave
->Op(Slave::SCHEDULE
);
518 void Transfer::slotRequestDelay()
522 logMessage(i18n("Delaying"));
524 assert(!(mode
== MD_DELAYED
));
525 if (status
== ST_RUNNING
) {
526 m_paPause
->setEnabled(false);
527 m_paRestart
->setEnabled(false);
528 m_pSlave
->Op(Slave::DELAY
);
537 void Transfer::slotCanceled(KIO::Job *)
541 logMessage(i18n("Canceled by user"));
542 emit statusChanged(this, OP_CANCELED);
548 void Transfer::slotFinished()
552 logMessage(i18n("Download finished"));
554 status
= ST_FINISHED
;
555 slotProcessedSize(totalSize
);
559 dlgIndividual
->enableOpenFile();
560 emit
statusChanged(this, OP_FINISHED
);
568 void Transfer::slotRenaming(KIO::Job *, const KURL &, const KURL & to)
574 logMessage(i18n("Renaming to %1").arg(dest.prettyURL().ascii()));
577 setText (view->lv_filename, dest.fileName ());
579 dlgIndividual->setCopying (src, dest);
588 void Transfer::slotSpeed(unsigned long bytes_per_second
)
592 setSpeed(bytes_per_second
);
594 if (speed
== 0 && status
== ST_RUNNING
) {
595 setText(view
->lv_speed
, i18n("Stalled"));
596 setText(view
->lv_remaining
, i18n("Stalled"));
597 } else if (speed
== 0 && status
== ST_FINISHED
) {
599 setText(view
->lv_progress
, i18n("OK as in 'finished'","OK"));
600 setText(view
->lv_speed
, i18n("0 MB/s"));
601 setText(view
->lv_remaining
, i18n("00:00:00"));
603 } else if (speed
== 0 && status
== ST_STOPPED
) {
606 setText(view
->lv_speed
, i18n("0 MB/s"));
607 setText(view
->lv_remaining
, i18n("00:00:00"));
610 QString tmps
= i18n("%1/s").arg(KIO::convertSize(speed
));
611 setText(view
->lv_speed
, tmps
);
612 setText(view
->lv_remaining
, remainingTime
.toString());
616 dlgIndividual
->setSpeed(speed
, remainingTime
);
623 void Transfer::slotTotalSize(KIO::filesize_t bytes
)
626 sDebugIn
<<" totalSize is = "<<totalSize
<< endl
;
629 if (totalSize
== 0) {
631 if (totalSize
!= 0) {
632 logMessage(i18n("Total size is %1 bytes").arg((double)totalSize
,0,'f',0));
633 setText(view
->lv_total
, KIO::convertSize(totalSize
));
636 dlgIndividual
->setTotalSize(totalSize
);
637 dlgIndividual
->setPercent(0);
638 dlgIndividual
->setProcessedSize(0);
644 sDebug
<<"totalSize="<<totalSize
<<" bytes="<<bytes
<<endl
;
645 assert(totalSize
== bytes
);
647 if (totalSize
!= bytes
)
648 logMessage(i18n("The file size does not match."));
650 logMessage(i18n("File Size checked"));
660 void Transfer::slotProcessedSize(KIO::filesize_t bytes
)
662 //sDebug<< ">>>>Entering"<<endl;
665 processedSize
= bytes
;
671 else if ( totalSize
< processedSize
) // bogus totalSize value
673 percent
= 99; // what can we say?
674 totalSize
= processedSize
;
676 setText(view
->lv_total
, KIO::convertSize(totalSize
));
678 dlgIndividual
->setTotalSize(totalSize
);
681 percent
= (int) (((float) processedSize
/ (float) totalSize
) * 100.0);
684 dlgIndividual
->setProcessedSize(processedSize
);
686 if (percent
!= old
) {
688 if (percent
== 100) {
689 tmps
= i18n("OK as in 'finished'","OK");
691 tmps
.setNum(percent
);
694 setText(view
->lv_progress
, tmps
);
697 dlgIndividual
->setPercent(percent
);
699 //sDebug<< "<<<<Leaving"<<endl;
705 void Transfer::showIndividual()
709 // create a DlgIndividual only if it hasn't been created yet
712 dlgIndividual
= new DlgIndividual(this);
713 dlgIndividual
->setLog(transferLog
);
714 dlgIndividual
->setCopying(src
, dest
);
715 dlgIndividual
->setCanResume(canResume
);
716 dlgIndividual
->setTotalSize(totalSize
);
717 dlgIndividual
->setPercent(percent
);
718 dlgIndividual
->setProcessedSize(processedSize
);
721 dlgIndividual
->raise();
724 if (ksettings
.b_iconifyIndividual
) {
725 KWin::iconifyWindow( dlgIndividual
->winId() );
728 // update the actions
730 // then show the single dialog
731 KWin::deIconifyWindow( dlgIndividual
->winId() );
732 dlgIndividual
->show();
738 void Transfer::logMessage(const QString
& message
)
740 sDebugIn
<< message
<< endl
;
742 emit
log(id
, src
.fileName(), message
);
744 QString tmps
= "<font color=\"blue\">" + QTime::currentTime().toString() + "</font> : " + message
;
746 transferLog
.append(tmps
+ '\n');
749 dlgIndividual
->appendLog(tmps
);
756 bool Transfer::read(KSimpleConfig
* config
, int id
)
762 str
.sprintf("Item%d", id
);
763 config
->setGroup(str
);
765 if (src
.isEmpty() || dest
.isEmpty()) {
769 if (!src
.isValid() && !ksettings
.b_expertMode
) {
770 KMessageBox::error(kmain
, i18n("Malformed URL:\n") + src
.prettyURL(), i18n("Error"));
774 mode
= (TransferMode
) config
->readNumEntry("Mode", MD_QUEUED
);
775 status
= (TransferStatus
) config
->readNumEntry("Status", ST_RUNNING
);
776 startTime
= config
->readDateTimeEntry("ScheduledTime");
777 canResume
= config
->readBoolEntry("CanResume", true);
778 totalSize
= config
->readUnsignedNum64Entry("TotalSize", 0);
779 processedSize
= config
->readUnsignedNum64Entry("ProcessedSize", 0);
781 if (status
!= ST_FINISHED
&& totalSize
!= 0) {
782 //TODO insert additional check
792 void Transfer::write(KSimpleConfig
* config
, int id
)
797 str
.sprintf("Item%d", id
);
799 config
->setGroup(str
);
800 config
->writePathEntry("Source", src
.url());
801 config
->writePathEntry("Dest", dest
.url());
802 config
->writeEntry("Mode", mode
);
803 config
->writeEntry("Status", status
);
804 config
->writeEntry("CanResume", canResume
);
805 config
->writeEntry("TotalSize", totalSize
);
806 config
->writeEntry("ProcessedSize", processedSize
);
807 config
->writeEntry("ScheduledTime", startTime
);
813 /** No descriptions */
814 void Transfer::slotExecPause()
820 m_paDelay
->setChecked(true);
823 m_paPause
->setEnabled(false);
824 m_paRestart
->setEnabled(true);
825 m_paResume
->setEnabled(true);
827 //TODO WE NEED TO UPDATE ACTIONS..
828 kmain
->slotUpdateActions();
829 emit
statusChanged(this, OP_PAUSED
);
833 void Transfer::slotExecError()
839 startTime
=QDateTime::currentDateTime().addSecs(ksettings
.reconnectTime
* 60);
840 emit
statusChanged(this, OP_SCHEDULED
);
845 void Transfer::slotExecBroken()
851 emit
statusChanged(this, OP_QUEUED
);
857 void Transfer::slotExecRemove()
862 emit
statusChanged(this, OP_REMOVED
);
867 void Transfer::slotExecResume()
870 emit
statusChanged(this, OP_RESUMED
);
874 void Transfer::slotExecConnected()
879 if (ksettings
.b_offline
)// when we're offline and arrive here, then the file is in cache
880 return; // Slave::slotResult will be called immediately, so we do nothing here
882 m_pSlave
->Op(Slave::KILL
);
883 if (ksettings
.b_addQueued
)
886 emit
statusChanged(this, OP_QUEUED
);
891 emit
statusChanged(this, OP_DELAYED
);
897 emit
statusChanged(this, OP_CONNECTED
);
902 void Transfer::slotCanResume(bool _bCanResume
)
906 canResume
= _bCanResume
;
909 logMessage(i18n("Download resumed"));
910 setText(view
->lv_resume
, i18n("Yes"));
912 setText(view
->lv_resume
, i18n("No"));
915 //dlgIndividual->setCanResume(canResume);
921 /** No descriptions */
922 void Transfer::slotExecDelay()
928 slotSpeed(0); //need???????
929 m_paDelay
->setChecked(true);
930 emit
statusChanged(this, OP_DELAYED
);
935 /** No descriptions */
936 void Transfer::slotExecSchedule()
942 m_paTimer
->setChecked(true);
943 emit
statusChanged(this, OP_SCHEDULED
);
948 /** No descriptions */
949 void Transfer::slotStartTime(const QDateTime
& _startTime
)
953 setStartTime(_startTime
);
957 /** return true if the dlgIndividual is Visible */
958 bool Transfer::isVisible() const
960 return dlgIndividual
? dlgIndividual
->isVisible() : false;
963 bool Transfer::keepDialogOpen() const
965 return dlgIndividual
? dlgIndividual
->keepDialogOpen() : false;
968 void Transfer::maybeShow()
970 if ( ksettings
.b_showIndividual
&& getStatus() != Transfer::ST_FINISHED
)
973 dlgIndividual
->show();
977 bool Transfer::retryOnError()
979 return (ksettings
.b_reconnectOnError
&& (retryCount
< ksettings
.reconnectRetries
));
982 bool Transfer::retryOnBroken()
984 return (ksettings
.b_reconnectOnBroken
&& (retryCount
< ksettings
.reconnectRetries
));
987 void Transfer::checkCache()
989 assert (mode
== MD_NEW
);
991 if (src
.protocol()=="http")
994 m_pSlave
->Op(Slave::RETR_CACHE
);
1000 void Transfer::NotInCache()
1002 logMessage(i18n("checking if file is in cache...no"));
1003 if (ksettings
.b_addQueued
)
1007 status
= ST_STOPPED
;
1009 #include "transfer.moc"