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"