Compile with QT_STRICT_ITERATORS definition.
[kdenetwork.git] / kget / core / kget.cpp
blob6a461e7df258e134ee32430e12225aa1a058ee6a
1 /* This file is part of the KDE project
3 Copyright (C) 2005 Dario Massarin <nekkar@libero.it>
4 Copyright (C) 2007-2008 Lukas Appelhans <l.appelhans@gmx.de>
5 Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org>
6 Copyright (C) 2008 Dario Freddi <drf54321@gmail.com>
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
14 #include "core/kget.h"
16 #include "mainwindow.h"
17 #include "core/transfer.h"
18 #include "core/transferdatasource.h"
19 #include "core/transfergroup.h"
20 #include "core/transfergrouphandler.h"
21 #include "core/transfertreemodel.h"
22 #include "core/transfertreeselectionmodel.h"
23 #include "core/plugin/plugin.h"
24 #include "core/plugin/transferfactory.h"
25 #include "core/observer.h"
26 #include "core/kuiserverjobs.h"
27 #include "core/transfergroupscheduler.h"
28 #include "settings.h"
30 #include <kio/netaccess.h>
31 #include <kinputdialog.h>
32 #include <kfiledialog.h>
33 #include <kmessagebox.h>
34 #include <klocale.h>
35 #include <kstandarddirs.h>
36 #include <kservicetypetrader.h>
37 #include <kiconloader.h>
38 #include <kactioncollection.h>
39 #include <kio/renamedialog.h>
40 #include <KSystemTrayIcon>
41 #include <KSharedConfig>
42 #include <KPluginInfo>
44 #include <QTextStream>
45 #include <QDomElement>
46 #include <QApplication>
47 #include <QClipboard>
48 #include <QAbstractItemView>
50 /**
51 * This is our KGet class. This is where the user's transfers and searches are
52 * stored and organized.
53 * Use this class from the views to add or remove transfers or searches
54 * In order to organize the transfers inside categories we have a TransferGroup
55 * class. By definition, a transfer must always belong to a TransferGroup. If we
56 * don't want it to be displayed by the gui inside a specific group, we will put
57 * it in the group named "Not grouped" (better name?).
58 **/
60 KGet& KGet::self( MainWindow * mainWindow )
62 if(mainWindow)
64 m_mainWindow = mainWindow;
67 static KGet m;
68 return m;
71 void KGet::addObserver(ModelObserver * observer)
73 kDebug(5001);
75 m_observers.append(observer);
77 //Update the new observer with the TransferGroups objects of the model
78 QList<TransferGroup *>::const_iterator it = m_transferTreeModel->transferGroups().begin();
79 QList<TransferGroup *>::const_iterator itEnd = m_transferTreeModel->transferGroups().end();
81 for( ; it!=itEnd ; ++it )
83 postAddedTransferGroupEvent(*it, observer);
86 kDebug(5001) << " >>> EXITING";
89 void KGet::delObserver(ModelObserver * observer)
91 m_observers.removeAll(observer);
94 bool KGet::addGroup(const QString& groupName)
96 kDebug(5001);
98 // Check if a group with that name already exists
99 if(m_transferTreeModel->findGroup(groupName))
100 return false;
102 TransferGroup * group = new TransferGroup(m_transferTreeModel, m_scheduler, groupName);
103 m_transferTreeModel->addGroup(group);
105 //post notifications
106 postAddedTransferGroupEvent(group);
108 return true;
111 void KGet::delGroup(const QString& groupName)
113 TransferGroup * group = m_transferTreeModel->findGroup(groupName);
115 if(group)
117 m_transferTreeModel->delGroup(group);
118 postRemovedTransferGroupEvent(group);
119 delete(group);
123 void KGet::renameGroup(const QString& oldName, const QString& newName)
125 TransferGroup *group = m_transferTreeModel->findGroup(oldName);
127 if(group)
129 group->handler()->setName(newName);
133 QStringList KGet::transferGroupNames()
135 QStringList names;
137 foreach(TransferGroup *group, m_transferTreeModel->transferGroups()) {
138 names << group->name();
141 return names;
144 void KGet::addTransfer(KUrl srcUrl, QString destDir, // krazy:exclude=passbyvalue
145 const QString& groupName, bool start)
147 kDebug(5001) << "Source:" << srcUrl.url();
149 KUrl destUrl;
151 if ( srcUrl.isEmpty() )
153 //No src location: we let the user insert it manually
154 srcUrl = urlInputDialog();
155 if( srcUrl.isEmpty() )
156 return;
159 if ( !isValidSource( srcUrl ) )
160 return;
162 if (destDir.isEmpty())
164 if (Settings::useDefaultDirectory())
165 #ifdef Q_OS_WIN //krazy:exclude=cpp
166 destDir = Settings::defaultDirectory().remove("file:///");
167 #else
168 destDir = Settings::defaultDirectory().remove("file://");
169 #endif
171 QString checkExceptions = getSaveDirectoryFromExceptions(srcUrl);
172 if (Settings::enableExceptions() && !checkExceptions.isEmpty())
173 destDir = checkExceptions;
176 if (!isValidDestDirectory(destDir))
177 destDir = destInputDialog();
179 if( (destUrl = getValidDestUrl( destDir, srcUrl )).isEmpty() )
180 return;
182 if(m_transferTreeModel->findTransferByDestination(destUrl) != 0 || (destUrl.isLocalFile() && QFile::exists(destUrl.path()))) {
183 KIO::RenameDialog dlg( m_mainWindow, i18n("Rename transfer"), srcUrl,
184 destUrl, KIO::M_MULTI);
185 if (dlg.exec() == KIO::R_RENAME)
186 destUrl = dlg.newDestUrl();
187 else
188 return;
190 createTransfer(srcUrl, destUrl, groupName, start);
193 void KGet::addTransfer(const QDomElement& e, const QString& groupName)
195 //We need to read these attributes now in order to know which transfer
196 //plugin to use.
197 KUrl srcUrl = KUrl( e.attribute("Source") );
198 KUrl destUrl = KUrl( e.attribute("Dest") );
200 kDebug(5001) << " src= " << srcUrl.url()
201 << " dest= " << destUrl.url()
202 << " group= "<< groupName << endl;
204 if ( srcUrl.isEmpty() || !isValidSource(srcUrl)
205 || !isValidDestDirectory(destUrl.directory()) )
206 return;
208 createTransfer(srcUrl, destUrl, groupName, false, &e);
211 void KGet::addTransfer(KUrl::List srcUrls, QString destDir, // krazy:exclude=passbyvalue
212 const QString& groupName, bool start)
214 KUrl::List urlsToDownload;
216 KUrl::List::Iterator it = srcUrls.begin();
217 KUrl::List::Iterator itEnd = srcUrls.end();
219 for(; it!=itEnd ; ++it)
221 if ( isValidSource( *it ) )
222 urlsToDownload.append( *it );
225 if ( urlsToDownload.count() == 0 )
226 return;
228 if ( urlsToDownload.count() == 1 )
230 // just one file -> ask for filename
231 addTransfer(srcUrls.first(), destDir + srcUrls.first().fileName(), groupName, start);
232 return;
235 KUrl destUrl;
237 // multiple files -> ask for directory, not for every single filename
238 if (!isValidDestDirectory(destDir) && !Settings::useDefaultDirectory())
239 destDir = destInputDialog();
241 it = urlsToDownload.begin();
242 itEnd = urlsToDownload.end();
244 for ( ; it != itEnd; ++it )
246 if (destDir.isEmpty())
248 if (Settings::useDefaultDirectory())
249 #ifdef Q_OS_WIN //krazy:exclude=cpp
250 destDir = Settings::defaultDirectory().remove("file:///");
251 #else
252 destDir = Settings::defaultDirectory().remove("file://");
253 #endif
255 QString checkExceptions = getSaveDirectoryFromExceptions(*it);
256 if (Settings::enableExceptions() && !checkExceptions.isEmpty())
257 destDir = checkExceptions;
259 destUrl = getValidDestUrl(destDir, *it);
261 if(!isValidDestUrl(destUrl))
262 continue;
264 createTransfer(*it, destUrl, groupName, start);
269 bool KGet::delTransfer(TransferHandler * transfer)
271 Transfer * t = transfer->m_transfer;
272 t->stop();
274 m_transferTreeModel->delTransfer(t);
276 //Here I delete the Transfer. The other possibility is to move it to a list
277 //and to delete all these transfers when kget gets closed. Obviously, after
278 //the notification to the views that the transfer has been removed, all the
279 //pointers to it are invalid.
280 transfer->postDeleteEvent();
281 delete t;
282 return true;
285 void KGet::moveTransfer(TransferHandler * transfer, const QString& groupName)
287 Q_UNUSED(transfer);
288 Q_UNUSED(groupName);
291 void KGet::redownloadTransfer(TransferHandler * transfer)
293 QString group = transfer->group()->name();
294 QString src = transfer->source().url();
295 QString dest = transfer->dest().url();
296 bool running = false;
297 if (transfer->status() == Job::Running)
298 running = true;
300 KGet::delTransfer(transfer);
301 KGet::addTransfer(src, dest, group, running);
304 QList<TransferHandler *> KGet::selectedTransfers()
306 // kDebug(5001) << "KGet::selectedTransfers";
308 QList<TransferHandler *> selectedTransfers;
310 QModelIndexList selectedIndexes = m_selectionModel->selectedRows();
312 foreach(const QModelIndex &currentIndex, selectedIndexes)
314 if(!m_transferTreeModel->isTransferGroup(currentIndex))
315 selectedTransfers.append(static_cast<TransferHandler *> (currentIndex.internalPointer()));
318 return selectedTransfers;
321 // This is the code that was used in the old selectedTransfers function
322 /* QList<TransferGroup *>::const_iterator it = m_transferTreeModel->transferGroups().begin();
323 QList<TransferGroup *>::const_iterator itEnd = m_transferTreeModel->transferGroups().end();
325 for( ; it!=itEnd ; ++it )
327 TransferGroup::iterator it2 = (*it)->begin();
328 TransferGroup::iterator it2End = (*it)->end();
330 for( ; it2!=it2End ; ++it2 )
332 Transfer * transfer = (Transfer*) *it2;
334 if( transfer->isSelected() )
335 selectedTransfers.append( transfer->handler() );
338 return selectedTransfers;*/
341 QList<TransferHandler *> KGet::finishedTransfers()
343 QList<TransferHandler *> finishedTransfers;
345 foreach(TransferHandler *transfer, allTransfers())
347 if (transfer->status() == Job::Finished) {
348 finishedTransfers << transfer;
351 return finishedTransfers;
354 QList<TransferGroupHandler *> KGet::selectedTransferGroups()
356 QList<TransferGroupHandler *> selectedTransferGroups;
358 QModelIndexList selectedIndexes = m_selectionModel->selectedRows();
360 foreach(const QModelIndex &currentIndex, selectedIndexes)
362 if(m_transferTreeModel->isTransferGroup(currentIndex))
363 selectedTransferGroups.append(static_cast<TransferGroupHandler *> (currentIndex.internalPointer()));
366 return selectedTransferGroups;
369 TransferTreeSelectionModel * KGet::selectionModel()
371 return m_selectionModel;
374 void KGet::addTransferView(QAbstractItemView * view)
376 view->setModel(m_transferTreeModel);
379 void KGet::load( QString filename ) // krazy:exclude=passbyvalue
381 kDebug(5001) << "(" << filename << ")";
383 if(filename.isEmpty())
384 filename = KStandardDirs::locateLocal("appdata", "transfers.kgt");
386 QString tmpFile;
388 //Try to save the transferlist to a temporary location
389 if(!KIO::NetAccess::download(KUrl(filename), tmpFile, 0))
390 return;
392 QFile file(tmpFile);
393 QDomDocument doc;
395 kDebug(5001) << "file:" << filename;
397 if(doc.setContent(&file))
399 QDomElement root = doc.documentElement();
401 QDomNodeList nodeList = root.elementsByTagName("TransferGroup");
402 int nItems = nodeList.length();
404 for( int i = 0 ; i < nItems ; i++ )
406 TransferGroup * foundGroup = m_transferTreeModel->findGroup( nodeList.item(i).toElement().attribute("Name") );
408 kDebug(5001) << "KGet::load -> group = " << nodeList.item(i).toElement().attribute("Name");
410 if( !foundGroup )
412 kDebug(5001) << "KGet::load -> group not found";
414 TransferGroup * newGroup = new TransferGroup(m_transferTreeModel, m_scheduler);
416 m_transferTreeModel->addGroup(newGroup);
418 newGroup->load(nodeList.item(i).toElement());
420 //Post notifications
421 postAddedTransferGroupEvent(newGroup);
423 else
425 kDebug(5001) << "KGet::load -> group found";
427 //A group with this name already exists.
428 //Integrate the group's transfers with the ones read from file
429 foundGroup->load(nodeList.item(i).toElement());
433 else
435 kWarning(5001) << "Error reading the transfers file";
438 addObserver(new GenericModelObserver());
441 void KGet::save( QString filename, bool plain ) // krazy:exclude=passbyvalue
443 if ( !filename.isEmpty()
444 && QFile::exists( filename )
445 && (KMessageBox::questionYesNoCancel(0,
446 i18n("The file %1 already exists.\nOverwrite?", filename),
447 i18n("Overwrite existing file?"), KStandardGuiItem::yes(),
448 KStandardGuiItem::no(), KStandardGuiItem::cancel(), "QuestionFilenameExists" )
449 != KMessageBox::Yes) )
450 return;
452 if(filename.isEmpty())
453 filename = KStandardDirs::locateLocal("appdata", "transfers.kgt");
455 QFile file(filename);
456 if ( !file.open( QIODevice::WriteOnly ) )
458 //kWarning(5001)<<"Unable to open output file when saving";
459 KMessageBox::error(0,
460 i18n("Unable to save to: %1", filename),
461 i18n("Error"));
463 return;
466 if (plain) {
467 QTextStream out(&file);
468 foreach(TransferHandler *handler, allTransfers()) {
469 out << handler->source().prettyUrl() << endl;
472 else {
473 QDomDocument doc(QString("KGetTransfers"));
474 QDomElement root = doc.createElement("Transfers");
475 doc.appendChild(root);
477 QList<TransferGroup *>::const_iterator it = m_transferTreeModel->transferGroups().begin();
478 QList<TransferGroup *>::const_iterator itEnd = m_transferTreeModel->transferGroups().end();
480 for ( ; it!=itEnd ; ++it )
482 QDomElement e = doc.createElement("TransferGroup");
483 root.appendChild(e);
484 (*it)->save(e);
487 QTextStream stream( &file );
488 doc.save( stream, 0 );
490 file.close();
493 TransferFactory * KGet::factory(TransferHandler * transfer)
495 return transfer->m_transfer->factory();
498 KActionCollection * KGet::actionCollection()
500 return m_mainWindow->actionCollection();
503 void KGet::setSchedulerRunning(bool running)
505 if(running)
507 m_scheduler->stop(); //stopall first, to have a clean startingpoint
508 m_scheduler->start();
510 else
511 m_scheduler->stop();
514 bool KGet::schedulerRunning()
516 return (m_scheduler->countRunningJobs() > 0);
519 QList<TransferHandler*> KGet::allTransfers()
521 QList<TransferHandler*> transfers;
523 foreach (TransferGroup *group, KGet::m_transferTreeModel->transferGroups())
525 transfers << group->handler()->transfers();
527 return transfers;
530 QList<TransferGroupHandler*> KGet::allTransferGroups()
532 QList<TransferGroupHandler*> transfergroups;
534 foreach (TransferGroup *group, KGet::m_transferTreeModel->transferGroups())
536 transfergroups << group->handler();
538 return transfergroups;
541 TransferHandler * KGet::findTransfer(const KUrl &src)
543 return KGet::m_transferTreeModel->findTransfer(src)->handler();
546 void KGet::checkSystemTray()
548 kDebug(5001);
549 bool running = false;
551 foreach (TransferHandler *handler, KGet::allTransfers())
553 if (handler->status() == Job::Running)
554 running = true;
556 if (running)
557 continue;
560 m_mainWindow->setSystemTrayDownloading(running);
563 void KGet::settingsChanged()
565 kDebug(5001);
567 QList<TransferFactory*>::const_iterator it = m_transferFactories.constBegin();
568 QList<TransferFactory*>::const_iterator itEnd = m_transferFactories.constEnd();
570 for( ; it!=itEnd ; ++it )
572 (*it)->settingsChanged();
576 void KGet::registerKJob(KJob *job)
578 m_jobManager->registerJob(job);
581 void KGet::unregisterKJob(KJob *job)
583 m_jobManager->unregisterJob(job);
586 void KGet::reloadKJobs()
588 m_jobManager->reload();
591 QStringList KGet::defaultFolders(const KUrl &filename, const QString &groupname)
593 kDebug(5001) << filename << groupname;
595 QStringList list;
596 const QString saveDirectoryFromExceptions = KGet::getSaveDirectoryFromExceptions(filename);
597 if (Settings::enableExceptions() && !saveDirectoryFromExceptions.isEmpty())
598 list.append(saveDirectoryFromExceptions);
600 TransferGroup * group = KGet::m_transferTreeModel->findGroup(groupname);
602 if (!group->defaultFolder().isEmpty())
603 list.append(group->defaultFolder());
605 if (Settings::useDefaultDirectory())
606 list.append(Settings::defaultDirectory());
608 if (!Settings::lastDirectory().isEmpty() &&
609 QString::compare(Settings::lastDirectory(), Settings::defaultDirectory()) != 0)
610 list.append(Settings::lastDirectory());
612 if (list.isEmpty())
613 list.append(QDir::homePath());//If we have no defaultDir, we return the home-dir
615 for (int i = 0; i < list.size(); i++)
617 #ifdef Q_OS_WIN //krazy:exclude=cpp
618 list[i] = list[i].remove("file:///");
619 #else
620 list[i] = list[i].remove("file://");
621 #endif
623 return list;
626 void KGet::setGlobalDownloadLimit(int limit)
628 m_scheduler->setDownloadLimit(limit);
629 if (!limit)
630 m_scheduler->calculateDownloadLimit();
633 void KGet::setGlobalUploadLimit(int limit)
635 m_scheduler->setUploadLimit(limit);
636 if (!limit)
637 m_scheduler->calculateUploadLimit();
640 void KGet::calculateGlobalSpeedLimits()
642 if (m_scheduler->downloadLimit())//TODO: Remove this and the both other hacks in the 2 upper functions with a better replacement
643 m_scheduler->calculateDownloadLimit();
644 if (m_scheduler->uploadLimit())
645 m_scheduler->calculateUploadLimit();
648 void KGet::calculateGlobalDownloadLimit()
650 m_scheduler->calculateDownloadLimit();
653 void KGet::calculateGlobalUploadLimit()
655 m_scheduler->calculateUploadLimit();
658 // ------ STATIC MEMBERS INITIALIZATION ------
659 QList<ModelObserver *> KGet::m_observers;
660 TransferTreeModel * KGet::m_transferTreeModel;
661 TransferTreeSelectionModel * KGet::m_selectionModel;
662 QList<TransferFactory *> KGet::m_transferFactories;
663 TransferGroupScheduler * KGet::m_scheduler = new TransferGroupScheduler();
664 MainWindow * KGet::m_mainWindow = 0;
665 KUiServerJobs * KGet::m_jobManager = new KUiServerJobs();
667 // ------ PRIVATE FUNCTIONS ------
668 KGet::KGet()
670 m_transferTreeModel = new TransferTreeModel(m_scheduler);
671 m_selectionModel = new TransferTreeSelectionModel(m_transferTreeModel);
673 //Load all the available plugins
674 loadPlugins();
676 //Create the default group
677 addGroup(i18n("My Downloads"));
680 KGet::~KGet()
682 delete m_scheduler;
685 bool KGet::createTransfer(const KUrl &src, const KUrl &dest, const QString& groupName,
686 bool start, const QDomElement * e)
688 kDebug(5001) << "srcUrl= " << src.url() << " "
689 << "destUrl= " << dest.url()
690 << "group= _" << groupName << "_" << endl;
692 TransferGroup * group = m_transferTreeModel->findGroup(groupName);
693 if (group==0)
695 kDebug(5001) << "KGet::createTransfer -> group not found";
696 group = m_transferTreeModel->transferGroups().first();
698 Transfer * newTransfer;
700 QList<TransferFactory *>::iterator it = m_transferFactories.begin();
701 QList<TransferFactory *>::iterator itEnd = m_transferFactories.end();
703 for( ; it!=itEnd ; ++it)
705 kDebug(5001) << "Trying plugin n.plugins=" << m_transferFactories.size();
706 if((newTransfer = (*it)->createTransfer(src, dest, group, m_scheduler, e)))
708 // kDebug(5001) << "KGet::createTransfer -> CREATING NEW TRANSFER ON GROUP: _" << group->name() << "_";
709 m_transferTreeModel->addTransfer(newTransfer, group);
711 if(start)
712 newTransfer->handler()->start();
714 if (newTransfer->percent() != 100) //Don't add a finished observer if the Transfer has already been finished
715 newTransfer->handler()->addObserver(new GenericTransferObserver());
717 return true;
720 kDebug(5001) << "Warning! No plugin found to handle the given url";
721 return false;
724 TransferDataSource * KGet::createTransferDataSource(const KUrl &src)
726 kDebug(5001);
727 QList<TransferFactory *>::iterator it = m_transferFactories.begin();
728 QList<TransferFactory *>::iterator itEnd = m_transferFactories.end();
730 TransferDataSource *dataSource;
731 for( ; it!=itEnd ; ++it)
733 dataSource = (*it)->createTransferDataSource(src);
734 if(dataSource)
735 return dataSource;
737 return 0;
740 void KGet::postAddedTransferGroupEvent(TransferGroup * group, ModelObserver * observer)
742 kDebug(5001);
743 if(observer)
745 observer->addedTransferGroupEvent(group->handler());
746 return;
749 QList<ModelObserver *>::iterator it = m_observers.begin();
750 QList<ModelObserver *>::iterator itEnd = m_observers.end();
752 for(; it!=itEnd; ++it)
754 kDebug(5001) << "message posted";
756 (*it)->addedTransferGroupEvent(group->handler());
760 void KGet::postRemovedTransferGroupEvent(TransferGroup * group, ModelObserver * observer)
762 if(observer)
764 observer->removedTransferGroupEvent(group->handler());
765 return;
768 QList<ModelObserver *>::iterator it = m_observers.begin();
769 QList<ModelObserver *>::iterator itEnd = m_observers.end();
771 for(; it!=itEnd; ++it)
773 (*it)->removedTransferGroupEvent(group->handler());
777 KUrl KGet::urlInputDialog()
779 QString newtransfer;
780 bool ok = false;
782 KUrl clipboardUrl = KUrl(QApplication::clipboard()->text(QClipboard::Clipboard).trimmed());
783 if (clipboardUrl.isValid())
784 newtransfer = clipboardUrl.url();
786 while (!ok)
788 newtransfer = KInputDialog::getText(i18n("New Download"), i18n("Enter URL:"), newtransfer, &ok, 0);
790 if (!ok)
792 //user pressed cancel
793 return KUrl();
796 KUrl src = KUrl(newtransfer);
797 if(src.isValid())
798 return src;
799 else
800 ok = false;
802 return KUrl();
805 QString KGet::destInputDialog()
807 QString destDir = KFileDialog::getExistingDirectory(Settings::lastDirectory());
809 Settings::setLastDirectory( destDir );
810 return destDir;
813 QString KGet::getSaveDirectoryFromExceptions(const KUrl &filename)
815 QString destDir;
817 const QStringList list = Settings::extensionsFolderList();
818 QStringList::ConstIterator it = list.begin();
819 const QStringList::ConstIterator end = list.end();
820 while (it != end) {
821 // odd list items are regular expressions for extensions
822 QString ext = *it;
823 ++it;
824 QString path = *it;
825 ++it;
827 if (!ext.startsWith('*'))
828 ext = '*' + ext;
830 QRegExp rexp(ext);
831 rexp.setPatternSyntax(QRegExp::Wildcard);
833 if (rexp.exactMatch(filename.url())) {
834 destDir = path;
835 break;
839 #ifdef Q_OS_WIN //krazy:exclude=cpp
840 destDir = destDir.remove("file:///");
841 #endif
842 return destDir.remove("file://");
845 bool KGet::isValidSource(const KUrl &source)
847 // Check if the URL is well formed
848 if (!source.isValid())
850 KMessageBox::error(0,
851 i18n("Malformed URL:\n%1", source.prettyUrl()),
852 i18n("Error"));
854 return false;
856 // Check if the URL contains the protocol
857 if ( source.protocol().isEmpty() ){
859 KMessageBox::error(0, i18n("Malformed URL, protocol missing:\n%1", source.prettyUrl()),
860 i18n("Error"));
862 return false;
864 // Check if a transfer with the same url already exists
865 Transfer * transfer = m_transferTreeModel->findTransfer( source );
866 if ( transfer )
868 if ( transfer->status() == Job::Finished )
870 // transfer is finished, ask if we want to download again
871 if (KMessageBox::questionYesNoCancel(0,
872 i18n("URL already saved:\n%1\nDownload again?", source.prettyUrl()),
873 i18n("Download URL again?"), KStandardGuiItem::yes(),
874 KStandardGuiItem::no(), KStandardGuiItem::cancel(), "QuestionUrlAlreadySaved" )
875 == KMessageBox::Yes)
877 transfer->stop();
878 TransferHandler * th = transfer->handler();
879 //TODO If the transfer is expanded, it crash.
880 // transfer should be collapsed before.
881 // Is correct close it from the KGet class or should it
882 // be handled in the viewscontainer?
883 // KGet class should be generic, it shouldn't
884 // interfere with the UI
885 KGet::delTransfer(th);
886 return true;
889 else
891 //Transfer is already in list and not finished, ...
892 return false;
894 return false;
896 return true;
899 bool KGet::isValidDestDirectory(const QString & destDir)
901 kDebug(5001) << destDir;
902 if (!QFileInfo(destDir).isDir())
904 if (QFileInfo(KUrl(destDir).directory()).isWritable())
905 return (!destDir.isEmpty());
906 if (!QFileInfo(KUrl(destDir).directory()).isWritable() && !destDir.isEmpty())
907 KMessageBox::error(0, i18n("Directory is not writable"));
909 else
911 if (QFileInfo(destDir).isWritable())
912 return (!destDir.isEmpty());
913 if (!QFileInfo(destDir).isWritable() && !destDir.isEmpty())
914 KMessageBox::error(0, i18n("Directory is not writable"));
916 return false;
919 bool KGet::isValidDestUrl(const KUrl &destUrl)
921 if(KIO::NetAccess::exists(destUrl, KIO::NetAccess::DestinationSide, 0))
923 if (KMessageBox::warningYesNoCancel(0,
924 i18n("Destination file \n%1\nalready exists.\n"
925 "Do you want to overwrite it?", destUrl.prettyUrl()))
926 == KMessageBox::Yes)
928 safeDeleteFile( destUrl );
929 return true;
931 else
932 return false;
934 if (m_transferTreeModel->findTransferByDestination(destUrl) || destUrl.isEmpty())
935 return false;
937 return true;
939 KIO::open_RenameDlg(i18n("File already exists"),
940 (*it).url(), destUrl.url(),
941 KIO::M_MULTI);
945 KUrl KGet::getValidDestUrl(const QString& destDir, const KUrl &srcUrl)
947 if ( !isValidDestDirectory(destDir) )
948 return KUrl();
950 // create a proper destination file from destDir
951 KUrl destUrl = KUrl( destDir );
952 QString filename = srcUrl.fileName();
954 if ( filename.isEmpty() )
956 // simply use the full url as filename
957 filename = KUrl::toPercentEncoding( srcUrl.prettyUrl(), "/" );
958 kDebug(5001) << " Filename is empty. Setting to " << filename;
959 kDebug(5001) << " srcUrl = " << srcUrl.url();
960 kDebug(5001) << " prettyUrl = " << srcUrl.prettyUrl();
962 if (QFileInfo(destUrl.path()).isDir())
964 kDebug(5001) << " Filename is not empty";
965 destUrl.adjustPath( KUrl::AddTrailingSlash );
966 destUrl.setFileName( filename );
968 if (!isValidDestUrl(destUrl))
970 kDebug(5001) << " destUrl " << destUrl.path() << " is not valid";
971 return KUrl();
973 return destUrl;
976 void KGet::loadPlugins()
978 m_transferFactories.clear();
979 // Add versioning constraint
980 QString
981 str = "[X-KDE-KGet-framework-version] == ";
982 str += QString::number( FrameworkVersion );
983 str += " and ";
984 str += "[X-KDE-KGet-rank] > 0";
985 str += " and ";
986 str += "[X-KDE-KGet-plugintype] == ";
988 KService::List offers;
990 //TransferFactory plugins
991 offers = KServiceTypeTrader::self()->query( "KGet/Plugin", str + "'TransferFactory'" );
993 //Here we use a QMap only to easily sort the plugins by rank
994 QMap<int, KService::Ptr> services;
995 QMap<int, KService::Ptr>::iterator it;
997 for ( int i = 0; i < offers.count(); ++i )
999 services[ offers[i]->property( "X-KDE-KGet-rank" ).toInt() ] = offers[i];
1000 kDebug(5001) << " TransferFactory plugin found:" << endl <<
1001 " rank = " << offers[i]->property( "X-KDE-KGet-rank" ).toInt() << endl <<
1002 " plugintype = " << offers[i]->property( "X-KDE-KGet-plugintype" ) << endl;
1005 //I must fill this pluginList before and my m_transferFactories list after.
1006 //This because calling the KLibLoader::globalLibrary() erases the static
1007 //members of this class (why?), such as the m_transferFactories list.
1008 QList<KGetPlugin *> pluginList;
1010 KConfigGroup plugins = KConfigGroup(KGlobal::config(), "Plugins");
1012 for( it = services.begin(); it != services.end(); ++it )
1014 KPluginInfo info(*it);
1015 info.load(plugins);
1017 if( !info.isPluginEnabled() ) {
1018 kDebug(5001) << "TransferFactory plugin (" << (*it)->library()
1019 << ") found, but not enabled";
1020 continue;
1023 KGetPlugin * plugin;
1024 if( (plugin = createPluginFromService(*it)) != 0 )
1026 QString pluginName = info.name();
1028 pluginList.prepend(plugin);
1029 kDebug(5001) << "TransferFactory plugin (" << (*it)->library()
1030 << ") found and added to the list of available plugins";
1033 else
1034 kDebug(5001) << "Error loading TransferFactory plugin ("
1035 << (*it)->library() << ")";
1038 QList<KGetPlugin *>::iterator it2 = pluginList.begin();
1039 QList<KGetPlugin *>::iterator it2End = pluginList.end();
1041 for( ; it2!=it2End ; ++it2 )
1042 m_transferFactories.append( qobject_cast<TransferFactory *>(*it2) );
1044 kDebug(5001) << "Number of factories = " << m_transferFactories.size();
1047 KGetPlugin * KGet::createPluginFromService( const KService::Ptr &service )
1049 //try to load the specified library
1050 KPluginFactory *factory = KPluginLoader(service->library()).factory();
1052 if (!factory)
1054 KMessageBox::error(0, i18n("<html><p>Plugin loader could not load the plugin:<br/><i>%1</i></p></html>",
1055 service->library()));
1056 kError(5001) << "KPluginFactory could not load the plugin:" << service->library();
1057 return 0;
1059 KGetPlugin * plugin = factory->create< TransferFactory >(KGet::m_mainWindow);
1061 return plugin;
1064 bool KGet::safeDeleteFile( const KUrl& url )
1066 if ( url.isLocalFile() )
1068 QFileInfo info( url.path() );
1069 if ( info.isDir() )
1071 KGet::showNotification(m_mainWindow, KNotification::Notification,
1072 i18n("Not deleting\n%1\nas it is a directory.", url.prettyUrl()),
1073 "dialog-info");
1074 return false;
1076 KIO::NetAccess::del( url, 0L );
1077 return true;
1080 else
1081 KGet::showNotification(m_mainWindow, KNotification::Notification,
1082 i18n("Not deleting\n%1\nas it is not a local file.", url.prettyUrl()),
1083 "dialog-info");
1084 return false;
1087 void KGet::showNotification(QWidget *parent, KNotification::StandardEvent eventId,
1088 const QString &text, const QString &icon)
1090 KNotification::event(eventId, text, KIcon(icon).pixmap(KIconLoader::Small), parent);
1093 GenericModelObserver::GenericModelObserver(QObject *parent) : QObject(parent)
1095 m_groupObserver = new GenericTransferGroupObserver();
1098 GenericModelObserver::~GenericModelObserver()
1100 delete m_groupObserver;
1103 void GenericModelObserver::addedTransferGroupEvent(TransferGroupHandler * group)
1105 Q_UNUSED(group)
1106 kDebug() << "OBSERVER :: Adding group " << group;
1107 group->addObserver(m_groupObserver);
1109 // we need to do this to add the genericTransfer to all the transfers under the group
1110 m_groupObserver->addTransferGroup(group);
1112 KGet::save();
1115 void GenericModelObserver::removedTransferGroupEvent(TransferGroupHandler * group)
1117 Q_UNUSED(group)
1118 group->delObserver(m_groupObserver);
1119 KGet::save();