File indexing completed on 2024-05-12 05:09:45

0001 /***************************************************************************
0002     Copyright (C) 2008-2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "xmlfetcher.h"
0026 #include "../translators/xslthandler.h"
0027 #include "../translators/tellicoimporter.h"
0028 #include "../utils/guiproxy.h"
0029 #include "../utils/xmlhandler.h"
0030 #include "../utils/string_utils.h"
0031 #include "../utils/datafileregistry.h"
0032 #include "../tellico_debug.h"
0033 
0034 #include <KIO/Job>
0035 #include <KIO/JobUiDelegate>
0036 
0037 #include <QFile>
0038 #include <QTextStream>
0039 #include <QTextCodec>
0040 #include <KJobWidgets/KJobWidgets>
0041 
0042 using Tellico::Fetch::XMLFetcher;
0043 
0044 XMLFetcher::XMLFetcher(QObject* parent_) : Fetcher(parent_)
0045     , m_xsltHandler(nullptr)
0046     , m_started(false)
0047     , m_limit(0) {
0048 }
0049 
0050 XMLFetcher::~XMLFetcher() {
0051   delete m_xsltHandler;
0052   m_xsltHandler = nullptr;
0053 }
0054 
0055 void XMLFetcher::search() {
0056   m_started = true;
0057   resetSearch();
0058   doSearch();
0059 }
0060 
0061 void XMLFetcher::continueSearch() {
0062   m_started = true;
0063   doSearch();
0064 }
0065 
0066 void XMLFetcher::doSearch() {
0067   const QUrl u = searchUrl();
0068   if(u.isEmpty()) {
0069     myDebug() << source() << "- empty search url";
0070     stop();
0071     return;
0072   }
0073 //  myDebug() << "url: " << u.url();
0074 
0075   m_job = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo);
0076   KJobWidgets::setWindow(m_job, GUI::Proxy::widget());
0077   connect(m_job.data(), &KJob::result, this, &XMLFetcher::slotComplete);
0078 }
0079 
0080 void XMLFetcher::stop() {
0081   if(!m_started) {
0082     return;
0083   }
0084   if(m_job) {
0085     m_job->kill();
0086     m_job = nullptr;
0087   }
0088   m_started = false;
0089   emit signalDone(this);
0090 }
0091 
0092 void XMLFetcher::slotComplete(KJob* ) {
0093   Q_ASSERT(m_job);
0094   if(m_job->error()) {
0095     myDebug() << source() << ":" << m_job->errorString();
0096     m_job->uiDelegate()->showErrorMessage();
0097     stop();
0098     return;
0099   }
0100 
0101   if(!m_xsltHandler) {
0102     initXSLTHandler();
0103     if(!m_xsltHandler) { // probably an error somewhere in the stylesheet loading
0104       stop();
0105       return;
0106     }
0107   }
0108 
0109   QByteArray data = m_job->data();
0110   if(data.isEmpty()) {
0111     myDebug() << "no data";
0112     stop();
0113     return;
0114   }
0115   // see bug 319662. If fetcher is cancelled, job is killed
0116   // if the pointer is retained, it gets double-deleted
0117   m_job = nullptr;
0118 
0119 #if 0
0120   myWarning() << "Remove debug from xmlfetcher.cpp";
0121   QFile f(QStringLiteral("/tmp/test.xml"));
0122   if(f.open(QIODevice::WriteOnly)) {
0123     QTextStream t(&f);
0124     t.setCodec("utf-8");
0125     t << data;
0126   }
0127   f.close();
0128 #endif
0129 
0130   parseData(data);
0131 
0132   const QString str = m_xsltHandler->applyStylesheet(XMLHandler::readXMLData(data));
0133 #if 0
0134   myWarning() << "Remove debug from xmlfetcher.cpp";
0135   QFile f2(QStringLiteral("/tmp/test-tellico.xml"));
0136   if(f2.open(QIODevice::WriteOnly)) {
0137     QTextStream t(&f2);
0138     t.setCodec("utf-8");
0139     t << str;
0140   }
0141   f2.close();
0142 #endif
0143   Import::TellicoImporter imp(str);
0144   // be quiet when loading images
0145   imp.setOptions(imp.options() ^ Import::ImportShowImageErrors);
0146   Data::CollPtr coll = imp.collection();
0147   if(!coll) {
0148     myDebug() << "no collection pointer";
0149     stop();
0150     return;
0151   }
0152 
0153   if(m_limit < 1) {
0154     myDebug() << "Limit < 1, changing to 1";
0155     m_limit = 1;
0156   }
0157 
0158   int count = 0;
0159   foreach(Data::EntryPtr entry, coll->entries()) {
0160     if(count >= m_limit) {
0161       break;
0162     }
0163     if(!m_started) {
0164       // might get aborted
0165       break;
0166     }
0167 
0168     FetchResult* r = new FetchResult(this, entry);
0169     m_entries.insert(r->uid, entry);
0170     emit signalResultFound(r);
0171     ++count;
0172   }
0173 
0174   checkMoreResults(m_entries.count());
0175   stop(); // required
0176 }
0177 
0178 Tellico::Data::EntryPtr XMLFetcher::fetchEntryHook(uint uid_) {
0179   Data::EntryPtr entry = m_entries[uid_];
0180   if(!entry) {
0181     myWarning() << "no entry in dict";
0182     return Data::EntryPtr();
0183   }
0184 
0185   // the fetcher might end up creating a new entry
0186   return fetchEntryHookData(entry);
0187 }
0188 
0189 void XMLFetcher::initXSLTHandler() {
0190   Q_ASSERT(!m_xsltFilename.isEmpty());
0191   QString xsltfile = DataFileRegistry::self()->locate(m_xsltFilename);
0192   if(xsltfile.isEmpty()) {
0193     myWarning() << "can not locate" << m_xsltFilename;
0194     return;
0195   }
0196 
0197   QUrl u = QUrl::fromLocalFile(xsltfile);
0198 
0199   delete m_xsltHandler;
0200   m_xsltHandler = new XSLTHandler(u);
0201   if(!m_xsltHandler->isValid()) {
0202     myWarning() << "error in" << m_xsltFilename;
0203     delete m_xsltHandler;
0204     m_xsltHandler = nullptr;
0205     return;
0206   }
0207 }
0208 
0209 void XMLFetcher::setXSLTFilename(const QString& filename_) {
0210   if(!filename_.isEmpty() && filename_ != m_xsltFilename) {
0211     m_xsltFilename = filename_;
0212     delete m_xsltHandler;
0213     m_xsltHandler = nullptr;
0214   }
0215 }
0216 
0217 void XMLFetcher::setLimit(int limit_) {
0218   Q_ASSERT(limit_ > 0);
0219   m_limit = limit_;
0220 }
0221 
0222 Tellico::XSLTHandler* XMLFetcher::xsltHandler() {
0223   Q_ASSERT(m_xsltHandler);
0224   return m_xsltHandler;
0225 }