backupwidget.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. *openPilotLog - A FOSS Pilot Logbook Application
  3. *Copyright (C) 2020-2021 Felix Turowsky
  4. *
  5. *This program is free software: you can redistribute it and/or modify
  6. *it under the terms of the GNU General Public License as published by
  7. *the Free Software Foundation, either version 3 of the License, or
  8. *(at your option) any later version.
  9. *
  10. *This program is distributed in the hope that it will be useful,
  11. *but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. *GNU General Public License for more details.
  14. *
  15. *You should have received a copy of the GNU General Public License
  16. *along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. #include "backupwidget.h"
  19. #include "ui_backupwidget.h"
  20. #include "src/opl.h"
  21. #include "src/classes/astandardpaths.h"
  22. #include "src/functions/alog.h"
  23. #include "src/database/database.h"
  24. #include "src/functions/adatetime.h"
  25. #include "src/database/dbsummary.h"
  26. #include <QListView>
  27. #include <QStandardItemModel>
  28. #include <QFileIconProvider>
  29. #include <QMessageBox>
  30. #include <QFileDialog>
  31. BackupWidget::BackupWidget(QWidget *parent) :
  32. QWidget(parent),
  33. ui(new Ui::BackupWidget)
  34. {
  35. ui->setupUi(this);
  36. model = new QStandardItemModel(this);
  37. model->setHorizontalHeaderLabels(QStringList{tr("Backup File"),tr("Flights"), tr("Aircraft"),
  38. tr("Pilots"), tr("Last Flight"), tr("Total Time")});
  39. view = ui->tableView;
  40. refresh();
  41. }
  42. BackupWidget::~BackupWidget()
  43. {
  44. delete ui;
  45. }
  46. void BackupWidget::changeEvent(QEvent *event)
  47. {
  48. if (event != nullptr)
  49. if(event->type() == QEvent::LanguageChange)
  50. ui->retranslateUi(this);
  51. }
  52. void BackupWidget::refresh()
  53. {
  54. // First column in table, would be created by listing the files in backupdir
  55. QDir backup_dir = QDir(AStandardPaths::directory(AStandardPaths::Backup));
  56. const QStringList entries = backup_dir.entryList(QStringList{"*.db"}, QDir::Files, QDir::Time);
  57. QFileIconProvider provider;
  58. // Get summary of each db file and populate lists (columns) of data
  59. for (const auto &entry : entries) {
  60. QMap<OPL::DbSummaryKey, QString> summary = OPL::DbSummary::databaseSummary(backup_dir.absoluteFilePath(entry));
  61. model->appendRow({new AFileStandardItem(provider.icon(QFileIconProvider::File), entry, AStandardPaths::Backup),
  62. new QStandardItem(summary[OPL::DbSummaryKey::total_flights]),
  63. new QStandardItem(summary[OPL::DbSummaryKey::total_tails]),
  64. new QStandardItem(summary[OPL::DbSummaryKey::total_pilots]),
  65. new QStandardItem(summary[OPL::DbSummaryKey::last_flight]),
  66. new QStandardItem(summary[OPL::DbSummaryKey::total_time])
  67. });
  68. }
  69. view->setModel(model);
  70. view->resizeColumnsToContents();
  71. }
  72. const QString BackupWidget::absoluteBackupPath()
  73. {
  74. const QString backup_name = QLatin1String("logbook_backup_")
  75. + ADateTime::toString(QDateTime::currentDateTime(), OPL::DateTimeFormat::Backup)
  76. + QLatin1String(".db");
  77. return AStandardPaths::asChildOfDir(AStandardPaths::Backup, backup_name);
  78. }
  79. const QString BackupWidget::backupName()
  80. {
  81. return QLatin1String("logbook_backup_")
  82. + ADateTime::toString(QDateTime::currentDateTime(), OPL::DateTimeFormat::Backup)
  83. + QLatin1String(".db");
  84. }
  85. void BackupWidget::on_tableView_clicked(const QModelIndex &index)
  86. {
  87. selectedFileInfo = static_cast<AFileStandardItem*>(model->item(index.row(), 0));
  88. DEB << "Item at row:" << index.row() << "->" << selectedFileInfo->data(Qt::DisplayRole);
  89. }
  90. void BackupWidget::on_createLocalPushButton_clicked()
  91. {
  92. QString filename = absoluteBackupPath();
  93. DEB << filename;
  94. if(!DB->createBackup(filename)) {
  95. WARN(tr("Could not create local file: %1").arg(filename));
  96. return;
  97. } else {
  98. INFO(tr("Backup successfully created."));
  99. }
  100. QFileIconProvider provider;
  101. QMap<OPL::DbSummaryKey, QString> summary = OPL::DbSummary::databaseSummary(filename);
  102. model->insertRow(0, {new AFileStandardItem(provider.icon(QFileIconProvider::File), QFileInfo(filename)),
  103. new QStandardItem(summary[OPL::DbSummaryKey::total_flights]),
  104. new QStandardItem(summary[OPL::DbSummaryKey::total_tails]),
  105. new QStandardItem(summary[OPL::DbSummaryKey::total_pilots]),
  106. new QStandardItem(summary[OPL::DbSummaryKey::last_flight]),
  107. new QStandardItem(summary[OPL::DbSummaryKey::total_time])
  108. });
  109. }
  110. void BackupWidget::on_restoreLocalPushButton_clicked()
  111. {
  112. if(selectedFileInfo == nullptr) {
  113. INFO(tr("No backup selected"));
  114. return;
  115. }
  116. QString backup_name = AStandardPaths::asChildOfDir(
  117. AStandardPaths::Backup,
  118. selectedFileInfo->data(Qt::DisplayRole).toString()
  119. );
  120. QMessageBox confirm(this);
  121. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  122. confirm.setDefaultButton(QMessageBox::No);
  123. confirm.setIcon(QMessageBox::Warning);
  124. confirm.setWindowTitle(tr("Restoring Backup"));
  125. confirm.setText(tr("The following backup will be restored:<br><br><b><tt>"
  126. "%1</b></tt><br><br>"
  127. "This will replace your currently active database with the backup.<br>This action is irreversible.<br><br>Are you sure?"
  128. ).arg(OPL::DbSummary::summaryString(backup_name)));
  129. if (confirm.exec() == QMessageBox::No)
  130. return;
  131. if(!DB->restoreBackup(backup_name)) {
  132. WARN(tr("Unable to restore Backup file: %1").arg(backup_name));
  133. } else {
  134. INFO(tr("Backup successfully restored."));
  135. }
  136. view->clearSelection();
  137. selectedFileInfo = nullptr;
  138. }
  139. void BackupWidget::on_deleteSelectedPushButton_clicked()
  140. {
  141. if(selectedFileInfo == nullptr) {
  142. INFO(tr("No backup was selected"));
  143. return;
  144. }
  145. const QFileInfo& filename = selectedFileInfo->info();
  146. QFile file(filename.absoluteFilePath());
  147. if(!file.exists()) {
  148. WARN(tr("Selected backup file (<tt>%1</tt>) does not exist.").arg(filename.absolutePath()));
  149. return;
  150. }
  151. QMessageBox confirm(this);
  152. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  153. confirm.setDefaultButton(QMessageBox::No);
  154. confirm.setIcon(QMessageBox::Question);
  155. confirm.setWindowTitle(tr("Delete Backup"));
  156. confirm.setText(tr("The following backup will be deleted:<br><br><b><tt>"
  157. "%1</b></tt><br><br>"
  158. "Are you sure?"
  159. ).arg(filename.fileName()));
  160. if (confirm.exec() == QMessageBox::No)
  161. return;
  162. LOG << "Deleting backup:" << filename;
  163. if(!file.remove()) {
  164. WARN(tr("Unable to remove file %1\nError: %2").arg(filename.fileName(),file.errorString()));
  165. return;
  166. } else {
  167. INFO(tr("Backup successfully deleted."));
  168. }
  169. model->removeRow(selectedFileInfo->row());
  170. view->clearSelection();
  171. selectedFileInfo = nullptr;
  172. }
  173. void BackupWidget::on_createExternalPushButton_clicked()
  174. {
  175. QString filename = QFileDialog::getSaveFileName(
  176. this,
  177. tr("Choose destination file"),
  178. QDir::homePath() + QDir::separator() + backupName(),
  179. "*.db"
  180. );
  181. if(filename.isEmpty()) { // QFileDialog has been cancelled
  182. return;
  183. }
  184. if(!filename.endsWith(".db")) {
  185. filename.append(".db");
  186. }
  187. if(!DB->createBackup(filename)) {
  188. WARN(tr("Unable to backup file:").arg(filename));
  189. return;
  190. } else {
  191. INFO(tr("Backup successfully created."));
  192. }
  193. }
  194. void BackupWidget::on_restoreExternalPushButton_clicked()
  195. {
  196. QString filename = QFileDialog::getOpenFileName(
  197. this,
  198. tr("Choose backup file"),
  199. QDir::homePath(),
  200. "*.db"
  201. );
  202. if(filename.isEmpty()) { // QFileDialog has been cancelled
  203. return;
  204. }
  205. // Maybe create a Message Box asking for confirmation here and displaying the summary of backup and active DB
  206. QMessageBox confirm(this);
  207. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  208. confirm.setDefaultButton(QMessageBox::No);
  209. confirm.setIcon(QMessageBox::Question);
  210. confirm.setWindowTitle(tr("Import Database"));
  211. confirm.setText(tr("The following database will be imported:<br><br><b><tt>"
  212. "%1<br></b></tt>"
  213. "<br>Is this correct?"
  214. ).arg(OPL::DbSummary::summaryString(filename)));
  215. if (confirm.exec() == QMessageBox::Yes) {
  216. if(!DB->restoreBackup(filename)) {
  217. WARN(tr("Unable to import database file:").arg(filename));
  218. return;
  219. }
  220. INFO(tr("Database successfully imported."));
  221. }
  222. }
  223. void BackupWidget::on_aboutPushButton_clicked()
  224. {
  225. TODO << "Implement settings and automatic backups";
  226. QString text = tr(
  227. "<h3><center>About Backups</center></h3>"
  228. "<br>"
  229. "<p>By creating a backup, you create a copy of your logbook for safekeeping. This copy includes all your "
  230. "flights, pilots, aircraft and expiries. By creating a backup, you are creating a snapshot of your logbook to date. This backup can "
  231. "later be restored. OpenPilotLog offers two kinds of backups: Local and External Backups.<br><br>Local backups "
  232. "are automatically stored in a folder on this computer and will show up in the list below. They can easily be created by selecting <b>Create Local backup</b> and restored with "
  233. "<b>Restore Local Backup</b>.<br>"
  234. "When using <b>Create External Backup</b>, you will be asked where to save your backup file. This can be a pen drive, a cloud location or any other location of your choice. "
  235. "This functionality can also be used to sync your database across devices or to take it with you when you buy a new PC. You can then import your backup file by selecting "
  236. "it with <b>Restore external backup</b>.</p>"
  237. "<p>Frequent backups are recommended to guard against data loss or corruption. It is also recommended to keep a backup copy in a seperate location from your main "
  238. "computer to prevent data loss due to system failures.</p>"
  239. //todo "<p>By default, OpenPilotLog creates a weekly automatic backup. If you would like to change this behaviour, you can adjust it in the settings.</p>"
  240. "<br>"
  241. );
  242. QMessageBox msg_box(QMessageBox::Information, "About backups", text, QMessageBox::Ok, this);
  243. msg_box.exec();
  244. }