File indexing completed on 2024-04-28 04:57:36

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     uiIntroduction.save->setNameFilters(
0171         {i18n("Metalink Version 4.0 file") + QLatin1String(" (*.meta4)"), i18n("Metalink Version 3.0 file") + QLatin1String(" (*.metalink)")});
0172     uiIntroduction.load->setNameFilter(i18n("Metalink file (*.metalink *.meta4)") + QLatin1String(" (*.metalink *.meta4)"));
0173     uiIntroduction.save->setAcceptMode(QFileDialog::AcceptSave);
0174 
0175     connect(uiIntroduction.save, &KUrlRequester::textChanged, this, &MetalinkCreator::slotUpdateIntroductionNextButton);
0176     connect(uiIntroduction.load, &KUrlRequester::textChanged, this, &MetalinkCreator::slotUpdateIntroductionNextButton);
0177     connect(uiIntroduction.loadButton, &QAbstractButton::toggled, this, &MetalinkCreator::slotUpdateIntroductionNextButton);
0178 
0179     m_introduction = addPage(widget, i18n("Define the saving location."));
0180 
0181     setValid(m_introduction, false);
0182 }
0183 
0184 void MetalinkCreator::slotUpdateIntroductionNextButton()
0185 {
0186     bool enableNext = false;
0187 
0188     // check if a save location and if selected if also a load location has been specified and if the m_countrySort has been created
0189     enableNext = uiIntroduction.save->url().isValid() && m_countrySort;
0190     if (enableNext && uiIntroduction.loadButton->isChecked()) {
0191         enableNext = uiIntroduction.load->url().isValid();
0192     }
0193 
0194     setValid(m_introduction, enableNext);
0195 }
0196 
0197 void MetalinkCreator::createFiles()
0198 {
0199     m_handler = new DirectoryHandler(this);
0200     connect(m_handler, &DirectoryHandler::finished, this, &MetalinkCreator::slotOpenDragDlg);
0201 
0202     auto *widget = new FileWidget(this);
0203     uiFiles.setupUi(widget);
0204 
0205     m_filesModel = new QStandardItemModel(0, 1, this);
0206     uiFiles.files->setModel(m_filesModel);
0207 
0208     uiFiles.infoWidget->setCloseButtonVisible(false);
0209     uiFiles.infoWidget->setMessageType(KMessageWidget::Information);
0210     uiFiles.add_local_file->setIcon(QIcon::fromTheme("list-add"));
0211     KGuiItem::assign(uiFiles.add_file, KStandardGuiItem::add());
0212     KGuiItem::assign(uiFiles.properties_file, KStandardGuiItem::properties());
0213     uiFiles.properties_file->setEnabled(false);
0214     KGuiItem::assign(uiFiles.remove_file, KStandardGuiItem::remove());
0215     uiFiles.remove_file->setEnabled(false);
0216     uiFiles.dragDrop->hide();
0217 
0218     connect(uiFiles.add_local_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotAddLocalFilesClicked);
0219     connect(uiFiles.add_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotAddClicked);
0220     connect(uiFiles.remove_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotRemoveFile);
0221     connect(uiFiles.properties_file, &QAbstractButton::clicked, this, &MetalinkCreator::slotFileProperties);
0222     connect(uiFiles.files->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MetalinkCreator::slotUpdateFilesButtons);
0223     connect(widget, &FileWidget::urlsDropped, m_handler, &DirectoryHandler::slotFiles);
0224 
0225     addPage(widget, i18nc("file as in file on hard drive", "Files"));
0226 }
0227 
0228 void MetalinkCreator::loadFiles()
0229 {
0230     foreach (const KGetMetalink::File &file, metalink.files.files) {
0231         auto *item = new QStandardItem(file.name);
0232         if (!file.resources.isValid()) {
0233             ++m_needUrlCount;
0234             item->setIcon(QIcon::fromTheme("edit-delete"));
0235         }
0236         m_filesModel->insertRow(m_filesModel->rowCount(), item);
0237     }
0238 }
0239 
0240 void MetalinkCreator::slotUpdateFilesButtons()
0241 {
0242     const QModelIndexList indexes = uiFiles.files->selectionModel()->selectedRows();
0243     uiFiles.remove_file->setEnabled(indexes.count());
0244 
0245     bool propertiesEnabled = (indexes.count() == 1);
0246     uiFiles.properties_file->setEnabled(propertiesEnabled);
0247 }
0248 
0249 void MetalinkCreator::slotAddLocalFilesClicked()
0250 {
0251     QPointer<QFileDialog> dialog = new QFileDialog(this);
0252     dialog->setFileMode(QFileDialog::ExistingFiles);
0253     if (dialog->exec() == QDialog::Accepted) {
0254         m_handler->slotFiles(dialog->selectedUrls());
0255     }
0256     delete dialog;
0257 }
0258 
0259 void MetalinkCreator::slotAddFile()
0260 {
0261     auto *item = new QStandardItem(m_tempFile.name);
0262     m_filesModel->insertRow(m_filesModel->rowCount(), item);
0263     metalink.files.files.append(m_tempFile);
0264     m_tempFile.clear();
0265 
0266     slotUpdateAssistantButtons(nullptr, m_files);
0267 }
0268 
0269 void MetalinkCreator::slotAddFile(const KGetMetalink::File &file)
0270 {
0271     auto *item = new QStandardItem(file.name);
0272     if (!file.resources.isValid()) {
0273         ++m_needUrlCount;
0274         item->setIcon(QIcon::fromTheme("edit-delete"));
0275     }
0276     m_filesModel->insertRow(m_filesModel->rowCount(), item);
0277     metalink.files.files.append(file);
0278 
0279     slotUpdateAssistantButtons(nullptr, m_files);
0280 }
0281 
0282 void MetalinkCreator::slotFileEdited(const QString &oldFileName, const QString &newFileName)
0283 {
0284     Q_UNUSED(oldFileName)
0285 
0286     const QModelIndex index = uiFiles.files->selectionModel()->selectedRows().first();
0287     QStandardItem *item = m_filesModel->itemFromIndex(index);
0288     item->setText(newFileName);
0289 
0290     // had no url but has it now
0291     if (!item->icon().isNull()) {
0292         --m_needUrlCount;
0293         item->setIcon(QIcon());
0294     }
0295 
0296     slotUpdateAssistantButtons(nullptr, m_files);
0297 }
0298 
0299 void MetalinkCreator::slotRemoveFile()
0300 {
0301     while (uiFiles.files->selectionModel()->hasSelection()) {
0302         const QModelIndex index = uiFiles.files->selectionModel()->selectedRows().first();
0303         const QString filePath = index.data().toString();
0304         for (int i = 0; i < metalink.files.files.size(); ++i) {
0305             if (metalink.files.files.at(i).name == filePath) {
0306                 // the entry had not url, so do not count it anymore
0307                 if (!index.data(Qt::DecorationRole).isNull()) {
0308                     --m_needUrlCount;
0309                 }
0310                 metalink.files.files.removeAt(i);
0311                 break;
0312             }
0313         }
0314 
0315         m_filesModel->removeRow(index.row());
0316     }
0317 
0318     slotUpdateFilesButtons();
0319     slotUpdateAssistantButtons(nullptr, m_files);
0320 }
0321 
0322 void MetalinkCreator::slotAddClicked()
0323 {
0324     // no old stored data should be used
0325     m_tempFile.clear();
0326     fileDlg(&m_tempFile);
0327 }
0328 
0329 void MetalinkCreator::fileDlg(KGetMetalink::File *file, bool edit)
0330 {
0331     QStringList currentNames;
0332     for (int i = 0; i < m_filesModel->rowCount(); ++i) {
0333         currentNames.append(m_filesModel->index(i, 0).data().toString());
0334     }
0335 
0336     auto *fileDlg = new FileDlg(file, currentNames, m_countrySort, m_languageSort, this, edit);
0337     fileDlg->setAttribute(Qt::WA_DeleteOnClose);
0338     fileDlg->setWindowModality(Qt::ApplicationModal);
0339     fileDlg->show();
0340 
0341     connect(fileDlg, SIGNAL(addFile()), this, SLOT(slotAddFile()));
0342     connect(fileDlg, &FileDlg::fileEdited, this, &MetalinkCreator::slotFileEdited);
0343 }
0344 
0345 void MetalinkCreator::slotFileProperties()
0346 {
0347     const QModelIndex index = uiFiles.files->selectionModel()->selectedRows().first();
0348     const QString fileName = index.data().toString();
0349 
0350     // search the selected file in metalink
0351     for (int i = 0; i < metalink.files.files.count(); ++i) {
0352         if (metalink.files.files.at(i).name == fileName) {
0353             fileDlg(&metalink.files.files[i], true);
0354             break;
0355         }
0356     }
0357 }
0358 void MetalinkCreator::slotOpenDragDlg()
0359 {
0360     m_tempResources.clear();
0361     m_tempCommonData.clear();
0362     auto *dragDlg = new DragDlg(&m_tempResources, &m_tempCommonData, m_countrySort, m_languageSort, this);
0363     dragDlg->setAttribute(Qt::WA_DeleteOnClose);
0364     dragDlg->show();
0365 
0366     connect(dragDlg, &DragDlg::usedTypes, this, &MetalinkCreator::slotHandleDropped);
0367 }
0368 void MetalinkCreator::slotHandleDropped(const QStringList &types, bool createPartial)
0369 {
0370     uiFiles.progressBar->setMaximum(0);
0371     uiFiles.dragDrop->show();
0372     m_thread.setData(m_handler->takeFiles(), types, createPartial, m_tempResources, m_tempCommonData);
0373 }
0374 
0375 void MetalinkCreator::slotThreadFinished()
0376 {
0377     uiFiles.progressBar->setMaximum(10);
0378     uiFiles.dragDrop->hide();
0379     slotUpdateAssistantButtons(nullptr, m_files);
0380 }
0381 
0382 #include "moc_metalinkcreator.cpp"