backupwidget.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. *openPilotLog - A FOSS Pilot Logbook Application
  3. *Copyright (C) 2020-2023 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/database/database.h"
  22. #include "src/functions/datetime.h"
  23. #include "src/database/dbsummary.h"
  24. #include "src/gui/dialogues/firstrundialog.h"
  25. #include "src/classes/settings.h"
  26. #include "src/classes/styleddatedelegate.h"
  27. #include <QListView>
  28. #include <QStandardItemModel>
  29. #include <QFileIconProvider>
  30. #include <QMessageBox>
  31. #include <QFileDialog>
  32. BackupWidget::BackupWidget(QWidget *parent) :
  33. QWidget(parent),
  34. ui(new Ui::BackupWidget)
  35. {
  36. ui->setupUi(this);
  37. model = new QStandardItemModel(this);
  38. model->setHorizontalHeaderLabels(QStringList{tr("Total Time"),tr("Flights"), tr("Aircraft"),
  39. tr("Pilots"), tr("Last Flight"), tr("Backup File")});
  40. view = ui->tableView;
  41. // julian day to Date Format
  42. const auto dateDelegate = new StyledDateDelegate(Settings::getDisplayFormat(), model);
  43. view->setItemDelegateForColumn(DATE_COLUMN, dateDelegate);
  44. refresh();
  45. }
  46. BackupWidget::~BackupWidget()
  47. {
  48. delete ui;
  49. }
  50. void BackupWidget::changeEvent(QEvent *event)
  51. {
  52. if (event != nullptr)
  53. if(event->type() == QEvent::LanguageChange)
  54. ui->retranslateUi(this);
  55. }
  56. void BackupWidget::refresh()
  57. {
  58. // First column in table, would be created by listing the files in backupdir
  59. QDir backup_dir = OPL::Paths::directory(OPL::Paths::Backup);
  60. const QStringList entries = backup_dir.entryList(QStringList{"*.db"}, QDir::Files, QDir::Time);
  61. QFileIconProvider provider;
  62. // Get summary of each db file and populate lists (columns) of data
  63. for (const auto &entry : entries) {
  64. QMap<OPL::DbSummaryKey, QString> summary = OPL::DbSummary::databaseSummary(backup_dir.absoluteFilePath(entry));
  65. model->appendRow({new QStandardItem(summary[OPL::DbSummaryKey::total_time]),
  66. new QStandardItem(summary[OPL::DbSummaryKey::total_flights]),
  67. new QStandardItem(summary[OPL::DbSummaryKey::total_tails]),
  68. new QStandardItem(summary[OPL::DbSummaryKey::total_pilots]),
  69. new QStandardItem(summary[OPL::DbSummaryKey::last_flight]),
  70. new QStandardItem(provider.icon(QFileIconProvider::File), entry),
  71. });
  72. }
  73. view->setModel(model);
  74. view->resizeColumnsToContents();
  75. }
  76. const QString BackupWidget::absoluteBackupPath()
  77. {
  78. const QString backup_name = backupName();
  79. return OPL::Paths::filePath(OPL::Paths::Backup, backup_name);
  80. }
  81. const QString BackupWidget::backupName()
  82. {
  83. auto owner = DB->getPilotEntry(1);
  84. return QStringLiteral("logbook_backup_%1_%2.db").arg(
  85. OPL::DateTime::dateTimeToString(QDateTime::currentDateTime(), OPL::DateTimeFormat_deprecated::Backup),
  86. owner.getLastName()
  87. );
  88. }
  89. void BackupWidget::on_tableView_clicked(const QModelIndex &index)
  90. {
  91. selectedRows.clear();
  92. selectedRows.append(index.row());
  93. }
  94. void BackupWidget::on_createLocalPushButton_clicked()
  95. {
  96. QString filename = absoluteBackupPath();
  97. DEB << filename;
  98. if(!DB->createBackup(QDir::toNativeSeparators(filename))) {
  99. WARN(tr("Could not create local file: %1").arg(filename));
  100. return;
  101. } else {
  102. INFO(tr("Backup successfully created."));
  103. }
  104. QFileInfo file_info(filename);
  105. QFileIconProvider provider;
  106. QMap<OPL::DbSummaryKey, QString> summary = OPL::DbSummary::databaseSummary(filename);
  107. model->insertRow(0, {new QStandardItem(summary[OPL::DbSummaryKey::total_time]),
  108. new QStandardItem(summary[OPL::DbSummaryKey::total_flights]),
  109. new QStandardItem(summary[OPL::DbSummaryKey::total_tails]),
  110. new QStandardItem(summary[OPL::DbSummaryKey::total_pilots]),
  111. new QStandardItem(summary[OPL::DbSummaryKey::last_flight]),
  112. new QStandardItem(provider.icon(QFileIconProvider::File), file_info.fileName()),
  113. });
  114. }
  115. void BackupWidget::on_restoreLocalPushButton_clicked()
  116. {
  117. if(selectedRows.isEmpty()) {
  118. INFO(tr("No backup selected"));
  119. return;
  120. }
  121. const QString file_name = model->item(selectedRows.first(), 5)->data(Qt::DisplayRole).toString();
  122. const QString backup_name = OPL::Paths::filePath(OPL::Paths::Backup, file_name);
  123. QMessageBox confirm(this);
  124. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  125. confirm.setDefaultButton(QMessageBox::No);
  126. confirm.setIcon(QMessageBox::Warning);
  127. confirm.setWindowTitle(tr("Restoring Backup"));
  128. confirm.setText(tr("The following backup will be restored:<br><br><b><tt>"
  129. "%1</b></tt><br><br>"
  130. "This will replace your currently active database with the backup.<br>This action is irreversible.<br><br>Are you sure?"
  131. ).arg(OPL::DbSummary::summaryString(backup_name)));
  132. if (confirm.exec() == QMessageBox::No)
  133. return;
  134. if(!DB->restoreBackup(QDir::toNativeSeparators(backup_name))) {
  135. WARN(tr("Unable to restore Backup file: %1").arg(backup_name));
  136. } else {
  137. INFO(tr("Backup successfully restored."));
  138. }
  139. view->clearSelection();
  140. selectedRows.clear();
  141. }
  142. void BackupWidget::on_deleteSelectedPushButton_clicked()
  143. {
  144. if(selectedRows.isEmpty()) {
  145. INFO(tr("No backup was selected"));
  146. return;
  147. }
  148. const QString file_name = model->item(selectedRows.first(), 5)->data(Qt::DisplayRole).toString();
  149. const QString backup_name = OPL::Paths::filePath(OPL::Paths::Backup, file_name);
  150. QFile file(OPL::Paths::filePath(OPL::Paths::Backup, file_name));
  151. if(!file.exists()) {
  152. WARN(tr("Selected backup file (<tt>%1</tt>) does not exist.").arg(file_name));
  153. return;
  154. }
  155. QMessageBox confirm(this);
  156. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  157. confirm.setDefaultButton(QMessageBox::No);
  158. confirm.setIcon(QMessageBox::Question);
  159. confirm.setWindowTitle(tr("Delete Backup"));
  160. confirm.setText(tr("The following backup will be deleted:<br><br><i>%1</i><br><br><b><tt>"
  161. "%2</b></tt><br><br>"
  162. "<b>This action is irreversible.</b><br><br>Continue?"
  163. ).arg(file_name, OPL::DbSummary::summaryString(backup_name)));
  164. if (confirm.exec() == QMessageBox::No)
  165. return;
  166. LOG << "Deleting backup:" << file_name;
  167. if(!file.remove()) {
  168. WARN(tr("Unable to remove file %1<br>Error: %2").arg(file_name,file.errorString()));
  169. return;
  170. } else {
  171. INFO(tr("Backup successfully deleted."));
  172. }
  173. model->removeRow(selectedRows.first());
  174. view->clearSelection();
  175. selectedRows.clear();
  176. }
  177. void BackupWidget::on_createExternalPushButton_clicked()
  178. {
  179. QString filename = QFileDialog::getSaveFileName(
  180. this,
  181. tr("Choose destination file"),
  182. QDir::homePath() + QDir::separator() + backupName(),
  183. "*.db"
  184. );
  185. if(filename.isEmpty()) { // QFileDialog has been cancelled
  186. return;
  187. }
  188. if(!filename.endsWith(".db")) {
  189. filename.append(".db");
  190. }
  191. if(!DB->createBackup(QDir::toNativeSeparators(filename))) {
  192. WARN(tr("Unable to backup file:").arg(filename));
  193. return;
  194. } else {
  195. INFO(tr("Backup successfully created."));
  196. }
  197. }
  198. void BackupWidget::on_restoreExternalPushButton_clicked()
  199. {
  200. QString filename = QFileDialog::getOpenFileName(
  201. this,
  202. tr("Choose backup file"),
  203. QDir::homePath(),
  204. "*.db"
  205. );
  206. if(filename.isEmpty()) { // QFileDialog has been cancelled
  207. return;
  208. }
  209. // Maybe create a Message Box asking for confirmation here and displaying the summary of backup and active DB
  210. QMessageBox confirm(this);
  211. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  212. confirm.setDefaultButton(QMessageBox::No);
  213. confirm.setIcon(QMessageBox::Question);
  214. confirm.setWindowTitle(tr("Import Database"));
  215. confirm.setText(tr("The following database will be imported:<br><br><b><tt>"
  216. "%1<br></b></tt>"
  217. "<br>Continue?"
  218. ).arg(OPL::DbSummary::summaryString(filename)));
  219. if (confirm.exec() == QMessageBox::Yes) {
  220. if(!DB->restoreBackup(QDir::toNativeSeparators(filename))) {
  221. WARN(tr("Unable to import database file:").arg(filename));
  222. return;
  223. }
  224. INFO(tr("Database successfully imported."));
  225. }
  226. }
  227. /*!
  228. * \brief BackupWidget::on_createNewLogbookPushButton_clicked Enables the user to reset the database
  229. */
  230. void BackupWidget::on_createNewLogbookPushButton_clicked()
  231. {
  232. QMessageBox confirm(this);
  233. confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  234. confirm.setDefaultButton(QMessageBox::No);
  235. confirm.setIcon(QMessageBox::Warning);
  236. confirm.setWindowTitle(tr("Start new Logbook"));
  237. confirm.setText(tr("By starting a new logbook, you reset and empty the database currently in use.<br><br>"
  238. "You will be asked if you want to keep a backup of your current database, but it is highly "
  239. "recommended to create an external backup before starting a new logbook.<br><br>"
  240. "Do you want to continue?"
  241. ));
  242. if (confirm.exec() == QMessageBox::Yes) {
  243. auto frd = new FirstRunDialog(this);
  244. if(!frd->exec()) {
  245. WARN(tr("Creating New Logbook has been unsuccessful or aborted."));
  246. }
  247. }
  248. }