File indexing completed on 2023-12-03 08:26:47

0001 /***************************************************************************
0002  *   Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>                     *
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU General Public License as published by  *
0006  *   the Free Software Foundation; either version 2 of the License, or     *
0007  *   (at your option) any later version.                                   *
0008  *                                                                         *
0009  *   This program is distributed in the hope that it will be useful,       *
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0012  *   GNU General Public License for more details.                          *
0013  *                                                                         *
0014  *   You should have received a copy of the GNU General Public License     *
0015  *   along with this program; if not, write to the                         *
0016  *   Free Software Foundation, Inc.,                                       *
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
0018  ***************************************************************************/
0019 
0020 #include "metalinkcreator.h"
0021 #include "dragdlg.h"
0022 #include "filedlg.h"
0023 #include "generalwidget.h"
0024 #include "localemodels.h"
0025 
0026 #include <QDragEnterEvent>
0027 #include <QFileDialog>
0028 #include <QMimeData>
0029 #include <QPushButton>
0030 #include <QSortFilterProxyModel>
0031 #include <QStandardItemModel>
0032 #include <QTimer>
0033 
0034 #include <KLocalizedString>
0035 #include <KMessageBox>
0036 #include <kio_version.h>
0037 
0038 // TODO for 4.4 look at the changes of the newest Draft --> what elements have to be added/removed
0039 
0040 FileWidget::FileWidget(QWidget *parent)
0041     : QWidget(parent)
0042 {
0043     setAcceptDrops(true);
0044 }
0045 
0046 void FileWidget::dragEnterEvent(QDragEnterEvent *event)
0047 {
0048     if (event->mimeData()->hasUrls()) {
0049         event->acceptProposedAction();
0050     }
0051 }
0052 
0053 void FileWidget::dropEvent(QDropEvent *event)
0054 {
0055     QList<QUrl> urls = event->mimeData()->urls();
0056 
0057     event->acceptProposedAction();
0058 
0059     if (!urls.isEmpty()) {
0060         Q_EMIT urlsDropped(urls);
0061     }
0062 }
0063 
0064 MetalinkCreator::MetalinkCreator(QWidget *parent)
0065     : KAssistantDialog(parent)
0066     , m_needUrlCount(0)
0067     , m_countrySort(nullptr)
0068     , m_languageModel(nullptr)
0069     , m_languageSort(nullptr)
0070     , m_introduction(nullptr)
0071     , m_generalPage(nullptr)
0072     , m_filesModel(nullptr)
0073 {
0074     create();
0075 
0076     connect(finishButton(), &QPushButton::clicked, this, &MetalinkCreator::slotSave);
0077     connect(this, &KPageDialog::currentPageChanged, this, &MetalinkCreator::slotUpdateAssistantButtons);
0078 
0079     qRegisterMetaType<KGetMetalink::File>("KGetMetalink::File");
0080     connect(&m_thread, SIGNAL(fileResult(KGetMetalink::File)), this, SLOT(slotAddFile(KGetMetalink::File)));
0081     connect(&m_thread, &QThread::finished, this, &MetalinkCreator::slotThreadFinished);
0082 
0083     setWindowTitle(i18n("Create a Metalink"));
0084 }
0085 
0086 MetalinkCreator::~MetalinkCreator()
0087 {
0088 }
0089 
0090 void MetalinkCreator::slotUpdateAssistantButtons(KPageWidgetItem *to, KPageWidgetItem *from)
0091 {
0092     // once we leave the introduction page the data is being loaded
0093     if (m_introduction && m_generalPage && (from == m_introduction) && (to == m_generalPage)) {
0094         load();
0095     }
0096 
0097     // it is impossible to return to the introduction page
0098     backButton()->setEnabled(to != m_generalPage);
0099 
0100     if (!m_filesModel->rowCount()) {
0101         uiFiles.infoWidget->setText(i18n("Add at least one file."));
0102     } else if (m_needUrlCount) {
0103         uiFiles.infoWidget->setText(i18n("You need to set mirrors for the entries with an icon."));
0104     }
0105     uiFiles.infoWidget->setVisible(!m_filesModel->rowCount() || m_needUrlCount);
0106 
0107     // only enable finish when the metalink is valid (i.e. no required data missing)
0108     // and the thread is not running
0109     finishButton()->setEnabled(metalink.isValid() && !m_thread.isRunning());
0110 }
0111 
0112 void MetalinkCreator::create()
0113 {
0114     createIntroduction();
0115     m_general = new GeneralWidget(this);
0116     m_generalPage = addPage(m_general, i18n("General optional information for the metalink."));
0117     QTimer::singleShot(0, this, &MetalinkCreator::slotDelayedCreation);
0118 }
0119 
0120 void MetalinkCreator::slotDelayedCreation()
0121 {
0122     auto *countryModel = new CountryModel(this);
0123     countryModel->setupModelData();
0124     m_countrySort = new QSortFilterProxyModel(this);
0125     m_countrySort->setSourceModel(countryModel);
0126     m_countrySort->setSortLocaleAware(true);
0127     m_countrySort->sort(0);
0128 
0129     m_languageModel = new LanguageModel(this);
0130     m_languageModel->setupModelData();
0131     m_languageSort = new QSortFilterProxyModel(this);
0132     m_languageSort->setSourceModel(m_languageModel);
0133     m_languageSort->setSortLocaleAware(true);
0134     m_languageSort->sort(0);
0135 
0136     createFiles();
0137     slotUpdateIntroductionNextButton();
0138 }
0139 
0140 void MetalinkCreator::load()
0141 {
0142     QUrl url = uiIntroduction.load->url();
0143     if (uiIntroduction.loadButton->isChecked() && url.isValid()) {
0144         if (!KGetMetalink::HandleMetalink::load(url, &metalink)) {
0145             KMessageBox::error(this, i18n("Unable to load: %1", url.toString()), i18n("Error"));
0146         }
0147     }
0148 
0149     m_general->load(metalink);
0150     loadFiles();
0151 }
0152 
0153 void MetalinkCreator::slotSave()
0154 {
0155     m_general->save(&metalink);
0156 
0157     QUrl url = uiIntroduction.save->url();
0158     if (url.isValid()) {
0159         if (!KGetMetalink::HandleMetalink::save(url, &metalink)) {
0160             KMessageBox::error(this, i18n("Unable to save to: %1", url.toString()), i18n("Error"));
0161         }
0162     }
0163 }
0164 
0165 void MetalinkCreator::createIntroduction()
0166 {
0167     auto *widget = new QWidget(this);
0168     uiIntroduction.setupUi(widget);
0169 
0170 #if KIO_VERSION >= QT_VERSION_CHECK(5, 108, 0)
0171     uiIntroduction.save->setNameFilters(
0172         {i18n("Metalink Version 4.0 file") + QLatin1String(" (*.meta4)"), i18n("Metalink Version 3.0 file") + QLatin1String(" (*.metalink)")});
0173     uiIntroduction.load->setNameFilter(i18n("Metalink file (*.metalink *.meta4)") + QLatin1String(" (*.metalink *.meta4)"));
0174 #else
0175     uiIntroduction.save->setFilter("*.meta4|" + i18n("Metalink Version 4.0 file (*.meta4)") + "\n*.metalink|" + i18n("Metalink Version 3.0 file (*.metalink)"));
0176     uiIntroduction.load->setFilter("*.metalink *.meta4|" + i18n("Metalink file (*.metalink *.meta4)"));
0177 #endif
0178     uiIntroduction.save->setAcceptMode(QFileDialog::AcceptSave);
0179 
0180     connect(uiIntroduction.save, &KUrlRequester::textChanged, this, &MetalinkCreator::slotUpdateIntroductionNextButton);
0181     connect(uiIntroduction.load, &KUrlRequester::textChanged, this, &MetalinkCreator::slotUpdateIntroductionNextButton);
0182     connect(uiIntroduction.loadButton, &QAbstractButton::toggled, this, &MetalinkCreator::slotUpdateIntroductionNextButton);
0183 
0184     m_introduction = addPage(widget, i18n("Define the saving location."));
0185 
0186     setValid(m_introduction, false);
0187 }
0188 
0189 void MetalinkCreator::slotUpdateIntroductionNextButton()
0190 {
0191     bool enableNext = false;
0192 
0193     // check if a save location and if selected if also a load location has been specified and if the m_countrySort has been created
0194     enableNext = uiIntroduction.save->url().isValid() && m_countrySort;
0195     if (enableNext && uiIntroduction.loadButton->isChecked()) {
0196         enableNext = uiIntroduction.load->url().isValid();
0197     }
0198 
0199     setValid(m_introduction, enableNext);
0200 }
0201 
0202 void MetalinkCreator::createFiles()
0203 {
0204     m_handler = new DirectoryHandler(this);
0205     connect(m_handler, &DirectoryHandler::finished, this, &MetalinkCreator::slotOpenDragDlg);
0206 
0207     auto *widget = new FileWidget(this);
0208     uiFiles.setupUi(widget);
0209 
0210     m_filesModel = new QStandardItemModel(0, 1, this);
0211     uiFiles.files->setModel(m_filesModel);
0212 
0213     uiFiles.infoWidget->setCloseButtonVisible(false);
0214     uiFiles.infoWidget->setMessageType(KMessageWidget::Information);
0215     uiFiles.add_local_file->setIcon(QIcon::fromTheme("list-add"));
0216     KGuiItem::assign(uiFiles.add_file, KStandardGuiItem::add());
0217     KGuiItem::assign(uiFiles.properties_file, KStandardGuiItem::properties());
0218     uiFiles.properties_file->setEnabled(false);
0219     KGuiItem::assign(uiFiles.remove_file, KStandardGuiItem::remove());
0220     uiFiles.remove_file->setEnabled(false);
0221     uiFiles.dragDrop->hide();
0222 
0223     connect(uiFiles.add_local_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotAddLocalFilesClicked);
0224     connect(uiFiles.add_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotAddClicked);
0225     connect(uiFiles.remove_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotRemoveFile);
0226     connect(uiFiles.properties_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotFileProperties);
0227     connect(uiFiles.files->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MetalinkCreator::slotUpdateFilesButtons);
0228     connect(widget, &FileWidget::urlsDropped, m_handler, &DirectoryHandler::slotFiles);
0229 
0230     addPage(widget, i18nc("file as in file on hard drive", "Files"));
0231 }
0232 
0233 void MetalinkCreator::loadFiles()
0234 {
0235     foreach (const KGetMetalink::File &file, metalink.files.files) {
0236         auto *item = new QStandardItem(file.name);
0237         if (!file.resources.isValid()) {
0238             ++m_needUrlCount;
0239             item->setIcon(QIcon::fromTheme("edit-delete"));
0240         }
0241         m_filesModel->insertRow(m_filesModel->rowCount(), item);
0242     }
0243 }
0244 
0245 void MetalinkCreator::slotUpdateFilesButtons()
0246 {
0247     const QModelIndexList indexes = uiFiles.files->selectionModel()->selectedRows();
0248     uiFiles.remove_file->setEnabled(indexes.count());
0249 
0250     bool propertiesEnabled = (indexes.count() == 1);
0251     uiFiles.properties_file->setEnabled(propertiesEnabled);
0252 }
0253 
0254 void MetalinkCreator::slotAddLocalFilesClicked()
0255 {
0256     QPointer<QFileDialog> dialog = new QFileDialog(this);
0257     dialog->setFileMode(QFileDialog::ExistingFiles);
0258     if (dialog->exec() == QDialog::Accepted) {
0259         m_handler->slotFiles(dialog->selectedUrls());
0260     }
0261     delete dialog;
0262 }
0263 
0264 void MetalinkCreator::slotAddFile()
0265 {
0266     auto *item = new QStandardItem(m_tempFile.name);
0267     m_filesModel->insertRow(m_filesModel->rowCount(), item);
0268     metalink.files.files.append(m_tempFile);
0269     m_tempFile.clear();
0270 
0271     slotUpdateAssistantButtons(nullptr, m_files);
0272 }
0273 
0274 void MetalinkCreator::slotAddFile(const KGetMetalink::File &file)
0275 {
0276     auto *item = new QStandardItem(file.name);
0277     if (!file.resources.isValid()) {
0278         ++m_needUrlCount;
0279         item->setIcon(QIcon::fromTheme("edit-delete"));
0280     }
0281     m_filesModel->insertRow(m_filesModel->rowCount(), item);
0282     metalink.files.files.append(file);
0283 
0284     slotUpdateAssistantButtons(nullptr, m_files);
0285 }
0286 
0287 void MetalinkCreator::slotFileEdited(const QString &oldFileName, const QString &newFileName)
0288 {
0289     Q_UNUSED(oldFileName)
0290 
0291     const QModelIndex index = uiFiles.files->selectionModel()->selectedRows().first();
0292     QStandardItem *item = m_filesModel->itemFromIndex(index);
0293     item->setText(newFileName);
0294 
0295     // had no url but has it now
0296     if (!item->icon().isNull()) {
0297         --m_needUrlCount;
0298         item->setIcon(QIcon());
0299     }
0300 
0301     slotUpdateAssistantButtons(nullptr, m_files);
0302 }
0303 
0304 void MetalinkCreator::slotRemoveFile()
0305 {
0306     while (uiFiles.files->selectionModel()->hasSelection()) {
0307         const QModelIndex index = uiFiles.files->selectionModel()->selectedRows().first();
0308         const QString filePath = index.data().toString();
0309         for (int i = 0; i < metalink.files.files.size(); ++i) {
0310             if (metalink.files.files.at(i).name == filePath) {
0311                 // the entry had not url, so do not count it anymore
0312                 if (!index.data(Qt::DecorationRole).isNull()) {
0313                     --m_needUrlCount;
0314                 }
0315                 metalink.files.files.removeAt(i);
0316                 break;
0317             }
0318         }
0319 
0320         m_filesModel->removeRow(index.row());
0321     }
0322 
0323     slotUpdateFilesButtons();
0324     slotUpdateAssistantButtons(nullptr, m_files);
0325 }
0326 
0327 void MetalinkCreator::slotAddClicked()
0328 {
0329     // no old stored data should be used
0330     m_tempFile.clear();
0331     fileDlg(&m_tempFile);
0332 }
0333 
0334 void MetalinkCreator::fileDlg(KGetMetalink::File *file, bool edit)
0335 {
0336     QStringList currentNames;
0337     for (int i = 0; i < m_filesModel->rowCount(); ++i) {
0338         currentNames.append(m_filesModel->index(i, 0).data().toString());
0339     }
0340 
0341     auto *fileDlg = new FileDlg(file, currentNames, m_countrySort, m_languageSort, this, edit);
0342     fileDlg->setAttribute(Qt::WA_DeleteOnClose);
0343     fileDlg->setWindowModality(Qt::ApplicationModal);
0344     fileDlg->show();
0345 
0346     connect(fileDlg, SIGNAL(addFile()), this, SLOT(slotAddFile()));
0347     connect(fileDlg, &FileDlg::fileEdited, this, &MetalinkCreator::slotFileEdited);
0348 }
0349 
0350 void MetalinkCreator::slotFileProperties()
0351 {
0352     const QModelIndex index = uiFiles.files->selectionModel()->selectedRows().first();
0353     const QString fileName = index.data().toString();
0354 
0355     // search the selected file in metalink
0356     for (int i = 0; i < metalink.files.files.count(); ++i) {
0357         if (metalink.files.files.at(i).name == fileName) {
0358             fileDlg(&metalink.files.files[i], true);
0359             break;
0360         }
0361     }
0362 }
0363 void MetalinkCreator::slotOpenDragDlg()
0364 {
0365     m_tempResources.clear();
0366     m_tempCommonData.clear();
0367     auto *dragDlg = new DragDlg(&m_tempResources, &m_tempCommonData, m_countrySort, m_languageSort, this);
0368     dragDlg->setAttribute(Qt::WA_DeleteOnClose);
0369     dragDlg->show();
0370 
0371     connect(dragDlg, &DragDlg::usedTypes, this, &MetalinkCreator::slotHandleDropped);
0372 }
0373 void MetalinkCreator::slotHandleDropped(const QStringList &types, bool createPartial)
0374 {
0375     uiFiles.progressBar->setMaximum(0);
0376     uiFiles.dragDrop->show();
0377     m_thread.setData(m_handler->takeFiles(), types, createPartial, m_tempResources, m_tempCommonData);
0378 }
0379 
0380 void MetalinkCreator::slotThreadFinished()
0381 {
0382     uiFiles.progressBar->setMaximum(10);
0383     uiFiles.dragDrop->hide();
0384     slotUpdateAssistantButtons(nullptr, m_files);
0385 }
0386 
0387 #include "moc_metalinkcreator.cpp"