diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b9f5d0..29a2dfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,121 +1,121 @@ cmake_minimum_required(VERSION 3.5) set(PIM_VERSION "5.14.40") project(pim-data-exporter VERSION ${PIM_VERSION}) set(RELEASE_SERVICE_VERSION "20.07.40") set(KF5_MIN_VERSION "5.70.0") find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMAddTests) include(GenerateExportHeader) include(ECMGenerateHeaders) include(FeatureSummary) include(CheckFunctionExists) include(ECMGeneratePriFile) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMAddAppIcon) include(ECMQtDeclareLoggingCategory) # Do NOT add quote set(KDEPIM_DEV_VERSION alpha) # add an extra space if(DEFINED KDEPIM_DEV_VERSION) set(KDEPIM_DEV_VERSION " ${KDEPIM_DEV_VERSION}") endif() set(KDEPIM_VERSION "${PIM_VERSION}${KDEPIM_DEV_VERSION} (${RELEASE_SERVICE_VERSION})") set(KDEPIM_LIB_VERSION "${PIM_VERSION}") set(KDEPIM_LIB_SOVERSION "5") set(QT_REQUIRED_VERSION "5.13.0") if(BUILD_TESTING) find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets Test) endif() set(AKONADI_VERSION "5.14.40") set(IDENTITYMANAGEMENT_LIB_VERSION "5.14.40") set(KMAILTRANSPORT_LIB_VERSION "5.14.40") set(KMIME_LIB_VERSION "5.14.40") set(KPIMTEXTEDIT_LIB_VERSION "5.14.40") set(LIBKDEPIM_LIB_VERSION_LIB "5.14.40") set(MAILCOMMON_LIB_VERSION_LIB "5.14.40") set(PIMCOMMON_LIB_VERSION_LIB "5.14.40") set(AKONADINOTES_LIB_VERSION "5.14.40") # Find KF5 package find_package(KF5Archive ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Config ${KF5_MIN_VERSION} REQUIRED) find_package(KF5ConfigWidgets ${KF5_MIN_VERSION} REQUIRED) find_package(KF5CoreAddons ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Crash ${KF5_MIN_VERSION} REQUIRED) find_package(KF5DBusAddons ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5DocTools ${KF5_MIN_VERSION} REQUIRED) find_package(KF5ItemViews ${KF5_MIN_VERSION} REQUIRED) find_package(KF5KIO ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Notifications ${KF5_MIN_VERSION} REQUIRED) find_package(KF5WidgetsAddons ${KF5_MIN_VERSION} REQUIRED) find_package(KF5XmlGui ${KF5_MIN_VERSION} REQUIRED) find_package(KF5WidgetsAddons ${KF5_MIN_VERSION} REQUIRED) # Find KdepimLibs Package find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED) find_package(KF5Contacts ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5IdentityManagement ${IDENTITYMANAGEMENT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Libkdepim ${LIBKDEPIM_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5MailCommon ${MAILCOMMON_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5MailTransport ${KMAILTRANSPORT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5PimCommonAkonadi ${PIMCOMMON_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5PimTextEdit ${KPIMTEXTEDIT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiNotes ${AKONADINOTES_LIB_VERSION} CONFIG REQUIRED) find_package(KUserFeedback 0.9.90 CONFIG) # Needs Provider::describeDataSources() set_package_properties(KUserFeedback PROPERTIES DESCRIPTION "User Feedback lib" TYPE OPTIONAL PURPOSE "Allow to send Telemetry Information (optional). It can be disable in apps.") include_directories(${pim-data-exporter_SOURCE_DIR} ${pim-data-exporter_BINARY_DIR}) add_definitions(-DTRANSLATION_DOMAIN=\"pimdataexporter\") if (EXISTS "${CMAKE_SOURCE_DIR}/.git") add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050f00) - add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054600) + add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054700) endif() configure_file(pimdataexporter-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/pimdataexporter-version.h @ONLY) add_definitions(-DQT_NO_FOREACH) add_definitions(-DQT_NO_KEYWORDS) if(BUILD_TESTING) add_definitions(-DBUILD_TESTING) endif(BUILD_TESTING) add_subdirectory(core) add_subdirectory(gui) add_subdirectory(console) ecm_qt_install_logging_categories( EXPORT PIMDATAEXPORTER FILE pimdataexporter.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} ) install(FILES org.kde.pimdataexporter.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) add_subdirectory(doc) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/gui/dialog/showarchivestructuredialog.cpp b/gui/dialog/showarchivestructuredialog.cpp index 5bfeeaf..04a4261 100644 --- a/gui/dialog/showarchivestructuredialog.cpp +++ b/gui/dialog/showarchivestructuredialog.cpp @@ -1,280 +1,293 @@ /* Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "showarchivestructuredialog.h" #include "core/utils.h" #include "pimdataexportgui_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include +#if KIO_VERSION >= QT_VERSION_CHECK(5, 71, 0) +#include +#include +#else #include +#endif #include #include #include ShowArchiveStructureDialog::ShowArchiveStructureDialog(const QString &filename, QWidget *parent) : QDialog(parent) , mFileName(filename) { setWindowTitle(i18nc("@title:window", "Show Archive Content on file \"%1\"", filename)); setModal(true); QVBoxLayout *mainLayout = new QVBoxLayout(this); mTreeWidget = new QTreeWidget(this); mTreeWidget->header()->hide(); mTreeWidget->setAlternatingRowColors(true); KTreeWidgetSearchLine *searchLine = new KTreeWidgetSearchLine(this, mTreeWidget); searchLine->setPlaceholderText(i18n("Search...")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this); QPushButton *user1Button = new QPushButton(this); user1Button->setText(i18n("Save As Text...")); buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); connect(buttonBox, &QDialogButtonBox::rejected, this, &ShowArchiveStructureDialog::reject); mExtractFile = new QPushButton(this); mExtractFile->setText(i18n("Extract Selected File")); mExtractFile->setEnabled(false); connect(mExtractFile, &QPushButton::clicked, this, &ShowArchiveStructureDialog::slotExtractFile); buttonBox->addButton(mExtractFile, QDialogButtonBox::ActionRole); mOpenFile = new QPushButton(this); mOpenFile->setText(i18n("Open Selected File")); mOpenFile->setEnabled(false); connect(mOpenFile, &QPushButton::clicked, this, &ShowArchiveStructureDialog::slotOpenFile); buttonBox->addButton(mOpenFile, QDialogButtonBox::ActionRole); connect(mTreeWidget, &QTreeWidget::itemClicked, this, &ShowArchiveStructureDialog::slotItemClicked); mainLayout->addWidget(searchLine); mainLayout->addWidget(mTreeWidget); mainLayout->addWidget(buttonBox); const bool result = fillTree(); if (result) { mTreeWidget->expandAll(); connect(user1Button, &QPushButton::clicked, this, &ShowArchiveStructureDialog::slotExportAsLogFile); } else { user1Button->setEnabled(false); } readConfig(); } ShowArchiveStructureDialog::~ShowArchiveStructureDialog() { writeConfig(); delete mZip; delete mTempDir; } void ShowArchiveStructureDialog::slotOpenFile() { QTreeWidgetItem *currentItem = mTreeWidget->currentItem(); if (currentItem) { const QString fullPath = currentItem->data(0, FullPath).toString(); if (!fullPath.isEmpty()) { const KArchiveDirectory *topDirectory = mZip->directory(); const KArchiveEntry *currentEntry = topDirectory->entry(fullPath); if (currentEntry && currentEntry->isFile()) { const KArchiveFile *currentFile = static_cast(currentEntry); if (!mTempDir) { mTempDir = new QTemporaryDir; } const QString fileName = mTempDir->path() + QLatin1Char('/') + currentItem->text(0); QFile f(fileName); if (!f.open(QIODevice::WriteOnly)) { qCWarning(PIMDATAEXPORTERGUI_LOG) << "Impossible to extract file: " << currentItem->text(0); return; } const QByteArray data = currentFile->data(); if (f.write(data) != data.length()) { qCWarning(PIMDATAEXPORTERGUI_LOG) << "Impossible to copy file: " << currentItem->text(0); return; } +#if KIO_VERSION >= QT_VERSION_CHECK(5, 71, 0) + KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(fileName)); + job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); + job->setRunExecutables(false); + job->start(); +#else KRun *runner = new KRun(QUrl::fromLocalFile(fileName), this); // will delete itself runner->setRunExecutables(false); +#endif } } } } void ShowArchiveStructureDialog::slotExtractFile() { QTreeWidgetItem *currentItem = mTreeWidget->currentItem(); if (currentItem) { const QString fullPath = currentItem->data(0, FullPath).toString(); if (!fullPath.isEmpty()) { const KArchiveDirectory *topDirectory = mZip->directory(); const KArchiveEntry *currentEntry = topDirectory->entry(fullPath); if (currentEntry && currentEntry->isFile()) { const KArchiveFile *currentFile = static_cast(currentEntry); const QString dir = QFileDialog::getExistingDirectory(this, i18n("Select Directory"), QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (!dir.isEmpty()) { if (QFile(dir + QLatin1Char('/') + currentFile->name()).exists()) { if (KMessageBox::questionYesNo(this, i18n("Do you want to override %1?", currentFile->name()), i18n("File Already Exist")) == KMessageBox::No) { return; } } if (!currentFile->copyTo(dir)) { KMessageBox::error(this, i18n("Impossible to copy %1 in %2.", currentFile->name(), dir)); qCWarning(PIMDATAEXPORTERGUI_LOG) << "Impossible to extract file: " << currentItem->text(0) << " to " << dir; } } } } } } void ShowArchiveStructureDialog::slotItemClicked(QTreeWidgetItem *item, int column) { Q_UNUSED(column); if (item) { const QString fullPath = item->data(0, FullPath).toString(); const bool enableButton = !fullPath.isEmpty(); mExtractFile->setEnabled(enableButton); mOpenFile->setEnabled(enableButton); } } void ShowArchiveStructureDialog::slotExportAsLogFile() { PimCommon::Util::saveTextAs(mLogFile, QStringLiteral("%1 (*.txt)").arg(i18nc("qfiledialog filter files text", "Text Files")), this, QUrl(), i18nc("@title:window", "Export Log File")); } bool ShowArchiveStructureDialog::fillTree() { mZip = new KZip(mFileName); bool result = mZip->open(QIODevice::ReadOnly); if (!result) { KMessageBox::error(this, i18n("Archive cannot be opened in read mode."), i18n("Cannot open archive")); delete mZip; mZip = nullptr; return false; } const KArchiveDirectory *topDirectory = mZip->directory(); const bool isAValidArchive = searchArchiveElement(Utils::infoPath(), topDirectory, i18n("Info")); if (!isAValidArchive) { KMessageBox::error(this, i18n("This is not pim archive."), i18n("Show information")); result = false; } else { (void)searchArchiveElement(Utils::mailsPath(), topDirectory, Utils::appTypeToI18n(Utils::KMail)); (void)searchArchiveElement(Utils::alarmPath(), topDirectory, Utils::appTypeToI18n(Utils::KAlarm)); (void)searchArchiveElement(Utils::calendarPath(), topDirectory, Utils::appTypeToI18n(Utils::KOrganizer)); (void)searchArchiveElement(Utils::addressbookPath(), topDirectory, Utils::appTypeToI18n(Utils::KAddressBook)); (void)searchArchiveElement(Utils::identitiesPath(), topDirectory, Utils::storedTypeToI18n(Utils::Identity)); (void)searchArchiveElement(Utils::resourcesPath(), topDirectory, Utils::storedTypeToI18n(Utils::Resources)); (void)searchArchiveElement(Utils::configsPath(), topDirectory, Utils::storedTypeToI18n(Utils::Config)); (void)searchArchiveElement(Utils::transportsPath(), topDirectory, Utils::storedTypeToI18n(Utils::MailTransport)); (void)searchArchiveElement(Utils::dataPath(), topDirectory, Utils::storedTypeToI18n(Utils::Data)); (void)searchArchiveElement(Utils::notePath(), topDirectory, Utils::appTypeToI18n(Utils::KNotes)); } return result; } bool ShowArchiveStructureDialog::searchArchiveElement(const QString &path, const KArchiveDirectory *topDirectory, const QString &name) { const KArchiveEntry *topEntry = topDirectory->entry(path); bool result = true; if (topEntry) { mLogFile += name + QLatin1Char('\n'); QTreeWidgetItem *item = addTopItem(name); addSubItems(path, item, topEntry, 0); } else { result = false; } return result; } void ShowArchiveStructureDialog::addSubItems(const QString &topLevelPath, QTreeWidgetItem *parent, const KArchiveEntry *entry, int indent, const QString &fullpath) { const KArchiveDirectory *dir = static_cast(entry); ++indent; const QString space = QString(indent * 2, QLatin1Char(' ')); const QStringList lst = dir->entries(); for (const QString &entryName : lst) { const KArchiveEntry *entry = dir->entry(entryName); if (entry) { if (entry->isDirectory()) { const KArchiveDirectory *dirEntry = static_cast(entry); QTreeWidgetItem *newTopItem = addItem(parent, dirEntry->name(), QString()); QFont font(newTopItem->font(0)); font.setBold(true); mLogFile += space + dirEntry->name() + QLatin1Char('\n'); newTopItem->setFont(0, font); addSubItems(topLevelPath, newTopItem, entry, indent, (fullpath.isEmpty() ? QString() : fullpath + QLatin1Char('/')) + dirEntry->name()); } else if (entry->isFile()) { const KArchiveFile *file = static_cast(entry); const QString fileFullPath = topLevelPath + (fullpath.isEmpty() ? QString() : fullpath + QLatin1Char('/')) + file->name(); //qDebug() << " fileFullPath " <name(), fileFullPath); mLogFile += space + file->name() + QLatin1Char('\n'); } } } } QTreeWidgetItem *ShowArchiveStructureDialog::addItem(QTreeWidgetItem *parent, const QString &name, const QString &fillFullPath) { QTreeWidgetItem *item = new QTreeWidgetItem(parent); item->setText(0, name); item->setData(0, FullPath, fillFullPath); return item; } QTreeWidgetItem *ShowArchiveStructureDialog::addTopItem(const QString &name) { QTreeWidgetItem *item = new QTreeWidgetItem; QFont font = item->font(0); font.setBold(true); item->setFont(0, font); item->setText(0, name); mTreeWidget->addTopLevelItem(item); return item; } void ShowArchiveStructureDialog::writeConfig() { KConfigGroup group(KSharedConfig::openConfig(), "ShowArchiveStructureDialog"); group.writeEntry("Size", size()); } void ShowArchiveStructureDialog::readConfig() { KConfigGroup group(KSharedConfig::openConfig(), "ShowArchiveStructureDialog"); const QSize sizeDialog = group.readEntry("Size", QSize(600, 400)); if (sizeDialog.isValid()) { resize(sizeDialog); } }