File indexing completed on 2024-06-23 05:03:08

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007  * This file is a plugin for file operation.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgfileplugin.h"
0012 
0013 #include <kaboutdata.h>
0014 #include <kactioncollection.h>
0015 #include <kmessagewidget.h>
0016 #include <knewpassworddialog.h>
0017 #include <kpassworddialog.h>
0018 #include <kpluginfactory.h>
0019 #include <krecentfilesaction.h>
0020 #include <kstandardaction.h>
0021 #include <kwallet.h>
0022 
0023 #include <qfile.h>
0024 #include <qfiledialog.h>
0025 #include <qsplashscreen.h>
0026 #include <qwidget.h>
0027 
0028 #include "skgerror.h"
0029 #include "skgfile_settings.h"
0030 #include "skgmainpanel.h"
0031 #include "skgtraces.h"
0032 #include "skgtransactionmng.h"
0033 
0034 /**
0035  * This plugin factory.
0036  */
0037 K_PLUGIN_CLASS_WITH_JSON(SKGFilePlugin, "metadata.json")
0038 
0039 SKGFilePlugin::SKGFilePlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/) :
0040     SKGInterfacePlugin(iParent),
0041     m_saveAction(nullptr), m_recentFiles(nullptr), m_currentDocument(nullptr)
0042 {
0043     Q_UNUSED(iWidget)
0044     SKGTRACEINFUNC(10)
0045 
0046     // Set save on close mode
0047     if (SKGMainPanel::getMainPanel() != nullptr) {
0048         SKGMainPanel::getMainPanel()->setSaveOnClose(skgfile_settings::saveonclose());
0049     }
0050 }
0051 
0052 SKGFilePlugin::~SKGFilePlugin()
0053 {
0054     SKGTRACEINFUNC(10)
0055     if (m_recentFiles != nullptr) {
0056         m_recentFiles->saveEntries(KConfigGroup(KSharedConfig::openConfig(), "RecentFiles"));
0057     }
0058 
0059     m_currentDocument = nullptr;
0060     m_recentFiles = nullptr;
0061     m_saveAction = nullptr;
0062 }
0063 
0064 bool SKGFilePlugin::setupActions(SKGDocument* iDocument)
0065 {
0066     SKGTRACEINFUNC(10)
0067 
0068     m_currentDocument = iDocument;
0069     if (m_currentDocument == nullptr) {
0070         return false;
0071     }
0072 
0073     setComponentName(QStringLiteral("skg_file"), title());
0074     setXMLFile(QStringLiteral("skg_file.rc"));
0075 
0076     // Menu
0077     registerGlobalAction(QStringLiteral("file_new"), KStandardAction::openNew(this, SLOT(onNew()), actionCollection()));
0078     registerGlobalAction(QStringLiteral("file_open"), KStandardAction::open(this, SLOT(onOpen()), actionCollection()));
0079 
0080     m_saveAction = KStandardAction::save(this, SLOT(onSave()), actionCollection());
0081     registerGlobalAction(QStringLiteral("file_save"), m_saveAction);
0082     registerGlobalAction(QStringLiteral("file_save_as"), KStandardAction::saveAs(this, SLOT(onSaveAs()), actionCollection()));
0083 
0084     auto actChangePassword = new QAction(SKGServices::fromTheme(QStringLiteral("document-encrypt")),  i18nc("Action allowing the user to change his document password", "Change password…"), this);
0085     connect(actChangePassword, &QAction::triggered, this, &SKGFilePlugin::onChangePassword);
0086     actionCollection()->setDefaultShortcut(actChangePassword, Qt::CTRL + Qt::Key_K);
0087     registerGlobalAction(QStringLiteral("file_change_password"), actChangePassword);
0088 
0089     // Recent file
0090     m_recentFiles = KStandardAction::openRecent(this, SLOT(onOpen(QUrl)), actionCollection());
0091     if (m_recentFiles != nullptr) {
0092         m_recentFiles->loadEntries(KConfigGroup(KSharedConfig::openConfig(), "RecentFiles"));
0093     }
0094 
0095     // Get last argument
0096     connect(this, &SKGFilePlugin::loadFile, this, &SKGFilePlugin::onOpen, Qt::QueuedConnection);
0097 
0098     return true;
0099 }
0100 
0101 QStringList SKGFilePlugin::processArguments(const QStringList& iArgument)
0102 {
0103     SKGTRACEINFUNC(10)
0104     QStringList output = iArgument;
0105     if (m_currentDocument->getCurrentFileName().isEmpty()) {
0106         int nbArg = iArgument.count();
0107         int openMode = 1;  // 0=no open, 1=open last opened if settings set, 2=new document
0108         if (nbArg != 0) {
0109             openMode = 2;
0110             QString filename = iArgument.at(nbArg - 1);
0111             QString extension = QFileInfo(filename).suffix().toUpper();
0112             auto inputFile = QFileInfo(filename);
0113             if (!inputFile.isAbsolute()) {
0114                 filename = QFileInfo(QDir::currentPath(), filename).absoluteFilePath();
0115             }
0116 
0117             QString extensionDocument = m_currentDocument->getFileExtension().toUpper();
0118             if (extension == extensionDocument) {
0119                 if (QFile(filename).exists()) {
0120                     if (SKGMainPanel::getMainPanel() != nullptr) {
0121                         QSplashScreen* splashScreen = SKGMainPanel::getMainPanel()->splashScreen();
0122                         if (splashScreen != nullptr) {
0123                             splashScreen->showMessage(i18nc("Splash screen message", "Opening file %1…", filename), Qt::AlignLeft, QColor(221, 130, 8));    // krazy:exclude=qmethods
0124                         }
0125                     }
0126                     Q_EMIT loadFile(QUrl::fromLocalFile(filename));
0127                     output.pop_back();
0128                     openMode = 0;
0129                 } else {
0130                     m_currentDocument->sendMessage(i18nc("Error Message", "File %1 not found! Impossible to open it.", filename), SKGDocument::Error);
0131                 }
0132             }
0133         }
0134 
0135         if (openMode != 0) {
0136             // Read Setting
0137             bool openlastfile = skgfile_settings::openlastfile();
0138             if (openMode == 1 && openlastfile) {
0139                 QString lastOpenedFile = skgfile_settings::lastfilepath();
0140                 if (!lastOpenedFile.isEmpty() && QFile(lastOpenedFile).exists()) {
0141                     if (SKGMainPanel::getMainPanel() != nullptr) {
0142                         QSplashScreen* splashScreen = SKGMainPanel::getMainPanel()->splashScreen();
0143                         if (splashScreen != nullptr) {
0144                             splashScreen->showMessage(i18nc("Splash screen message",  "Opening file %1…", lastOpenedFile), Qt::AlignLeft, QColor(221, 130, 8));    // krazy:exclude=qmethods
0145                         }
0146                     }
0147                     Q_EMIT loadFile(QUrl::fromLocalFile(lastOpenedFile));
0148                 } else {
0149                     openMode = 2;
0150                 }
0151             } else {
0152                 openMode = 2;
0153             }
0154 
0155             if (openMode == 2 && m_currentDocument->getMainDatabase() == nullptr) {
0156                 onNew();
0157             }
0158         }
0159 
0160         // To be sure that the document has the right parameters
0161         savePreferences();
0162     }
0163 
0164     return output;
0165 }
0166 
0167 QWidget* SKGFilePlugin::getPreferenceWidget()
0168 {
0169     SKGTRACEINFUNC(10)
0170     auto w = new QWidget();
0171     ui.setupUi(w);
0172     connect(ui.kcfg_backup_enabled, &QCheckBox::toggled, ui.kcfg_prefix, &SKGComboBox::setEnabled);
0173     connect(ui.kcfg_backup_enabled, &QCheckBox::toggled, ui.kcfg_suffix, &SKGComboBox::setEnabled);
0174     connect(ui.kcfg_storeInKdeWallet, &QCheckBox::toggled, ui.kcfg_selectedWallet, &SKGComboBox::setEnabled);
0175 
0176     ui.kcfg_prefix->addItem(QLatin1String(""));
0177     ui.kcfg_prefix->addItem(QStringLiteral("."));
0178 
0179     ui.kcfg_suffix->addItem(QStringLiteral(".old"));
0180     ui.kcfg_suffix->addItem(QStringLiteral(".back"));
0181     ui.kcfg_suffix->addItem(QStringLiteral(".<DATE>.back"));
0182     ui.kcfg_suffix->addItem(QStringLiteral(".<DATE>.old"));
0183     ui.kcfg_suffix->addItem(QStringLiteral("~"));
0184 
0185     ui.kcfg_selectedWallet->addItems(KWallet::Wallet::walletList());
0186 
0187     return w;
0188 }
0189 
0190 KConfigSkeleton* SKGFilePlugin::getPreferenceSkeleton()
0191 {
0192     return skgfile_settings::self();
0193 }
0194 
0195 SKGError SKGFilePlugin::savePreferences() const
0196 {
0197     SKGError err;
0198     if (m_currentDocument != nullptr) {
0199         // Read Setting
0200         QString prefix;
0201         QString suffix;
0202         if (skgfile_settings::backup_enabled()) {
0203             prefix = skgfile_settings::prefix();
0204             suffix = skgfile_settings::suffix();
0205         }
0206 
0207         // Save setting in document
0208         m_currentDocument->setBackupParameters(prefix, suffix);
0209 
0210         // Set save on close mode
0211         if (SKGMainPanel::getMainPanel()) {
0212             SKGMainPanel::getMainPanel()->setSaveOnClose(skgfile_settings::saveonclose());
0213         }
0214     }
0215     return err;
0216 }
0217 
0218 void SKGFilePlugin::refresh()
0219 {
0220     SKGTRACEINFUNC(10)
0221 
0222     // Refresh action status
0223     if (m_currentDocument != nullptr) {
0224         if (m_saveAction != nullptr) {
0225             m_saveAction->setEnabled(m_currentDocument->isFileModified());
0226         }
0227     }
0228 }
0229 
0230 QString SKGFilePlugin::title() const
0231 {
0232     return i18nc("Noun, a file as in a text file", "File");
0233 }
0234 
0235 QString SKGFilePlugin::icon() const
0236 {
0237     return QStringLiteral("document-save");
0238 }
0239 
0240 QString SKGFilePlugin::toolTip() const
0241 {
0242     return i18nc("File Management, as in Save File, Save As…", "File management");
0243 }
0244 
0245 QStringList SKGFilePlugin::tips() const
0246 {
0247     QStringList output;
0248     output.push_back(i18nc("Description of a tip", "<p>… the last opened file can be <a href=\"skg://tab_configure?page=File plugin\">open automatically</a> when the application is launched.</p>"));
0249     output.push_back(i18nc("Description of a tip", "<p>… you can secure your document with a <a href=\"skg://file_change_password\">password</a>.</p>"));
0250     return output;
0251 }
0252 
0253 int SKGFilePlugin::getOrder() const
0254 {
0255     // Must be one of the first
0256     return 1;
0257 }
0258 
0259 void SKGFilePlugin::onNew()
0260 {
0261     SKGError err;
0262     SKGTRACEINFUNCRC(10, err)
0263     if ((SKGMainPanel::getMainPanel() != nullptr) && (m_currentDocument != nullptr) && SKGMainPanel::getMainPanel()->queryFileClose()) {
0264         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0265 
0266         SKGMainPanel::getMainPanel()->closeAllPages(true);
0267 
0268         err = m_currentDocument->initialize();
0269 
0270         IFOKDO(err, m_currentDocument->setLanguage(QLocale::languageToString(QLocale().language())))
0271         QApplication::restoreOverrideCursor();
0272 
0273         // status bar
0274         IFOKDO(err, SKGError(0, i18nc("Successful message after creating a document", "Document successfully created.")))
0275         else {
0276             err.addError(ERR_FAIL, i18nc("Error message: Could not create a document",  "Document creation failed."));
0277         }
0278 
0279         // Display error
0280         SKGMainPanel::displayErrorMessage(err);
0281     }
0282 }
0283 
0284 void SKGFilePlugin::onSave()
0285 {
0286     SKGError err;
0287     SKGTRACEINFUNCRC(10, err)
0288     if ((m_currentDocument != nullptr) && (SKGMainPanel::getMainPanel() != nullptr)) {
0289         if (m_currentDocument->getCurrentFileName().isEmpty()) {
0290             onSaveAs();
0291         } else {
0292             QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0293             err = m_currentDocument->save();
0294             QApplication::restoreOverrideCursor();
0295 
0296             // Refresh
0297             SKGMainPanel::getMainPanel()->refresh();
0298 
0299             // status bar
0300             IFOKDO(err, SKGError(0, i18nc("Successfully saved a file", "File successfully saved.")))
0301             else {
0302                 err.addError(ERR_FAIL, i18nc("Error message: Could not save a file",  "Cannot save file"));
0303             }
0304 
0305             // Display error
0306             SKGMainPanel::displayErrorMessage(err);
0307         }
0308     }
0309 }
0310 
0311 void SKGFilePlugin::onSaveAs()
0312 {
0313     SKGError err;
0314     SKGTRACEINFUNCRC(10, err)
0315     if ((m_currentDocument != nullptr) && (SKGMainPanel::getMainPanel() != nullptr)) {
0316         QString fileName = SKGMainPanel::getSaveFileName("kfiledialog:///" % m_currentDocument->objectName(),
0317                            "*." % m_currentDocument->getFileExtension() % '|' % i18nc("Associated with the file extension : for example, .csv --> CSV document", "%1 document", KAboutData::applicationData().displayName()),
0318                            SKGMainPanel::getMainPanel());
0319         if (fileName.isEmpty()) {
0320             return;
0321         }
0322 
0323         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0324         err = m_currentDocument->saveAs(fileName, true);
0325         QApplication::restoreOverrideCursor();
0326 
0327         // Refresh
0328         SKGMainPanel::getMainPanel()->refresh();
0329 
0330         // status bar
0331         IFOK(err) {
0332             err = SKGError(0, i18nc("Successfully saved a file", "File '%1' saved.", fileName));
0333             // Add in recentFiles
0334             if (m_recentFiles != nullptr) {
0335                 m_recentFiles->addUrl(QUrl::fromLocalFile(fileName));
0336                 m_recentFiles->saveEntries(KConfigGroup(KSharedConfig::openConfig(), "RecentFiles"));
0337             }
0338             // Set as last open file in kcfg
0339             KSharedConfigPtr config = KSharedConfig::openConfig();
0340             KConfigGroup pref = config->group("File");
0341             pref.writePathEntry("lastfilepath", fileName);
0342 
0343         } else {
0344             err.addError(ERR_FAIL, i18nc("Error message: Could not save a file",  "Failed to save '%1'.", fileName));
0345         }
0346 
0347         // Display error
0348         SKGMainPanel::displayErrorMessage(err);
0349     }
0350 }
0351 
0352 void SKGFilePlugin::onReOpen()
0353 {
0354     auto* act = qobject_cast< QAction* >(sender());
0355     if (act != nullptr) {
0356         QString filename = act->data().toString();
0357         QFile(SKGDocument::getTemporaryFile(filename)).remove();
0358         onOpen(QUrl::fromLocalFile(filename));
0359     }
0360 }
0361 
0362 void SKGFilePlugin::onOpen(const QUrl& iUrl)
0363 {
0364     SKGError err;
0365     SKGTRACEINFUNCRC(10, err)
0366     if ((SKGMainPanel::getMainPanel() != nullptr) && (m_currentDocument != nullptr) && SKGMainPanel::getMainPanel()->queryFileClose()) {
0367         bool useKWallet = skgfile_settings::storeInKdeWallet();
0368         QString pwd;
0369         QString programName = KAboutData::applicationData().displayName();
0370         QString fileName = iUrl.toLocalFile();
0371         if (fileName.isEmpty()) {
0372             auto* act = qobject_cast< QAction* >(sender());
0373             if (act != nullptr) {
0374                 fileName = act->property("filename").toString();
0375             }
0376         }
0377         if (fileName.isEmpty()) {
0378             fileName = QFileDialog::getOpenFileUrl(SKGMainPanel::getMainPanel(), i18nc("Panel title", "Open file"),
0379                                                    QUrl(),
0380                                                    i18nc("File format for open dialog panel", "%1 document", programName) % "(*." % m_currentDocument->getFileExtension() % ")").toLocalFile();
0381         }
0382         if (!fileName.isEmpty()) {
0383             // Check if temporary file exists
0384             bool restoreTmpFile = false;
0385             QString tmpFile = SKGDocument::getTemporaryFile(fileName);
0386             if (QFile(tmpFile).exists()) {
0387                 KMessageWidget* msg = SKGMainPanel::getMainPanel()->displayMessage(i18nc("Warning message", "Your document has been restored from its temporary file. You can decide to reopen the original document."), SKGDocument::Warning);
0388                 auto reopen = new QAction(i18nc("Noun", "Reopen"), msg);
0389                 reopen->setIcon(SKGServices::fromTheme(QStringLiteral("quickopen")));
0390                 reopen->setData(fileName);
0391                 msg->addAction(reopen);
0392                 connect(reopen, &QAction::triggered, this, &SKGFilePlugin::onReOpen);
0393                 connect(reopen, &QAction::triggered, msg, &KMessageWidget::deleteLater, Qt::QueuedConnection);
0394 
0395                 restoreTmpFile = true;
0396             }
0397 
0398             // Open
0399             QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0400             SKGMainPanel::getMainPanel()->closeAllPages(true);
0401             err = m_currentDocument->load(fileName, QLatin1String(""), restoreTmpFile);
0402             QApplication::restoreOverrideCursor();
0403 
0404             if (err && err.getReturnCode() == ERR_ENCRYPTION) {
0405                 m_currentDocument->close();
0406 
0407                 // Open failed
0408                 // Password must be asked
0409                 QString additionalMessage;
0410                 do {
0411                     // Reset error
0412                     err = SKGError(0, QLatin1String(""));
0413                     pwd = QLatin1String("");
0414 
0415                     // Get password
0416                     if (useKWallet) {
0417                         SKGTRACEL(10) << "Use KWallet" << SKGENDL;
0418                         // Use KWallet
0419                         QString walletName = skgfile_settings::selectedWallet();
0420                         if (!KWallet::Wallet::walletList().contains(walletName)) {
0421                             walletName = KWallet::Wallet::walletList().value(SKGServices::stringToInt(skgfile_settings::selectedWallet()));
0422                             if (walletName.isEmpty()) {
0423                                 walletName = QStringLiteral("kdewallet");
0424                             }
0425                         }
0426                         KWallet::Wallet* w = KWallet::Wallet::openWallet(walletName, SKGMainPanel::getMainPanel()->winId());
0427                         if (w != nullptr) {
0428                             // Change folder
0429                             if (!w->hasFolder(programName)) {
0430                                 w->createFolder(programName);
0431                             }
0432                             w->setFolder(programName);
0433 
0434                             // Read password
0435                             w->readPassword(fileName, pwd);
0436                             if (pwd.isEmpty()) {
0437                                 SKGTRACEL(10) << "Password not found in KWallet for " << fileName << SKGENDL;
0438                                 useKWallet = false;
0439                             }
0440 
0441                             delete w;
0442                             w = nullptr;
0443                         }
0444                     }
0445 
0446                     if (!useKWallet) {
0447                         SKGTRACEL(10) << "Ask password" << SKGENDL;
0448                         // Use password dialog
0449                         QPointer<KPasswordDialog> dlg = new KPasswordDialog(SKGMainPanel::getMainPanel());
0450                         dlg->setPrompt(additionalMessage % i18nc("Question", "This file seems to be protected.\nPlease enter the password."));
0451                         if (dlg->exec() == QDialog::Accepted) {
0452                             pwd = dlg->password();
0453                         }
0454                         delete dlg;
0455                     }
0456 
0457                     // Load file
0458                     if (!pwd.isEmpty()) {
0459                         QSplashScreen* splashScreen = SKGMainPanel::getMainPanel()->splashScreen();
0460                         if (splashScreen != nullptr) {
0461                             splashScreen->hide();
0462                         }
0463 
0464                         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0465                         err = m_currentDocument->load(fileName, pwd, restoreTmpFile);
0466                         IFKO(err) {
0467                             if (err.getReturnCode() == ERR_ENCRYPTION) {
0468                                 additionalMessage = i18nc("The user did not provide the correct password", "<b>Wrong password.</b>\n");
0469                                 useKWallet = false;
0470                             } else {
0471                                 // Load error
0472                                 QApplication::restoreOverrideCursor();
0473                                 break;
0474                             }
0475                         }
0476                         QApplication::restoreOverrideCursor();
0477 
0478                         if (splashScreen != nullptr) {
0479                             splashScreen->show();
0480                         }
0481                     }
0482                 } while (err);
0483             }
0484 
0485             IFOKDO(err, m_currentDocument->setLanguage(QLocale::languageToString(QLocale().language())))
0486 
0487             // status bar
0488             IFOK(err) {
0489                 err = SKGError(0, i18nc("Successfully opened a file", "File '%1' opened.", fileName));
0490                 // Add in recentFiles
0491                 if (m_recentFiles != nullptr) {
0492                     m_recentFiles->addUrl(QUrl::fromLocalFile(fileName));
0493                     m_recentFiles->saveEntries(KConfigGroup(KSharedConfig::openConfig(), "RecentFiles"));
0494                 }
0495                 // Set as last open file in kcfg
0496                 KSharedConfigPtr config = KSharedConfig::openConfig();
0497                 KConfigGroup pref = config->group("File");
0498                 pref.writePathEntry("lastfilepath", fileName);
0499 
0500                 // Store password if KDE wallet if needed
0501                 if (skgfile_settings::storeInKdeWallet() && !useKWallet) {
0502                     // Use KWallet
0503                     QString walletName = skgfile_settings::selectedWallet();
0504                     if (!KWallet::Wallet::walletList().contains(walletName)) {
0505                         walletName = KWallet::Wallet::walletList().value(SKGServices::stringToInt(skgfile_settings::selectedWallet()));
0506                         if (walletName.isEmpty()) {
0507                             walletName = QStringLiteral("kdewallet");
0508                         }
0509                     }
0510                     KWallet::Wallet* w = KWallet::Wallet::openWallet(walletName, SKGMainPanel::getMainPanel()->winId());
0511                     if (w != nullptr) {
0512                         // Change folder
0513                         w->setFolder(programName);
0514 
0515                         // Write password
0516                         w->writePassword(fileName, pwd);
0517 
0518                         delete w;
0519                         w = nullptr;
0520                     }
0521                 }
0522             } else {
0523                 this->onNew();
0524                 if (err.getReturnCode() != ERR_CORRUPTION) {
0525                     err.addError(ERR_FAIL, i18nc("Error message: Could not open a file",  "Failed to open '%1'.", fileName));
0526                 }
0527             }
0528 
0529             // Display error
0530             QAction* recovery = nullptr;
0531 #ifdef Q_OS_UNIX
0532             if (err.getReturnCode() == ERR_CORRUPTION) {
0533                 recovery = new QAction(i18nc("Noun", "Try a recovery"), this);
0534                 recovery->setIcon(SKGServices::fromTheme(QStringLiteral("games-solve")));
0535                 recovery->setData(SKGServices::stringsToCsv(QStringList() << fileName << pwd));
0536                 connect(recovery, &QAction::triggered, this, &SKGFilePlugin::onRecover);
0537             }
0538 #endif
0539             // Initialize preferences
0540             int index = 0;
0541             while (index >= 0) {
0542                 SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByIndex(index);
0543                 if (plugin != nullptr) {
0544                     plugin->initPreferences();
0545                 } else {
0546                     index = -2;
0547                 }
0548                 ++index;
0549             }
0550 
0551             SKGMainPanel::displayErrorMessage(err, recovery);
0552         }
0553     }
0554 }
0555 
0556 void SKGFilePlugin::onRecover()
0557 {
0558     SKGError err;
0559     SKGTRACEINFUNCRC(10, err)
0560     auto* act = qobject_cast< QAction* >(sender());
0561     if ((act != nullptr) && (m_currentDocument != nullptr) && (SKGMainPanel::getMainPanel() != nullptr)) {
0562         QStringList params = SKGServices::splitCSVLine(act->data().toString());
0563         QString recoveredFileName;
0564         err = m_currentDocument->recover(params.at(0), params.at(1), recoveredFileName);
0565 
0566         IFOK(err) {
0567             // Display recovery message
0568             KMessageWidget* msg = SKGMainPanel::getMainPanel()->displayMessage(i18nc("Positive message", "Your document has been recovered here: %1\nTake care the recovery could be not perfect", recoveredFileName), SKGDocument::Positive);
0569             auto reopen = new QAction(i18nc("Noun", "Open the recovered file"), msg);
0570             reopen->setIcon(SKGServices::fromTheme(QStringLiteral("quickopen")));
0571             reopen->setData(recoveredFileName);
0572             msg->addAction(reopen);
0573             connect(reopen, &QAction::triggered, this, &SKGFilePlugin::onReOpen);
0574             connect(reopen, &QAction::triggered, msg, &KMessageWidget::deleteLater, Qt::QueuedConnection);
0575         } else {
0576             // Display error
0577             SKGMainPanel::displayErrorMessage(err);
0578         }
0579     }
0580 }
0581 
0582 void SKGFilePlugin::onChangePassword()
0583 {
0584     SKGError err;
0585     SKGTRACEINFUNCRC(10, err)
0586     if ((m_currentDocument != nullptr) && (SKGMainPanel::getMainPanel() != nullptr)) {
0587         QPointer<KNewPasswordDialog> dlg = new KNewPasswordDialog(SKGMainPanel::getMainPanel());
0588         dlg->setPrompt(i18n("Take care, if you lose your <b>password</b> then it will be <u><b>impossible</b></u> to open your document. Warning, this action can not be undone excepted by changing the password again."));
0589         if (dlg->exec() == 0) {
0590             err = SKGError(0, i18nc("Successfully changed the document password", "Changing password was canceled."));
0591         } else {
0592             QString newPassword = dlg->password();
0593             IFOKDO(err, m_currentDocument->changePassword(newPassword))
0594 
0595             // status
0596             IFOKDO(err, SKGError(0, i18nc("Successfully changed the document password", "Password changed.")))
0597             else {
0598                 err.addError(ERR_FAIL, i18nc("Error message: Could not change the document password",  "Failed to change password."));
0599             }
0600         }
0601         delete dlg;
0602 
0603         // Display error
0604         SKGMainPanel::displayErrorMessage(err);
0605     }
0606 }
0607 
0608 SKGAdviceList SKGFilePlugin::advice(const QStringList& iIgnoredAdvice)
0609 {
0610     SKGTRACEINFUNC(10)
0611     SKGAdviceList output;
0612 
0613     // Backup
0614     if (!iIgnoredAdvice.contains(QStringLiteral("skgfileplugin_notvalidated"))) {
0615         SKGAdvice ad;
0616         ad.setUUID(QStringLiteral("skgfileplugin_notvalidated"));
0617         ad.setPriority(2);
0618         ad.setShortMessage(i18nc("Advice to the user that he should backup his document", "Backup your document"));
0619         ad.setLongMessage(i18nc("Explain the user that he should backup his document", "Do not forget to backup your document on another device."));
0620         output.push_back(ad);
0621     }
0622 
0623     return output;
0624 }
0625 
0626 #include <skgfileplugin.moc>