kget.cpp 54.1 KB
Newer Older
1 2 3
/* This file is part of the KDE project

   Copyright (C) 2005 Dario Massarin <nekkar@libero.it>
4
   Copyright (C) 2007-2009 Lukas Appelhans <l.appelhans@gmx.de>
5
   Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org>
6
   Copyright (C) 2008 Dario Freddi <drf54321@gmail.com>
7
   Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>
8 9 10

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
11 12
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
13 14
*/

Urs Wolfer's avatar
Urs Wolfer committed
15 16 17
#include "core/kget.h"

#include "mainwindow.h"
18
#include "core/mostlocalurl.h"
Urs Wolfer's avatar
Urs Wolfer committed
19
#include "core/transfer.h"
20
#include "core/transferdatasource.h"
Urs Wolfer's avatar
Urs Wolfer committed
21
#include "core/transfergroup.h"
22
#include "core/transfergrouphandler.h"
Urs Wolfer's avatar
Urs Wolfer committed
23 24 25 26
#include "core/transfertreemodel.h"
#include "core/transfertreeselectionmodel.h"
#include "core/plugin/plugin.h"
#include "core/plugin/transferfactory.h"
27
#include "core/kuiserverjobs.h"
28
#include "core/transfergroupscheduler.h"
Urs Wolfer's avatar
Urs Wolfer committed
29
#include "settings.h"
30
#include "core/transferhistorystore.h"
31 32 33

#include "kget_debug.h"

Andrius Štikonas's avatar
Andrius Štikonas committed
34
#include <algorithm>
35
#include <iostream>
36 37 38 39 40 41 42 43

#include <KMessageBox>
#include <KLocalizedString>
#include <KServiceTypeTrader>
#include <KIconLoader>
#include <KActionCollection>
#include <KIO/RenameDialog>
#include <KIO/DeleteJob>
44
#include <KSharedConfig>
45
#include <KPluginInfo>
46
#include <KConfigDialog>
47
#include <KPluginMetaData>
48

49
#include <QAbstractItemView>
Urs Wolfer's avatar
Urs Wolfer committed
50
#include <QApplication>
51
#include <QDomElement>
Urs Wolfer's avatar
Urs Wolfer committed
52
#include <QClipboard>
53
#include <QFileDialog>
54 55
#include <QInputDialog>
#include <QSaveFile>
56
#include <QStandardPaths>
57
#include <QTimer>
Heiko Becker's avatar
Heiko Becker committed
58
#include <QTemporaryFile>
59
#include <QTextStream>
60

61
#ifdef HAVE_KWORKSPACE
Wolfgang Bauer's avatar
Wolfgang Bauer committed
62 63 64 65
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCall>
#include <kworkspace.h>
66 67
#endif

68

Lukas Appelhans's avatar
Lukas Appelhans committed
69
KGet::TransferData::TransferData(const QUrl &source, const QUrl &destination, const QString& group, bool doStart, const QDomElement *element)
70 71 72 73 74 75 76 77
  : src(source),
    dest(destination),
    groupName(group),
    start(doStart),
    e(element)
{
}

78
/**
79
 * This is our KGet class. This is where the user's transfers and searches are
80 81 82 83 84 85 86 87
 * stored and organized.
 * Use this class from the views to add or remove transfers or searches 
 * In order to organize the transfers inside categories we have a TransferGroup
 * class. By definition, a transfer must always belong to a TransferGroup. If we 
 * don't want it to be displayed by the gui inside a specific group, we will put 
 * it in the group named "Not grouped" (better name?).
 **/

88
KGet* KGet::self( MainWindow * mainWindow )
89 90 91 92
{
    if(mainWindow)
    {
        m_mainWindow = mainWindow;
93
        m_jobManager = new KUiServerJobs(m_mainWindow);
94 95
    }

96
    static KGet *m = new KGet();
97

98 99 100
    return m;
}

101
bool KGet::addGroup(const QString& groupName)
102
{
103
    qCDebug(KGET_DEBUG);
104

105
    // Check if a group with that name already exists
106
    if (m_transferTreeModel->findGroup(groupName))
107 108
        return false;

109
    TransferGroup * group = new TransferGroup(m_transferTreeModel, m_scheduler, groupName);
110
    m_transferTreeModel->addGroup(group);
Dario Massarin's avatar
Dario Massarin committed
111

112
    return true;
113 114
}

115
void KGet::delGroup(TransferGroupHandler *group, bool askUser)
116
{
117 118 119 120 121 122 123 124 125
    TransferGroup *g = group->m_group;

    if (askUser) {
        QWidget *configDialog = KConfigDialog::exists("preferences");
        if (KMessageBox::warningYesNo(configDialog ? configDialog : m_mainWindow,
                        i18n("Are you sure that you want to remove the group named %1?", g->name()),
                        i18n("Remove Group"),
                        KStandardGuiItem::remove(), KStandardGuiItem::cancel()) != KMessageBox::Yes)
            return;
126
    }
127 128 129

    m_transferTreeModel->delGroup(g);
    g->deleteLater();
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
}

void KGet::delGroups(QList<TransferGroupHandler*> groups, bool askUser)
{
    if (groups.isEmpty())
        return;
    if (groups.count() == 1) {
        KGet::delGroup(groups.first(), askUser);
        return;
    }
    bool del = !askUser;
    if (askUser) {
        QStringList names;
        foreach (TransferGroupHandler * handler, groups)
            names << handler->name();
        QWidget * configDialog = KConfigDialog::exists("preferences");
        del = KMessageBox::warningYesNoList(configDialog ? configDialog : m_mainWindow,
              i18n("Are you sure that you want to remove the following groups?"),
              names,
              i18n("Remove groups"),
              KStandardGuiItem::remove(), KStandardGuiItem::cancel()) == KMessageBox::Yes;
    }
    if (del) {
        foreach (TransferGroupHandler * handler, groups)
            KGet::delGroup(handler, false);
Dario Massarin's avatar
Dario Massarin committed
155
    }
156 157
}

158 159 160 161 162 163 164 165 166 167
void KGet::renameGroup(const QString& oldName, const QString& newName)
{
    TransferGroup *group = m_transferTreeModel->findGroup(oldName);

    if(group)
    {
        group->handler()->setName(newName);
    }
}

Javier Goday's avatar
Javier Goday committed
168 169 170 171 172 173 174 175 176 177 178
QStringList KGet::transferGroupNames()
{
    QStringList names;

    foreach(TransferGroup *group, m_transferTreeModel->transferGroups()) {
        names << group->name();
    }

    return names;
}

Lukas Appelhans's avatar
Lukas Appelhans committed
179
TransferHandler * KGet::addTransfer(QUrl srcUrl, QString destDir, QString suggestedFileName, // krazy:exclude=passbyvalue
180
                                    QString groupName, bool start)
181
{
182
    srcUrl = mostLocalUrl(srcUrl);
Carsten Pfeiffer's avatar
Carsten Pfeiffer committed
183
    // Note: destDir may actually be a full path to a file :-(
Laurent Montel's avatar
Laurent Montel committed
184
    qCDebug(KGET_DEBUG) << "Source:" << srcUrl.url() << ", dest: " << destDir << ", sugg file: " << suggestedFileName;
185

Lukas Appelhans's avatar
Lukas Appelhans committed
186
    QUrl destUrl; // the final destination, including filename
187

Urs Wolfer's avatar
Urs Wolfer committed
188
    if ( srcUrl.isEmpty() )
189 190
    {
        //No src location: we let the user insert it manually
Urs Wolfer's avatar
Urs Wolfer committed
191 192
        srcUrl = urlInputDialog();
        if( srcUrl.isEmpty() )
193
            return nullptr;
194
    }
195
    
Urs Wolfer's avatar
Urs Wolfer committed
196
    if ( !isValidSource( srcUrl ) )
197
        return nullptr;
Dario Massarin's avatar
Dario Massarin committed
198

199 200 201
    // when we get a destination directory and suggested filename, we don't
    // need to ask for it again
    bool confirmDestination = false;
202 203
    if (destDir.isEmpty())
    {
204
        confirmDestination = true;
205
        QList<TransferGroupHandler*> list = groupsFromExceptions(srcUrl);
206
        if (!list.isEmpty()) {
207
            destDir = list.first()->defaultFolder();
208 209 210
            groupName = list.first()->name();
        }
        
Carsten Pfeiffer's avatar
Carsten Pfeiffer committed
211 212
    } else {
        // check whether destDir is actually already the path to a file
213 214
        QUrl targetUrl = QUrl::fromLocalFile(destDir);
        QString directory = targetUrl.adjusted(QUrl::RemoveFilename).path();
Lukas Appelhans's avatar
Lukas Appelhans committed
215
        QString fileName = targetUrl.fileName(QUrl::PrettyDecoded);
216
        if (QFileInfo(directory).isDir() && !fileName.isEmpty()) {
Carsten Pfeiffer's avatar
Carsten Pfeiffer committed
217 218 219
            destDir = directory;
            suggestedFileName = fileName;
        }
220
    }
221

222 223
    if (suggestedFileName.isEmpty())
    {
224
        confirmDestination = true;
Lukas Appelhans's avatar
Lukas Appelhans committed
225
        suggestedFileName = srcUrl.fileName(QUrl::PrettyDecoded);
226 227 228
        if (suggestedFileName.isEmpty())
        {
            // simply use the full url as filename
Lukas Appelhans's avatar
Lukas Appelhans committed
229
            suggestedFileName = QUrl::toPercentEncoding( srcUrl.toDisplayString(), "/" );
230 231
        }
    }
Urs Wolfer's avatar
Urs Wolfer committed
232

233 234 235 236 237 238
    // now ask for confirmation of the entire destination url (dir + filename)
    if (confirmDestination || !isValidDestDirectory(destDir))
    {
        do 
        {
            destUrl = destFileInputDialog(destDir, suggestedFileName);
239
            if (destUrl.isEmpty())
240
                return nullptr;
241

242
            destDir = destUrl.adjusted(QUrl::RemoveFilename).path();
243
        } while (!isValidDestDirectory(destDir));
244
    } else {
245
        destUrl = QUrl::fromLocalFile(destDir + suggestedFileName);
246 247
    }
    destUrl = getValidDestUrl(destUrl, srcUrl);
248

Lukas Appelhans's avatar
Lukas Appelhans committed
249
    if (destUrl == QUrl())
250
        return nullptr;
251 252 253 254

    TransferHandler *transfer = createTransfer(srcUrl, destUrl, groupName, start);
    if (transfer) {
        KGet::showNotification(m_mainWindow, "added",
Lukas Appelhans's avatar
Lukas Appelhans committed
255
                                i18n("<p>The following transfer has been added to the download list:</p><p style=\"font-size: small;\">%1</p>", transfer->source().toString()),
256 257 258 259
                                "kget", i18n("Download added"));
    }

    return transfer;
260 261
}

262
QList<TransferHandler*> KGet::addTransfers(const QList<QDomElement> &elements, const QString &groupName)
Dario Massarin's avatar
Dario Massarin committed
263
{
264
    QList<TransferData> data;
Dario Massarin's avatar
Dario Massarin committed
265

266 267 268
    foreach(const QDomElement &e, elements) {
        //We need to read these attributes now in order to know which transfer
        //plugin to use.
Lukas Appelhans's avatar
Lukas Appelhans committed
269 270
        QUrl srcUrl = QUrl(e.attribute("Source"));
        QUrl destUrl = QUrl(e.attribute("Dest"));
271
        data << TransferData(srcUrl, destUrl, groupName, false, &e);
Dario Massarin's avatar
Dario Massarin committed
272

273
        qCDebug(KGET_DEBUG) << "src=" << srcUrl << " dest=" << destUrl << " group=" << groupName;
274 275 276
    }

    return createTransfers(data);
Dario Massarin's avatar
Dario Massarin committed
277 278
}

Lukas Appelhans's avatar
Lukas Appelhans committed
279
const QList<TransferHandler *> KGet::addTransfer(QList<QUrl> srcUrls, QString destDir, QString groupName, bool start)
280
{
Lukas Appelhans's avatar
Lukas Appelhans committed
281
    QList<QUrl> urlsToDownload;
282

Lukas Appelhans's avatar
Lukas Appelhans committed
283 284
    QList<QUrl>::iterator it = srcUrls.begin();
    QList<QUrl>::iterator itEnd = srcUrls.end();
285 286
    
    QList<TransferHandler *> addedTransfers;
287 288 289

    for(; it!=itEnd ; ++it)
    {
290
        *it = mostLocalUrl(*it);
291 292 293 294 295
        if ( isValidSource( *it ) )
            urlsToDownload.append( *it );
    }

    if ( urlsToDownload.count() == 0 )
296
        return addedTransfers;
297

298 299 300
    if ( urlsToDownload.count() == 1 )
    {
        // just one file -> ask for filename
301
        TransferHandler * newTransfer = addTransfer(srcUrls.first(), destDir, srcUrls.first().fileName(), groupName, start);
302 303

        if (newTransfer) {
304
            addedTransfers.append(newTransfer);
305
        }
306 307

        return addedTransfers;
308
    }
309

Lukas Appelhans's avatar
Lukas Appelhans committed
310
    QUrl destUrl;
311 312

    // multiple files -> ask for directory, not for every single filename
313
    if (!isValidDestDirectory(destDir))//TODO: Move that after the for-loop
314
        destDir = destDirInputDialog();
315

316 317
    it = urlsToDownload.begin();
    itEnd = urlsToDownload.end();
318

319
    QList<TransferData> data;
320 321
    for ( ; it != itEnd; ++it )
    {
322 323
        if (destDir.isEmpty())
        {
324
            //TODO only use groupsFromExceptions if that is allowed in the settings
325
            QList<TransferGroupHandler*> list = groupsFromExceptions(*it);
326
            if (!list.isEmpty()) {
327
                destDir = list.first()->defaultFolder();
328 329
                groupName = list.first()->name();
            }
330
        }
331
        destUrl = getValidDestUrl(QUrl::fromLocalFile(destDir), *it);
332

Lukas Appelhans's avatar
Lukas Appelhans committed
333
        if (destUrl == QUrl())
334
            continue;
335

336
        data << TransferData(*it, destUrl, groupName, start);
337
    }
338 339 340

    QList<TransferHandler*> transfers = createTransfers(data);
    if (!transfers.isEmpty()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
341
        QString urls = transfers[0]->source().toString();
342
        for (int i = 1; i < transfers.count(); ++i) {
Lukas Appelhans's avatar
Lukas Appelhans committed
343
            urls += '\n' + transfers[i]->source().toString();
344 345 346 347 348 349 350 351
        }

        QString message;
        if (transfers.count() == 1) {
            message = i18n("<p>The following transfer has been added to the download list:</p>");
        } else {
            message = i18n("<p>The following transfers have been added to the download list:</p>");
        }
352
        const QString content = QString("<p style=\"font-size: small;\">%1</p>").arg(urls);
353 354 355 356
        KGet::showNotification(m_mainWindow, "added", message + content, "kget", i18n("Download added"));
    }

    return transfers;
357 358
}

359

360
bool KGet::delTransfer(TransferHandler * transfer, DeleteMode mode)
361
{
Matthias Fuchs's avatar
Matthias Fuchs committed
362
    return delTransfers(QList<TransferHandler*>() << transfer, mode);
363 364
}

Matthias Fuchs's avatar
Matthias Fuchs committed
365
bool KGet::delTransfers(const QList<TransferHandler*> &handlers, DeleteMode mode)
366
{
367 368 369
    if (!m_store) {
        m_store = TransferHistoryStore::getStore();
    }
370
    QList<Transfer*> transfers;
371
    QList<TransferHistoryItem> historyItems;
372 373 374
    foreach (TransferHandler *handler, handlers) {
        Transfer *transfer = handler->m_transfer;
        transfers << transfer;
375
        historyItems << TransferHistoryItem(*transfer);
376

377 378 379
        // TransferHandler deinitializations
        handler->destroy();
        // Transfer deinitializations (the deinit function is called by the destroy() function)
380 381 382 383
        if (mode == AutoDelete) {
            Transfer::DeleteOptions o = Transfer::DeleteTemporaryFiles;
            if (transfer->status() != Job::Finished && transfer->status() != Job::FinishedKeepAlive)
                o |= Transfer::DeleteFiles;
Matthias Fuchs's avatar
Matthias Fuchs committed
384
            transfer->destroy(o);
385
        } else {
Matthias Fuchs's avatar
Matthias Fuchs committed
386
            transfer->destroy((Transfer::DeleteTemporaryFiles | Transfer::DeleteFiles));
387
        }
388
    }
389 390
    m_store->saveItems(historyItems);

391 392
    m_transferTreeModel->delTransfers(transfers);
    qDeleteAll(transfers);
393
    return true;
394 395
}

396

397
void KGet::moveTransfer(TransferHandler * transfer, const QString& groupName)
398
{
Matthias Fuchs's avatar
Matthias Fuchs committed
399 400
  Q_UNUSED(transfer)
  Q_UNUSED(groupName)
401 402
}

403 404 405
void KGet::redownloadTransfer(TransferHandler * transfer)
{
     QString group = transfer->group()->name();
406 407
     QUrl src = transfer->source();
     QString dest = transfer->dest().toLocalFile();
408
     QString destFile = transfer->dest().fileName();
409

Matthias Fuchs's avatar
Matthias Fuchs committed
410
     KGet::delTransfer(transfer);
411
     KGet::addTransfer(src, dest, destFile, group, true);
412 413
}

414
QList<TransferHandler *> KGet::selectedTransfers()
Dario Massarin's avatar
Dario Massarin committed
415
{
416
//     qCDebug(KGET_DEBUG) << "KGet::selectedTransfers";
417

Dario Massarin's avatar
Dario Massarin committed
418
    QList<TransferHandler *> selectedTransfers;
Dario Massarin's avatar
Dario Massarin committed
419

420
    QModelIndexList selectedIndexes = m_selectionModel->selectedRows();
421
    //sort the indexes as this can speed up operations like deleting etc.
Andrius Štikonas's avatar
Andrius Štikonas committed
422
    std::sort(selectedIndexes.begin(), selectedIndexes.end());
423

Albert Astals Cid's avatar
Albert Astals Cid committed
424
    foreach(const QModelIndex &currentIndex, selectedIndexes)
425
    {
426 427 428
        ModelItem * item = m_transferTreeModel->itemFromIndex(currentIndex);
        if (!item->isGroup())
            selectedTransfers.append(item->asTransfer()->transferHandler());
429 430 431 432 433 434 435
    }

    return selectedTransfers;


// This is the code that was used in the old selectedTransfers function
/*    QList<TransferGroup *>::const_iterator it = m_transferTreeModel->transferGroups().begin();
436
    QList<TransferGroup *>::const_iterator itEnd = m_transferTreeModel->transferGroups().end();
Dario Massarin's avatar
Dario Massarin committed
437 438 439 440 441 442 443 444 445 446 447 448 449 450

    for( ; it!=itEnd ; ++it )
    {
        TransferGroup::iterator it2 = (*it)->begin();
        TransferGroup::iterator it2End = (*it)->end();

        for( ; it2!=it2End ; ++it2 )
        {
            Transfer * transfer = (Transfer*) *it2;

            if( transfer->isSelected() )
                selectedTransfers.append( transfer->handler() );
        }
    }
451
    return selectedTransfers;*/
Dario Massarin's avatar
Dario Massarin committed
452 453
}

454 455 456 457 458 459 460 461 462 463 464 465 466
QList<TransferHandler *> KGet::finishedTransfers()
{
    QList<TransferHandler *> finishedTransfers;

    foreach(TransferHandler *transfer, allTransfers())
    {
        if (transfer->status() == Job::Finished) {
            finishedTransfers << transfer;
        }
    }
    return finishedTransfers;
}

467
QList<TransferGroupHandler *> KGet::selectedTransferGroups()
Manolo Valdes's avatar
Manolo Valdes committed
468 469 470 471 472
{
    QList<TransferGroupHandler *> selectedTransferGroups;

    QModelIndexList selectedIndexes = m_selectionModel->selectedRows();

Albert Astals Cid's avatar
Albert Astals Cid committed
473
    foreach(const QModelIndex &currentIndex, selectedIndexes)
Manolo Valdes's avatar
Manolo Valdes committed
474
    {
475
        ModelItem * item = m_transferTreeModel->itemFromIndex(currentIndex);
476 477 478 479
        if (item->isGroup()) {
            TransferGroupHandler *group = item->asGroup()->groupHandler();
            selectedTransferGroups.append(group);
        }
Manolo Valdes's avatar
Manolo Valdes committed
480 481 482 483 484
    }

    return selectedTransferGroups;
}

485 486 487 488 489
TransferTreeModel * KGet::model()
{
    return m_transferTreeModel;
}

490
TransferTreeSelectionModel * KGet::selectionModel()
491
{
492 493
    return m_selectionModel;
}
494

Urs Wolfer's avatar
Urs Wolfer committed
495
void KGet::load( QString filename ) // krazy:exclude=passbyvalue
Dario Massarin's avatar
Dario Massarin committed
496
{
497
    qCDebug(KGET_DEBUG) << "(" << filename << ")";
498

499 500 501 502 503 504 505 506
    if(filename.isEmpty()) {
        filename = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
        // make sure that the DataLocation directory exists (earlier this used to be handled by KStandardDirs)
        if (!QFileInfo::exists(filename)) {
            QDir().mkpath(filename);
        }
        filename += QStringLiteral("/transfers.kgt");
    }
Dario Massarin's avatar
Dario Massarin committed
507

508
    QTemporaryFile tmpFile;
Dario Massarin's avatar
Dario Massarin committed
509

510 511 512 513 514 515 516
    QUrl url = QUrl(filename);
    if (url.scheme().isEmpty())
        url.setScheme("file");
    KIO::StoredTransferJob * job = KIO::storedGet(url);
    job->exec();
    if (job->data().isEmpty() || !tmpFile.open()) {
        qCDebug(KGET_DEBUG) << "Transferlist empty or cannot open temporary file";
517 518
        if (m_transferTreeModel->transferGroups().isEmpty()) //Create the default group
            addGroup(i18n("My Downloads"));
Dario Massarin's avatar
Dario Massarin committed
519
        return;
520
    }
521 522
    tmpFile.write(job->data());
    tmpFile.close();
Dario Massarin's avatar
Dario Massarin committed
523 524 525

    QDomDocument doc;

526
    qCDebug(KGET_DEBUG) << "file:" << tmpFile.fileName();
Dario Massarin's avatar
Dario Massarin committed
527

528
    if(doc.setContent(&tmpFile))
Dario Massarin's avatar
Dario Massarin committed
529 530 531 532 533 534 535 536
    {
        QDomElement root = doc.documentElement();

        QDomNodeList nodeList = root.elementsByTagName("TransferGroup");
        int nItems = nodeList.length();

        for( int i = 0 ; i < nItems ; i++ )
        {
537
            TransferGroup * foundGroup = m_transferTreeModel->findGroup( nodeList.item(i).toElement().attribute("Name") );
Dario Massarin's avatar
Dario Massarin committed
538

539
            qCDebug(KGET_DEBUG) << "KGet::load  -> group = " << nodeList.item(i).toElement().attribute("Name");
540

Dario Massarin's avatar
Dario Massarin committed
541 542
            if( !foundGroup )
            {
543
                qCDebug(KGET_DEBUG) << "KGet::load  -> group not found";
544 545 546

                TransferGroup * newGroup = new TransferGroup(m_transferTreeModel, m_scheduler);

547
                m_transferTreeModel->addGroup(newGroup);
548

549
                newGroup->load(nodeList.item(i).toElement());
Dario Massarin's avatar
Dario Massarin committed
550 551 552
            }
            else
            {
553
                qCDebug(KGET_DEBUG) << "KGet::load  -> group found";
554

Dario Massarin's avatar
Dario Massarin committed
555 556 557 558 559 560 561 562
                //A group with this name already exists.
                //Integrate the group's transfers with the ones read from file
                foundGroup->load(nodeList.item(i).toElement());
            }
        }
    }
    else
    {
563
        qCWarning(KGET_DEBUG) << "Error reading the transfers file";
Dario Massarin's avatar
Dario Massarin committed
564
    }
565 566 567
    
    if (m_transferTreeModel->transferGroups().isEmpty()) //Create the default group
        addGroup(i18n("My Downloads"));
568

569
    new GenericObserver(m_mainWindow);
Dario Massarin's avatar
Dario Massarin committed
570 571
}

572
void KGet::save( QString filename, bool plain ) // krazy:exclude=passbyvalue
Dario Massarin's avatar
Dario Massarin committed
573 574 575
{
    if ( !filename.isEmpty()
        && QFile::exists( filename )
576
        && (KMessageBox::questionYesNoCancel(nullptr,
577
                i18n("The file %1 already exists.\nOverwrite?", filename),
Urs Wolfer's avatar
compile  
Urs Wolfer committed
578
                i18n("Overwrite existing file?"), KStandardGuiItem::yes(),
579
                KStandardGuiItem::no(), KStandardGuiItem::cancel(), "QuestionFilenameExists" )
580
                != KMessageBox::Yes) )
Dario Massarin's avatar
Dario Massarin committed
581 582
        return;

583 584 585 586 587 588 589 590
    if(filename.isEmpty()) {
        filename = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
        // make sure that the DataLocation directory exists (earlier this used to be handled by KStandardDirs)
        if (!QFileInfo::exists(filename)) {
            QDir().mkpath(filename);
        }
        filename += QStringLiteral("/transfers.kgt");
    }
591 592
    
    qCDebug(KGET_DEBUG) << "Save transferlist to " << filename;
Dario Massarin's avatar
Dario Massarin committed
593

594
    QSaveFile file(filename);
Dario Massarin's avatar
Dario Massarin committed
595
    if ( !file.open( QIODevice::WriteOnly ) )
Dario Massarin's avatar
Dario Massarin committed
596
    {
597
        //qCWarning(KGET_DEBUG)<<"Unable to open output file when saving";
598 599
        KGet::showNotification(m_mainWindow, "error",
                               i18n("Unable to save to: %1", filename));
Dario Massarin's avatar
Dario Massarin committed
600 601 602
        return;
    }

603 604 605
    if (plain) {
        QTextStream out(&file);
        foreach(TransferHandler *handler, allTransfers()) {
Laurent Montel's avatar
Laurent Montel committed
606
            out << handler->source().toString() << '\n';
607 608 609 610 611 612 613
        }
    }
    else {
        QDomDocument doc(QString("KGetTransfers"));
        QDomElement root = doc.createElement("Transfers");
        doc.appendChild(root);

614
        foreach (TransferGroup * group, m_transferTreeModel->transferGroups())
615 616 617
        {
            QDomElement e = doc.createElement("TransferGroup");
            root.appendChild(e);
618
            group->save(e);
Lukas Appelhans's avatar
Lukas Appelhans committed
619
            //KGet::delGroup((*it)->name());
620 621 622
        }

        QTextStream stream( &file );
623
        doc.save( stream, 2 );
624
    }
625
    file.commit();
Dario Massarin's avatar
Dario Massarin committed
626 627
}

628 629 630 631 632
QList<TransferFactory*> KGet::factories()
{
    return m_transferFactories;
}

633 634 635 636 637
KPluginInfo::List KGet::pluginInfos()
{
    return m_pluginInfoList;
}

638
TransferFactory * KGet::factory(TransferHandler * transfer)
639 640 641 642
{
    return transfer->m_transfer->factory();
}

643
KActionCollection * KGet::actionCollection()
Dario Massarin's avatar
Dario Massarin committed
644
{
645
    return m_mainWindow->actionCollection();
Dario Massarin's avatar
Dario Massarin committed
646 647
}

648
void KGet::setSchedulerRunning(bool running)
649 650
{
    if(running)
651 652
    {
        m_scheduler->stop(); //stopall first, to have a clean startingpoint
Lukas Appelhans's avatar
Lukas Appelhans committed
653
	    m_scheduler->start();
654
    }
655
    else
Lukas Appelhans's avatar
Lukas Appelhans committed
656
	    m_scheduler->stop();
657 658
}

Urs Wolfer's avatar
Urs Wolfer committed
659 660
bool KGet::schedulerRunning()
{
661
    return (m_scheduler->hasRunningJobs());
Urs Wolfer's avatar
Urs Wolfer committed
662 663
}

664 665 666 667 668
void KGet::setSuspendScheduler(bool isSuspended)
{
    m_scheduler->setIsSuspended(isSuspended);
}

Lukas Appelhans's avatar
Lukas Appelhans committed
669 670 671 672 673 674 675 676 677 678 679
QList<TransferHandler*> KGet::allTransfers()
{
    QList<TransferHandler*> transfers;

    foreach (TransferGroup *group, KGet::m_transferTreeModel->transferGroups())
    {
        transfers << group->handler()->transfers();
    }
    return transfers;
}

680 681 682 683 684 685
QList<TransferGroupHandler*> KGet::allTransferGroups()
{
    QList<TransferGroupHandler*> transfergroups;

    foreach (TransferGroup *group, KGet::m_transferTreeModel->transferGroups())
    {
Yuri Chornoivan's avatar
Yuri Chornoivan committed
686
        qDebug() << group->name();
687 688 689 690 691
        transfergroups << group->handler();
    }
    return transfergroups;
}

Lukas Appelhans's avatar
Lukas Appelhans committed
692
TransferHandler * KGet::findTransfer(const QUrl &src)
693
{
694 695 696 697 698
    Transfer *transfer = KGet::m_transferTreeModel->findTransfer(src);
    if (transfer)
    {
        return transfer->handler();
    }
699
    return nullptr;
700 701
}

702 703 704 705 706 707 708
TransferGroupHandler * KGet::findGroup(const QString &name)
{
    TransferGroup *group = KGet::m_transferTreeModel->findGroup(name);
    if (group)
    {
        return group->handler();
    }
709
    return nullptr;
710 711
}

Lukas Appelhans's avatar
Lukas Appelhans committed
712
void KGet::checkSystemTray()
Lukas Appelhans's avatar
Lukas Appelhans committed
713
{
714
    qCDebug(KGET_DEBUG);
Lukas Appelhans's avatar
Lukas Appelhans committed
715 716 717 718 719
    bool running = false;

    foreach (TransferHandler *handler, KGet::allTransfers())
    {
        if (handler->status() == Job::Running)
720
        {
Lukas Appelhans's avatar
Lukas Appelhans committed
721
            running = true;
722 723
            break;
        }
Lukas Appelhans's avatar
Lukas Appelhans committed
724 725 726
    }

    m_mainWindow->setSystemTrayDownloading(running);
Lukas Appelhans's avatar
Lukas Appelhans committed
727 728
}

729 730
void KGet::settingsChanged()
{
731
    qCDebug(KGET_DEBUG);
732

733
    foreach (TransferFactory *factory, m_transferFactories)
734
    {
735
        factory->settingsChanged();
736
    }
737 738
    
    m_jobManager->settingsChanged();
739
    m_scheduler->settingsChanged();
740 741
}

Lukas Appelhans's avatar
Lukas Appelhans committed
742
QList<TransferGroupHandler*> KGet::groupsFromExceptions(const QUrl &filename)
743
{
744 745
    QList<TransferGroupHandler*> handlers;
    foreach (TransferGroupHandler * handler, allTransferGroups()) {
746 747 748 749 750
        const QStringList patterns = handler->regExp().pattern().split(',');//FIXME 4.5 add a tooltip: "Enter a list of foo separated by ," and then do split(i18nc("used as separator in a list, translate to the same thing you translated \"Enter a list of foo separated by ,\"", ","))
        if (matchesExceptions(filename, patterns)) {
            handlers.append(handler);
        }
    }
751

752 753 754
    return handlers;
}

Lukas Appelhans's avatar
Lukas Appelhans committed
755
bool KGet::matchesExceptions(const QUrl &sourceUrl, const QStringList &patterns)
756 757 758 759 760 761 762
{
    foreach (const QString &pattern, patterns) {
        const QString trimmedPattern = pattern.trimmed();
        if (trimmedPattern.isEmpty()) {
            continue;
        }
        QRegExp regExp = QRegExp(trimmedPattern);
763

764 765 766 767 768 769
        //try with Regular Expression first
        regExp.setPatternSyntax(QRegExp::RegExp2);
        regExp.setCaseSensitivity(Qt::CaseInsensitive);
        if (regExp.exactMatch(sourceUrl.url())) {
            return true;
        }
770

771 772 773 774 775 776 777 778 779 780
        //now try with wildcards
        if (!regExp.pattern().isEmpty() && !regExp.pattern().contains('*')) {
            regExp.setPattern('*' + regExp.pattern());
        }

        regExp.setPatternSyntax(QRegExp::Wildcard);
        regExp.setCaseSensitivity(Qt::CaseInsensitive);

        if (regExp.exactMatch(sourceUrl.url())) {
            return true;
781
        }
782
    }
783

784
    return false;
785 786
}

787 788 789 790 791 792 793 794 795 796
void KGet::setGlobalDownloadLimit(int limit)
{
    m_scheduler->setDownloadLimit(limit);
}

void KGet::setGlobalUploadLimit(int limit)
{
    m_scheduler->setUploadLimit(limit);
}

797 798
void KGet::calculateGlobalSpeedLimits()
{
Lukas Appelhans's avatar
Lukas Appelhans committed
799
    //if (m_scheduler->downloadLimit())//TODO: Remove this and the both other hacks in the 2 upper functions with a better replacement
800
        m_scheduler->calculateDownloadLimit();
Lukas Appelhans's avatar
Lukas Appelhans committed
801
    //if (m_scheduler->uploadLimit())
802
        m_scheduler->calculateUploadLimit();
803 804 805 806 807 808 809 810 811 812 813 814
}

void KGet::calculateGlobalDownloadLimit()
{
    m_scheduler->calculateDownloadLimit();
}

void KGet::calculateGlobalUploadLimit()
{
    m_scheduler->calculateUploadLimit();
}

815
// ------ STATIC MEMBERS INITIALIZATION ------
816
TransferTreeModel * KGet::m_transferTreeModel;
817
TransferTreeSelectionModel * KGet::m_selectionModel;
818
QList<TransferFactory *> KGet::m_transferFactories;
819
KPluginInfo::List KGet::m_pluginInfoList;
820 821 822 823
TransferGroupScheduler * KGet::m_scheduler = nullptr;
MainWindow * KGe