File indexing completed on 2024-05-05 16:39:03

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003,2009 Carsten Pfeiffer <pfeiffer@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation, version 2.
0007 
0008    This program is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011     General Public License for more details.
0012 
0013    You should have received a copy of the GNU General Public License
0014    along with this program; see the file COPYING.  If not, write to
0015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0016    Boston, MA 02110-1301, USA.
0017 */
0018 
0019 #include "kuickfile.h"
0020 #include "kuickshow_debug.h"
0021 
0022 #include <KIO/FileCopyJob>
0023 #include <KIO/StatJob>
0024 #include <KLocalizedString>
0025 
0026 #include <QFile>
0027 #include <QProgressDialog>
0028 #include <QScopedPointer>
0029 #include <QTemporaryFile>
0030 
0031 #include "filecache.h"
0032 
0033 
0034 KuickFile::KuickFile(const QUrl& url)
0035     : QObject(),
0036       m_url( url ),
0037       m_job( 0L ),
0038       m_progress( 0L ),
0039       m_currentProgress( 0 )
0040 {
0041     if ( m_url.isLocalFile())
0042         m_localFile = m_url.path();
0043     else {
0044         QUrl mostLocal;
0045         KIO::StatJob* job = KIO::mostLocalUrl(m_url);
0046         connect(job, &KIO::StatJob::result, [job, &mostLocal]() {
0047             if(!job->error()) mostLocal = job->mostLocalUrl();
0048         });
0049         job->exec();
0050 
0051         if ( mostLocal.isValid() && mostLocal.isLocalFile() )
0052             m_localFile = mostLocal.path();
0053     }
0054 }
0055 
0056 KuickFile::~KuickFile()
0057 {
0058     delete m_job;
0059 
0060     if ( hasDownloaded() )
0061         QFile::remove( m_localFile );
0062 }
0063 
0064 QString KuickFile::localFile() const
0065 {
0066     // Note: never call isAvailable() from here, directly or indirectly
0067 
0068     if ( isDownloading() )
0069         return QString();
0070 
0071     return m_localFile;
0072 }
0073 
0074 bool KuickFile::hasDownloaded() const
0075 {
0076     return !m_url.isLocalFile() && isAvailable() && m_job != 0L;
0077 }
0078 
0079 // ### need an API for refreshing the file?
0080 bool KuickFile::download()
0081 {
0082     if ( m_url.isLocalFile() || isAvailable() )
0083         return true;
0084 
0085     if ( isDownloading() )
0086         return true;
0087 
0088     // reinitialize
0089     m_localFile.clear();
0090     m_currentProgress = 0;
0091 
0092 
0093     QString ext;
0094     QString fileName = m_url.fileName();
0095     int extIndex = fileName.lastIndexOf('.');
0096     if ( extIndex > 0 )
0097         ext = fileName.mid( extIndex );
0098 
0099     QScopedPointer<QTemporaryFile> tempFilePtr(FileCache::self()->createTempFile(ext));
0100     if(tempFilePtr.isNull() || !tempFilePtr->open()) return false;
0101 
0102     QUrl destURL = QUrl::fromLocalFile(tempFilePtr->fileName());
0103 
0104     // we don't need the actual temp file, just its unique name
0105     tempFilePtr.reset();
0106 
0107     m_job = KIO::file_copy( m_url, destURL, -1, KIO::HideProgressInfo | KIO::Overwrite ); // handling progress ourselves
0108 //    m_job->setAutoErrorHandlingEnabled( true );
0109     connect( m_job, SIGNAL( result( KJob * )), SLOT( slotResult( KJob * ) ));
0110     connect( m_job, SIGNAL( percent( KJob *, unsigned long )), SLOT( slotProgress( KJob *, unsigned long ) ));
0111 
0112     // TODO: generify background/foreground downloading?
0113 
0114     return m_job != 0L;
0115 }
0116 
0117 KuickFile::DownloadStatus KuickFile::waitForDownload( QWidget *parent )
0118 {
0119     if ( isAvailable() )
0120         return OK;
0121 
0122     if ( !isDownloading() ) {
0123         if ( !download() )
0124             return ERROR;
0125     }
0126 
0127     QProgressDialog *dialog = new QProgressDialog( parent );
0128     dialog->setWindowTitle( i18n("Downloading %1...", m_url.fileName() ) );
0129     dialog->setLabelText( i18n("Please wait while downloading\n%1", m_url.toDisplayString() ));
0130     dialog->setAutoClose( true );
0131 
0132     dialog->setMaximum( 100 ); // percent
0133     dialog->setValue( m_currentProgress );
0134 
0135     m_progress = dialog;
0136     dialog->exec();
0137     m_progress = nullptr;
0138 
0139     bool canceled = dialog->wasCanceled();
0140     delete dialog;
0141 
0142     if ( canceled && m_job ) {
0143         m_job->kill();
0144         m_job = 0L;
0145         m_currentProgress = 0;
0146     }
0147     // ### when aborted, remove KuickImage from FileCache?
0148 
0149     if ( canceled )
0150         return CANCELED;
0151 
0152     if ( !isAvailable() )
0153         return ERROR;
0154 
0155     // ### use custom progress dialog with OK, SKIP, CANCEL?
0156      return OK;
0157 }
0158 
0159 void KuickFile::slotResult( KJob *job )
0160 {
0161     if (job != m_job) { // huh?
0162         return;
0163     }
0164 
0165     m_job = 0L;
0166 
0167     if ( job->error() != 0 ) {
0168         m_currentProgress = 0;
0169 
0170         if ( job->error() != KIO::ERR_USER_CANCELED )
0171             qWarning("ERROR: KuickFile::slotResult: %s", qUtf8Printable(job->errorString()));
0172 
0173         QString canceledFile = static_cast<KIO::FileCopyJob*>(job)->destUrl().path();
0174         QFile::remove( canceledFile );
0175         m_progress->hide();
0176     }
0177     else {
0178         m_localFile = static_cast<KIO::FileCopyJob*>(job)->destUrl().path();
0179         emit downloaded( this ); // before closing the progress dialog
0180 
0181         if ( m_progress ) {
0182             m_progress->setValue( 100 );
0183         }
0184     }
0185 }
0186 
0187 void KuickFile::slotProgress( KJob *job, unsigned long percent )
0188 {
0189     if (job != m_job) { // huh?
0190         return;
0191     }
0192 
0193     m_currentProgress = percent;
0194 
0195     if ( !m_progress )
0196         return;
0197 
0198     // only set 100% in slotResult. Otherwise, the progress dialog would be closed
0199     // before slotResult() is called.
0200     if ( percent >= 100 )
0201         percent = 99;
0202 
0203     m_progress->setValue( (int) percent );
0204 }
0205 
0206 bool operator==( const KuickFile& first, const KuickFile& second ) {
0207     return first.url() == second.url();
0208 }