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 ***************************************************************************/
31 #include <kmessagebox.h>
33 #include <ksimpleconfig.h>
35 #include <kiconloader.h>
36 #include <kstandarddirs.h>
38 #include <kmessagebox.h>
41 #include "safedelete.h"
43 #include "logwindow.h"
44 #include "kmainwidget.h"
45 #include "dlgIndividual.h"
46 #include "transferlist.h"
49 #include <kapplication.h>
50 #include <kio/passdlg.h>
51 #include <kio/global.h>
52 #include <kio/netaccess.h>
55 extern Settings ksettings
;
58 Transfer::Transfer(TransferList
* _view
, const KURL
& _src
, const KURL
& _dest
, const uint _id
)
75 Transfer::Transfer(TransferList
* _view
, Transfer
* after
, const KURL
& _src
, const KURL
& _dest
, const uint _id
)
77 KListViewItem(_view
, (Q3ListViewItem
*) after
),
78 src(_src
), dest(_dest
), view(_view
),
104 Transfer::init(const uint _id
)
107 remainingTimeSec
= 0;
112 m_pSlave
= new Slave(this, src
, dest
);
114 startTime
= QDateTime::currentDateTime();
116 // retryCount = ksettings.reconnectRetries-1;
118 //first off all we need to know if resume is supported...
123 connect(this, SIGNAL(statusChanged(Transfer
*, int)), kmain
, SLOT(slotStatusChanged(Transfer
*, int)));
124 connect(this, SIGNAL(statusChanged(Transfer
*, int)), this, SLOT(slotUpdateActions()));
126 connect(this, SIGNAL(log(uint
, const QString
&, const QString
&)), kmain
->logwin(), SLOT(logTransfer(uint
, const QString
&, const QString
&)));
129 m_paResume
= new KAction(i18n("&Resume"), "tool_resume", 0, this, SLOT(slotResume()), this, "resume");
131 m_paPause
= new KAction(i18n("&Pause"), "tool_pause", 0, this, SLOT(slotRequestPause()), this, "pause");
133 m_paDelete
= new KAction(i18n("&Delete"), "editdelete", 0, this, SLOT(slotRequestRemove()), this, "delete");
135 m_paRestart
= new KAction(i18n("Re&start"), "tool_restart", 0, this, SLOT(slotRequestRestart()), this, "restart");
137 m_paQueue
= new KRadioAction(i18n("&Queue"), "tool_queue", 0, this, SLOT(slotQueue()), this, "queue");
139 m_paTimer
= new KRadioAction(i18n("&Timer"), "tool_timer", 0, this, SLOT(slotRequestSchedule()), this, "timer");
141 m_paDelay
= new KRadioAction(i18n("De&lay"), "tool_delay", 0, this, SLOT(slotRequestDelay()), this, "delay");
143 m_paQueue
->setExclusiveGroup("TransferMode");
144 m_paTimer
->setExclusiveGroup("TransferMode");
145 m_paDelay
->setExclusiveGroup("TransferMode");
149 // m_paDock = new KAction(i18n("&Dock"),"tool_dock", 0, this,SLOT(slotRequestDelay()), this, "dockIndividual");
151 // setup individual transfer dialog
159 void Transfer::synchronousAbort()
163 if ( m_pSlave
->running() )
165 m_pSlave
->Op(Slave::KILL
);
169 if ( m_pSlave
->running() )
170 m_pSlave
->terminate();
181 void Transfer::slotUpdateActions()
183 sDebugIn
<< "the item Status is =" << status
<< "offline=" << ksettings
.b_offline
<< endl
;
184 //if we are offline just disable Resume and Pause and return
185 if (ksettings
.b_offline
) {
186 m_paResume
->setEnabled(false);
187 m_paPause
->setEnabled(false);
188 m_paRestart
->setEnabled(false);
190 dlgIndividual
->update();
198 case ST_TRYING
://fall-through
200 m_paResume
->setEnabled(false);
201 m_paPause
->setEnabled(true);
202 m_paRestart
->setEnabled(true);
206 m_paResume
->setEnabled(true);
207 m_paPause
->setEnabled(false);
208 m_paRestart
->setEnabled(false);
211 m_paResume
->setEnabled(false);
212 m_paPause
->setEnabled(false);
213 m_paRestart
->setEnabled(false);
217 // disable all signals
218 m_paQueue
->blockSignals(true);
219 m_paTimer
->blockSignals(true);
220 m_paDelay
->blockSignals(true);
224 m_paQueue
->setChecked(true);
227 m_paTimer
->setChecked(true);
230 m_paDelay
->setChecked(true);
232 case MD_NEW
: //fall through
234 m_paQueue
->setChecked(false);
235 m_paTimer
->setChecked(false);
236 m_paDelay
->setChecked(false);
238 m_paQueue
->setEnabled(false);
239 m_paTimer
->setEnabled(false);
240 m_paDelay
->setEnabled(false);
246 // enable all signals
247 m_paQueue
->blockSignals(false);
248 m_paTimer
->blockSignals(false);
249 m_paDelay
->blockSignals(false);
252 dlgIndividual
->update();
259 void Transfer::setSpeed(unsigned long _speed
)
264 remainingTimeSec
= KIO::calculateRemainingSeconds(totalSize
, processedSize
, speed
);
265 remainingTime
= KIO::convertSeconds(remainingTimeSec
);
271 void Transfer::updateAll()
275 updateStatus(status
); // first phase of animation
277 logMessage(i18n("Copy file from: %1").arg(src
.prettyURL()));
278 logMessage(i18n("To: %1").arg(dest
.prettyURL()));
281 setText(view
->lv_url
, src
.prettyURL());
284 setText(view
->lv_filename
, dest
.fileName());
288 dlgIndividual
->setCopying(src
, dest
);
289 dlgIndividual
->setCanResume(canResume
);
290 dlgIndividual
->setTotalSize(totalSize
);
291 dlgIndividual
->setPercent(0);
292 dlgIndividual
->setProcessedSize(0);
295 if (totalSize
!= 0) {
296 //logMessage(i18n("Total size is %1 bytes").arg((double)totalSize));
297 setText(view
->lv_total
, KIO::convertSize(totalSize
));
299 //logMessage(i18n("Total size is unknown"));
300 setText(view
->lv_total
, i18n("unknown"));
308 bool Transfer::updateStatus(int counter
)
310 //sDebug<< ">>>>Entering"<<endl;
313 bool isTransfer
= false;
315 view
->setUpdatesEnabled(false);
320 pix
= view
->animConn
.at(counter
);
324 pix
= view
->animTry
.at(counter
);
328 if(mode
== MD_QUEUED
)
329 pix
= &view
->pixQueued
;
330 else if(mode
== MD_SCHEDULED
)
331 pix
= &view
->pixScheduled
;
333 pix
= &view
->pixDelayed
;
336 pix
= &view
->pixFinished
;
339 setPixmap(view
->lv_pixmap
, *pix
);
340 view
->setUpdatesEnabled(true);
342 if(prevStatus
!=status
|| prevMode
!= mode
|| status
==ST_RUNNING
|| status
==ST_TRYING
)
344 QRect rect
= view
->header()->sectionRect(view
->lv_pixmap
);
347 int y
= view
->itemRect(this).y();
348 int w
= rect
.width();
349 int h
= rect
.height();
351 view
->Q3ScrollView::updateContents(x
,y
,w
,h
);
361 void Transfer::UpdateRetry()
366 retry
.setNum(retryCount
);
367 MaxRetry
.setNum(ksettings
.reconnectRetries
);
368 retry
+= " / " + MaxRetry
;
370 setText(view
->lv_count
, retry
);
374 void Transfer::slotResume()
376 sDebugIn
<< " state =" << status
<< endl
;
379 if (retryCount
> ksettings
.reconnectRetries
)
382 assert(status
== ST_STOPPED
);
384 sDebug
<< "src: " << src
.prettyURL() << endl
;
385 sDebug
<< "dest " << dest
.prettyURL() << endl
;
387 m_paResume
->setEnabled(false);
391 logMessage(i18n("Attempt number %1").arg(retryCount
));
393 sDebug
<< "sending Resume to slave " << endl
;
394 m_pSlave
->Op(Slave::RETR
);
400 void Transfer::slotStop()
404 logMessage(i18n("Stopping"));
406 assert(status
<= ST_RUNNING
&& ksettings
.b_offline
);
408 m_pSlave
->Op(Slave::KILL
); // KILL doesn't post a Message
409 sDebug
<< "Killing Slave" << endl
;
414 m_paQueue
->setChecked(true);
422 void Transfer::slotRequestPause()
426 logMessage(i18n("Pausing"));
428 assert(status
<= ST_RUNNING
);
432 m_paPause
->setEnabled(false);
433 m_paRestart
->setEnabled(false);
436 m_pSlave
->Op(Slave::PAUSE
);
437 sDebug
<< "Requesting Pause.." << endl
;
445 void Transfer::slotRequestRestart()
448 m_pSlave
->Op(Slave::RESTART
);
454 void Transfer::slotRequestRemove()
457 if (dlgIndividual
&& !ksettings
.b_expertMode
)
459 if (KMessageBox::warningContinueCancel(0, i18n("Are you sure you want to delete this transfer?"),
460 QString::null
, KStdGuiItem::del(),
461 QString("delete_transfer"))
462 != KMessageBox::Continue
)
465 m_paDelete
->setEnabled(false);
466 m_paPause
->setEnabled(false);
468 dlgIndividual
->close();
470 if ( status
!= ST_FINISHED
)
473 // delete the partly downloaded file, if any
474 file
.setFileName( dest
.fileName() + ".part" ); // ### get it from the job?
476 if ( KIO::NetAccess::exists( file
, false, view
) ) // don't pollute user with warnings
478 SafeDelete::deleteFile( file
); // ### messagebox on failure?
481 if (status
== ST_RUNNING
)
482 m_pSlave
->Op(Slave::REMOVE
);
484 emit
statusChanged(this, OP_REMOVED
);
490 void Transfer::slotQueue()
492 sDebug
<< ">>>>Entering with mode = " << mode
<< endl
;
494 logMessage(i18n("Queueing"));
496 assert(!(mode
== MD_QUEUED
));
499 m_paQueue
->setChecked(true);
500 emit
statusChanged(this, OP_QUEUED
);
505 void Transfer::slotRequestSchedule()
509 logMessage(i18n("Scheduling"));
510 assert(!(mode
== MD_SCHEDULED
));
512 // if the time was already set somewhere in the future, keep it
513 // otherwise set it to the current time + 60 seconds
514 if (startTime
< QDateTime::currentDateTime()) {
515 QDateTime dt
= QDateTime::currentDateTime();
516 startTime
= dt
.addSecs(60);
518 if (status
== ST_RUNNING
) {
519 m_paPause
->setEnabled(false);
520 m_paRestart
->setEnabled(false);
521 m_pSlave
->Op(Slave::SCHEDULE
);
529 void Transfer::slotRequestDelay()
533 logMessage(i18n("Delaying"));
535 assert(!(mode
== MD_DELAYED
));
536 if (status
== ST_RUNNING
) {
537 m_paPause
->setEnabled(false);
538 m_paRestart
->setEnabled(false);
539 m_pSlave
->Op(Slave::DELAY
);
548 void Transfer::slotCanceled(KIO::Job *)
552 logMessage(i18n("Canceled by user"));
553 emit statusChanged(this, OP_CANCELED);
559 void Transfer::slotFinished()
563 logMessage(i18n("Download finished"));
565 status
= ST_FINISHED
;
566 slotProcessedSize(totalSize
);
570 dlgIndividual
->enableOpenFile();
571 emit
statusChanged(this, OP_FINISHED
);
579 void Transfer::slotRenaming(KIO::Job *, const KURL &, const KURL & to)
585 logMessage(i18n("Renaming to %1").arg(dest.prettyURL().ascii()));
588 setText (view->lv_filename, dest.fileName ());
590 dlgIndividual->setCopying (src, dest);
599 void Transfer::slotSpeed(unsigned long bytes_per_second
)
603 setSpeed(bytes_per_second
);
605 if (speed
== 0 && status
== ST_RUNNING
) {
606 setText(view
->lv_speed
, i18n("Stalled"));
607 setText(view
->lv_remaining
, i18n("Stalled"));
609 dlgIndividual
->setSpeed(i18n("Stalled"));
610 } else if (speed
== 0 && status
== ST_FINISHED
) {
612 setText(view
->lv_progress
, i18n("OK as in 'finished'","OK"));
613 setText(view
->lv_speed
, i18n("Finished"));
614 setText(view
->lv_remaining
, i18n("Finished"));
616 dlgIndividual
->setSpeed(i18n("Finished"));
618 } else if (speed
== 0 && status
== ST_STOPPED
) {
621 setText(view
->lv_speed
, i18n("Stopped"));
622 setText(view
->lv_remaining
, i18n("Stopped"));
624 dlgIndividual
->setSpeed(i18n("Stopped"));
627 QString tmps
= i18n("%1/s").arg(KIO::convertSize(speed
));
628 setText(view
->lv_speed
, tmps
);
629 setText(view
->lv_remaining
, remainingTime
);
631 dlgIndividual
->setSpeed(tmps
+ " ( " + remainingTime
+ " ) ");
639 void Transfer::slotTotalSize(KIO::filesize_t bytes
)
642 sDebugIn
<<" totalSize is = "<<totalSize
<< endl
;
645 if (totalSize
== 0) {
647 if (totalSize
!= 0) {
648 logMessage(i18n("Total size is %1 bytes").arg((double)totalSize
,0,'f',0));
649 setText(view
->lv_total
, KIO::convertSize(totalSize
));
652 dlgIndividual
->setTotalSize(totalSize
);
653 dlgIndividual
->setPercent(0);
654 dlgIndividual
->setProcessedSize(0);
660 sDebug
<<"totalSize="<<totalSize
<<" bytes="<<bytes
<<endl
;
661 assert(totalSize
== bytes
);
663 if (totalSize
!= bytes
)
664 logMessage(i18n("The file size does not match."));
666 logMessage(i18n("File Size checked"));
676 void Transfer::slotProcessedSize(KIO::filesize_t bytes
)
678 //sDebug<< ">>>>Entering"<<endl;
681 processedSize
= bytes
;
687 else if ( totalSize
< processedSize
) // bogus totalSize value
689 percent
= 99; // what can we say?
690 totalSize
= processedSize
;
692 setText(view
->lv_total
, KIO::convertSize(totalSize
));
694 dlgIndividual
->setTotalSize(totalSize
);
697 percent
= (int) (((float) processedSize
/ (float) totalSize
) * 100.0);
700 dlgIndividual
->setProcessedSize(processedSize
);
702 if (percent
!= old
) {
704 if (percent
== 100) {
705 tmps
= i18n("OK as in 'finished'","OK");
707 tmps
.setNum(percent
);
710 setText(view
->lv_progress
, tmps
);
713 dlgIndividual
->setPercent(percent
);
715 //sDebug<< "<<<<Leaving"<<endl;
721 void Transfer::showIndividual()
725 // create a DlgIndividual only if it hasn't been created yet
728 dlgIndividual
= new DlgIndividual(this);
729 dlgIndividual
->setLog(transferLog
);
730 dlgIndividual
->setCopying(src
, dest
);
731 dlgIndividual
->setCanResume(canResume
);
732 dlgIndividual
->setTotalSize(totalSize
);
733 dlgIndividual
->setPercent(percent
);
734 dlgIndividual
->setProcessedSize(processedSize
);
737 dlgIndividual
->raise();
740 if (ksettings
.b_iconifyIndividual
) {
741 KWin::iconifyWindow( dlgIndividual
->winId() );
744 // update the actions
746 // then show the single dialog
747 KWin::deIconifyWindow( dlgIndividual
->winId() );
748 dlgIndividual
->show();
754 void Transfer::logMessage(const QString
& message
)
756 sDebugIn
<< message
<< endl
;
758 emit
log(id
, src
.fileName(), message
);
760 QString tmps
= "<font color=\"blue\">" + QTime::currentTime().toString() + "</font> : " + message
;
762 transferLog
.append(tmps
+ '\n');
765 dlgIndividual
->appendLog(tmps
);
772 bool Transfer::read(KSimpleConfig
* config
, int id
)
778 str
.sprintf("Item%d", id
);
779 config
->setGroup(str
);
781 if (src
.isEmpty() || dest
.isEmpty()) {
785 if (!src
.isValid() && !ksettings
.b_expertMode
) {
786 KMessageBox::error(kmain
, i18n("Malformed URL:\n") + src
.prettyURL(), i18n("Error"));
790 mode
= (TransferMode
) config
->readNumEntry("Mode", MD_QUEUED
);
791 status
= (TransferStatus
) config
->readNumEntry("Status", ST_RUNNING
);
792 startTime
= config
->readDateTimeEntry("ScheduledTime");
793 canResume
= config
->readBoolEntry("CanResume", true);
794 totalSize
= config
->readUnsignedNum64Entry("TotalSize", 0);
795 processedSize
= config
->readUnsignedNum64Entry("ProcessedSize", 0);
797 if (status
!= ST_FINISHED
&& totalSize
!= 0) {
798 //TODO insert additional check
808 void Transfer::write(KSimpleConfig
* config
, int id
)
813 str
.sprintf("Item%d", id
);
815 config
->setGroup(str
);
816 config
->writePathEntry("Source", src
.url());
817 config
->writePathEntry("Dest", dest
.url());
818 config
->writeEntry("Mode", mode
);
819 config
->writeEntry("Status", status
);
820 config
->writeEntry("CanResume", canResume
);
821 config
->writeEntry("TotalSize", totalSize
);
822 config
->writeEntry("ProcessedSize", processedSize
);
823 config
->writeEntry("ScheduledTime", startTime
);
829 /** No descriptions */
830 void Transfer::slotExecPause()
836 m_paDelay
->setChecked(true);
839 m_paPause
->setEnabled(false);
840 m_paRestart
->setEnabled(true);
841 m_paResume
->setEnabled(true);
843 //TODO WE NEED TO UPDATE ACTIONS..
844 kmain
->slotUpdateActions();
845 emit
statusChanged(this, OP_PAUSED
);
849 void Transfer::slotExecError()
855 startTime
=QDateTime::currentDateTime().addSecs(ksettings
.reconnectTime
* 60);
856 emit
statusChanged(this, OP_SCHEDULED
);
861 void Transfer::slotExecBroken()
867 emit
statusChanged(this, OP_QUEUED
);
873 void Transfer::slotExecRemove()
878 emit
statusChanged(this, OP_REMOVED
);
883 void Transfer::slotExecResume()
886 emit
statusChanged(this, OP_RESUMED
);
890 void Transfer::slotExecConnected()
895 if (ksettings
.b_offline
)// when we're offline and arrive here, then the file is in cache
896 return; // Slave::slotResult will be called immediately, so we do nothing here
898 m_pSlave
->Op(Slave::KILL
);
899 if (ksettings
.b_addQueued
)
902 emit
statusChanged(this, OP_QUEUED
);
907 emit
statusChanged(this, OP_DELAYED
);
913 emit
statusChanged(this, OP_CONNECTED
);
918 void Transfer::slotCanResume(bool _bCanResume
)
922 canResume
= _bCanResume
;
925 logMessage(i18n("Download resumed"));
926 setText(view
->lv_resume
, i18n("Yes"));
928 setText(view
->lv_resume
, i18n("No"));
931 //dlgIndividual->setCanResume(canResume);
937 /** No descriptions */
938 void Transfer::slotExecDelay()
944 slotSpeed(0); //need???????
945 m_paDelay
->setChecked(true);
946 emit
statusChanged(this, OP_DELAYED
);
951 /** No descriptions */
952 void Transfer::slotExecSchedule()
958 m_paTimer
->setChecked(true);
959 emit
statusChanged(this, OP_SCHEDULED
);
964 /** No descriptions */
965 void Transfer::slotStartTime(const QDateTime
& _startTime
)
969 setStartTime(_startTime
);
973 /** return true if the dlgIndividual is Visible */
974 bool Transfer::isVisible() const
976 return dlgIndividual
? dlgIndividual
->isVisible() : false;
979 bool Transfer::keepDialogOpen() const
981 return dlgIndividual
? dlgIndividual
->keepDialogOpen() : false;
984 void Transfer::maybeShow()
986 if ( ksettings
.b_showIndividual
&& getStatus() != Transfer::ST_FINISHED
)
989 dlgIndividual
->show();
993 bool Transfer::retryOnError()
995 return (ksettings
.b_reconnectOnError
&& (retryCount
< ksettings
.reconnectRetries
));
998 bool Transfer::retryOnBroken()
1000 return (ksettings
.b_reconnectOnBroken
&& (retryCount
< ksettings
.reconnectRetries
));
1003 void Transfer::checkCache()
1005 assert (mode
== MD_NEW
);
1007 if (src
.protocol()=="http")
1010 m_pSlave
->Op(Slave::RETR_CACHE
);
1016 void Transfer::NotInCache()
1018 logMessage(i18n("checking if file is in cache...no"));
1019 if (ksettings
.b_addQueued
)
1023 status
= ST_STOPPED
;
1025 #include "transfer.moc"