File indexing completed on 2024-04-28 09:45:20
0001 //************************************************************************** 0002 // Copyright 2006 - 2022 Martin Koller, kollix@aon.at 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, version 2 of the License 0007 // 0008 //************************************************************************** 0009 #include <MainWindow.hxx> 0010 #include <Selector.hxx> 0011 #include <Archiver.hxx> 0012 #include <MainWidget.hxx> 0013 #include <SettingsDialog.hxx> 0014 0015 #include <QSplitter> 0016 #include <QSpinBox> 0017 #include <QToolTip> 0018 #include <QTimer> 0019 #include <QCursor> 0020 #include <QCheckBox> 0021 #include <QMenu> 0022 #include <QAction> 0023 #include <QUrl> 0024 #include <QApplication> 0025 #include <QFileDialog> 0026 #include <QHeaderView> 0027 0028 #include <KXMLGUIFactory> 0029 #include <KStandardAction> 0030 #include <KActionCollection> 0031 #include <KToggleAction> 0032 #include <KRecentFilesAction> 0033 #include <KMessageBox> 0034 #include <kio/global.h> 0035 #include <KStringHandler> 0036 #include <KStatusNotifierItem> 0037 #include <KSharedConfig> 0038 #include <KConfigGroup> 0039 #include <KShortcutsDialog> 0040 0041 //#include <iostream> 0042 //using namespace std; 0043 //-------------------------------------------------------------------------------- 0044 0045 MainWindow::MainWindow() 0046 { 0047 new Archiver(this); 0048 0049 quitAction = KStandardAction::quit(this, SLOT(maybeQuit()), actionCollection()); 0050 KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection()); 0051 0052 0053 QAction *action; 0054 0055 action = actionCollection()->addAction(QStringLiteral("newProfile"), this, SLOT(newProfile())); 0056 action->setText(i18n("New Profile")); 0057 action->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); 0058 0059 action = actionCollection()->addAction(QStringLiteral("loadProfile"), this, SLOT(loadProfile())); 0060 action->setText(i18n("Load Profile...")); 0061 action->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); 0062 0063 action = actionCollection()->addAction(QStringLiteral("saveProfile"), this, SLOT(saveProfile())); 0064 action->setText(i18n("Save Profile")); 0065 action->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); 0066 0067 action = actionCollection()->addAction(QStringLiteral("saveProfileAs"), this, SLOT(saveProfileAs())); 0068 action->setText(i18n("Save Profile As...")); 0069 action->setIcon(QIcon::fromTheme(QStringLiteral("document-save-as"))); 0070 0071 action = actionCollection()->addAction(QStringLiteral("profileSettings"), this, SLOT(profileSettings())); 0072 action->setText(i18n("Profile Settings...")); 0073 0074 action = actionCollection()->addAction(QStringLiteral("enableAllMessages"), this, SLOT(enableAllMessages())); 0075 action->setText(i18n("Enable All Messages")); 0076 0077 KToggleAction *docked = new KToggleAction(i18n("Dock in System Tray"), this); 0078 actionCollection()->addAction(QStringLiteral("dockInSysTray"), docked); 0079 connect(docked, &QAction::toggled, this, &MainWindow::dockInSysTray); 0080 0081 KToggleAction *showHidden = new KToggleAction(i18n("Show Hidden Files"), this); 0082 actionCollection()->addAction(QStringLiteral("showHiddenFiles"), showHidden); 0083 connect(showHidden, &QAction::toggled, this, &MainWindow::showHiddenFiles); 0084 0085 recentFiles = KStandardAction::openRecent(this, SLOT(recentProfileSelected(const QUrl &)), actionCollection()); 0086 recentFiles->setObjectName(QStringLiteral("recentProfiles")); 0087 recentFiles->loadEntries(KSharedConfig::openConfig()->group(QString())); 0088 0089 createGUI(); 0090 0091 splitter = new QSplitter(Qt::Horizontal, this); 0092 0093 selector = new Selector(splitter, actionCollection()); 0094 0095 mainWidget = new MainWidget(splitter); 0096 mainWidget->setSelector(selector); 0097 splitter->setCollapsible(splitter->indexOf(mainWidget), false); 0098 0099 setCentralWidget(splitter); 0100 0101 splitter->restoreState(KSharedConfig::openConfig()->group(QStringLiteral("geometry")).readEntry<QByteArray>("splitter", QByteArray())); 0102 selector->header()->restoreState(KSharedConfig::openConfig()->group(QStringLiteral("geometry")).readEntry<QByteArray>("tree", QByteArray())); 0103 0104 // save/restore window settings and size 0105 setAutoSaveSettings(); 0106 0107 connect(Archiver::instance, &Archiver::totalFilesChanged, this, &MainWindow::changeSystrayTip); 0108 connect(Archiver::instance, &Archiver::logging, this, &MainWindow::loggingSlot); 0109 connect(Archiver::instance, &Archiver::inProgress, this, &MainWindow::inProgress); 0110 0111 startBackupAction = actionCollection()->addAction(QStringLiteral("startBackup"), mainWidget, SLOT(startBackup())); 0112 startBackupAction->setIcon(QIcon::fromTheme(QStringLiteral("kbackup_start"))); 0113 startBackupAction->setText(i18n("Start Backup")); 0114 0115 cancelBackupAction = actionCollection()->addAction(QStringLiteral("cancelBackup"), Archiver::instance, SLOT(cancel())); 0116 cancelBackupAction->setText(i18n("Cancel Backup")); 0117 cancelBackupAction->setIcon(QIcon::fromTheme(QStringLiteral("kbackup_cancel"))); 0118 cancelBackupAction->setEnabled(false); 0119 0120 showHidden->setChecked(KSharedConfig::openConfig()->group(QStringLiteral("settings")).readEntry<bool>("showHiddenFiles", false)); 0121 showHiddenFiles(showHidden->isChecked()); 0122 docked->setChecked(KSharedConfig::openConfig()->group(QStringLiteral("settings")).readEntry<bool>("dockInSysTray", false)); 0123 dockInSysTray(docked->isChecked()); 0124 0125 // for convenience, open the tree at the HOME directory 0126 selector->openHomeDir(); 0127 0128 changeSystrayTip(); 0129 } 0130 0131 //-------------------------------------------------------------------------------- 0132 0133 void MainWindow::runBackup() 0134 { 0135 autorun = true; 0136 QTimer::singleShot(0, mainWidget, &MainWidget::startBackup); 0137 } 0138 0139 //-------------------------------------------------------------------------------- 0140 0141 bool MainWindow::stopAllowed() 0142 { 0143 if ( Archiver::instance->isInProgress() ) 0144 { 0145 if ( KMessageBox::warningTwoActions(this, 0146 i18n("There is a backup in progress. Do you want to abort it?"), i18n("Backup in Progress"), KGuiItem(i18n("Abort")), KStandardGuiItem::cancel()) == KMessageBox::SecondaryAction ) 0147 return false; 0148 0149 Archiver::instance->cancel(); 0150 } 0151 0152 KSharedConfig::openConfig()->group(QStringLiteral("geometry")).writeEntry("splitter", splitter->saveState()); 0153 KSharedConfig::openConfig()->group(QStringLiteral("geometry")).writeEntry("tree", selector->header()->saveState()); 0154 0155 return true; 0156 } 0157 0158 //-------------------------------------------------------------------------------- 0159 0160 void MainWindow::maybeQuit() 0161 { 0162 if ( stopAllowed() ) 0163 qApp->quit(); 0164 } 0165 0166 //-------------------------------------------------------------------------------- 0167 0168 bool MainWindow::queryClose() 0169 { 0170 if ( qApp->isSavingSession() || !sysTray ) 0171 return stopAllowed(); 0172 0173 hide(); 0174 return false; 0175 } 0176 0177 //-------------------------------------------------------------------------------- 0178 0179 void MainWindow::recentProfileSelected(const QUrl &url) 0180 { 0181 loadProfile(url.path()); 0182 } 0183 0184 //-------------------------------------------------------------------------------- 0185 0186 void MainWindow::loadProfile() 0187 { 0188 QString fileName = QFileDialog::getOpenFileName(this, i18n("Select Profile"), QString(), 0189 i18n("KBackup Profile (*.kbp)")); 0190 0191 if ( fileName.isEmpty() ) return; 0192 0193 loadProfile(fileName); 0194 } 0195 0196 //-------------------------------------------------------------------------------- 0197 0198 void MainWindow::loadProfile(const QString &fileName, bool adaptTreeWidth) 0199 { 0200 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0201 0202 QStringList includes, excludes; 0203 QString error; 0204 0205 if ( ! Archiver::instance->loadProfile(fileName, includes, excludes, error) ) 0206 { 0207 QApplication::restoreOverrideCursor(); 0208 0209 KMessageBox::error(this, 0210 i18n("Could not open profile '%1' for reading: %2", 0211 fileName, 0212 error), 0213 i18n("Open failed")); 0214 return; 0215 } 0216 0217 setLoadedProfile(fileName); 0218 0219 // now fill the Selector tree with those settings 0220 selector->setBackupList(includes, excludes); 0221 0222 mainWidget->getTargetLineEdit()->setText(Archiver::instance->getTarget().toDisplayString(QUrl::PreferLocalFile)); 0223 0224 if ( adaptTreeWidth ) 0225 selector->resizeColumnToContents(0); 0226 0227 QApplication::restoreOverrideCursor(); 0228 } 0229 0230 //-------------------------------------------------------------------------------- 0231 0232 void MainWindow::saveProfileAs() 0233 { 0234 QString fileName = QFileDialog::getSaveFileName(this, i18n("Select Profile"), QString(), 0235 i18n("KBackup Profile (*.kbp)")); 0236 0237 if ( fileName.isEmpty() ) return; 0238 0239 saveProfile(fileName); 0240 } 0241 0242 //-------------------------------------------------------------------------------- 0243 0244 void MainWindow::saveProfile(QString fileName) 0245 { 0246 if ( fileName.isEmpty() ) 0247 fileName = loadedProfile; 0248 0249 if ( fileName.isEmpty() ) 0250 { 0251 fileName = QFileDialog::getSaveFileName(this, i18n("Select Profile"), QString(), 0252 i18n("KBackup Profile (*.kbp)")); 0253 0254 if ( fileName.isEmpty() ) return; 0255 } 0256 0257 QFile file(fileName); 0258 0259 if ( file.exists() && (fileName != loadedProfile) ) 0260 { 0261 if ( KMessageBox::warningTwoActions(this, 0262 i18n("The profile '%1' does already exist.\n" 0263 "Do you want to overwrite it?", 0264 fileName), 0265 i18n("Profile exists"), KStandardGuiItem::save(), KStandardGuiItem::discard()) == KMessageBox::SecondaryAction ) 0266 return; 0267 } 0268 0269 QStringList includes, excludes; 0270 selector->getBackupList(includes, excludes); 0271 QString error; 0272 0273 Archiver::instance->setTarget(QUrl(mainWidget->getTargetLineEdit()->text())); 0274 0275 // when manually saving a profile, we need to restart the backup (incremental) cycle 0276 // since e.g. adding a new dir would otherwise not save its content on the next run 0277 Archiver::instance->resetBackupCycle(); 0278 0279 if ( ! Archiver::instance->saveProfile(fileName, includes, excludes, error) ) 0280 { 0281 KMessageBox::error(this, 0282 i18n("Could not open profile '%1' for writing: %2", 0283 fileName, 0284 error), 0285 i18n("Open failed")); 0286 return; 0287 } 0288 0289 setLoadedProfile(fileName); 0290 } 0291 0292 //-------------------------------------------------------------------------------- 0293 0294 void MainWindow::profileSettings() 0295 { 0296 SettingsDialog dialog(this); 0297 0298 dialog.ui.prefix->setText(Archiver::instance->getFilePrefix()); 0299 dialog.setMaxMB(Archiver::instance->getMaxSliceMBs()); 0300 dialog.ui.numBackups->setValue(Archiver::instance->getKeptBackups()); 0301 dialog.ui.mediaNeedsChange->setChecked(Archiver::instance->getMediaNeedsChange()); 0302 dialog.ui.compressFiles->setChecked(Archiver::instance->getCompressFiles()); 0303 dialog.ui.fullBackupInterval->setValue(Archiver::instance->getFullBackupInterval()); 0304 dialog.ui.filter->setText(Archiver::instance->getFilter()); 0305 dialog.ui.dirFilter->setPlainText(Archiver::instance->getDirFilter()); 0306 0307 if ( dialog.exec() == QDialog::Accepted ) 0308 { 0309 Archiver::instance->setFilePrefix(dialog.ui.prefix->text().trimmed()); 0310 Archiver::instance->setMaxSliceMBs(dialog.ui.maxSliceSize->value()); 0311 Archiver::instance->setKeptBackups(dialog.ui.numBackups->value()); 0312 Archiver::instance->setMediaNeedsChange(dialog.ui.mediaNeedsChange->isChecked()); 0313 Archiver::instance->setCompressFiles(dialog.ui.compressFiles->isChecked()); 0314 Archiver::instance->setFullBackupInterval(dialog.ui.fullBackupInterval->value()); 0315 Archiver::instance->setFilter(dialog.ui.filter->text()); 0316 Archiver::instance->setDirFilter(dialog.ui.dirFilter->toPlainText()); 0317 } 0318 } 0319 0320 //-------------------------------------------------------------------------------- 0321 0322 void MainWindow::newProfile() 0323 { 0324 Archiver::instance->setFilePrefix(QString()); // back to default 0325 Archiver::instance->setMaxSliceMBs(Archiver::UNLIMITED); 0326 Archiver::instance->setMediaNeedsChange(true); 0327 Archiver::instance->setTarget(QUrl()); 0328 Archiver::instance->setKeptBackups(Archiver::UNLIMITED); 0329 Archiver::instance->setFullBackupInterval(1); 0330 Archiver::instance->setFilter(QString()); 0331 Archiver::instance->setDirFilter(QString()); 0332 0333 // clear selection 0334 QStringList includes, excludes; 0335 selector->setBackupList(includes, excludes); 0336 0337 mainWidget->getTargetLineEdit()->setText(QString()); 0338 0339 setLoadedProfile(QString()); 0340 } 0341 0342 //-------------------------------------------------------------------------------- 0343 0344 void MainWindow::loggingSlot(const QString &message) 0345 { 0346 lastLog = message; 0347 changeSystrayTip(); 0348 } 0349 0350 //-------------------------------------------------------------------------------- 0351 0352 void MainWindow::changeSystrayTip() 0353 { 0354 if ( !sysTray ) 0355 return; 0356 0357 QString text = qApp->applicationDisplayName() + QLatin1String(" - ") + 0358 i18n("Files: %1 Size: %2 MB\n%3", 0359 Archiver::instance->getTotalFiles(), 0360 QString::number(Archiver::instance->getTotalBytes() / 1024.0 / 1024.0, 'f', 2), 0361 KStringHandler::csqueeze(lastLog, 60)); 0362 0363 sysTray->setToolTip(QStringLiteral("kbackup"), QStringLiteral("kbackup"), text); 0364 } 0365 0366 //-------------------------------------------------------------------------------- 0367 0368 void MainWindow::inProgress(bool runs) 0369 { 0370 if ( runs ) 0371 { 0372 if ( sysTray ) 0373 { 0374 /* 0375 QMovie *movie = KIconLoader::global()->loadMovie("kbackup_runs", KIconLoader::Panel); 0376 if ( movie ) 0377 { 0378 sysTray->setMovie(movie); 0379 movie->start(); 0380 } 0381 */ 0382 sysTray->setIconByName(QStringLiteral("kbackup_runs")); 0383 sysTray->setStatus(KStatusNotifierItem::Active); 0384 } 0385 0386 startBackupAction->setEnabled(false); 0387 cancelBackupAction->setEnabled(true); 0388 } 0389 else 0390 { 0391 if ( sysTray ) 0392 { 0393 /* 0394 if ( sysTray->movie() ) 0395 const_cast<QMovie*>(sysTray->movie())->stop(); // why does it return a const pointer ? :-( 0396 0397 sysTray->setIcon(sysTray->loadIcon("kbackup")); 0398 */ 0399 sysTray->setIconByName(QStringLiteral("kbackup")); 0400 sysTray->setStatus(KStatusNotifierItem::Passive); 0401 } 0402 0403 startBackupAction->setEnabled(true); 0404 cancelBackupAction->setEnabled(false); 0405 0406 if ( autorun ) 0407 qApp->quit(); 0408 } 0409 } 0410 0411 //-------------------------------------------------------------------------------- 0412 0413 void MainWindow::dockInSysTray(bool checked) 0414 { 0415 KSharedConfig::openConfig()->group(QStringLiteral("settings")).writeEntry("dockInSysTray", checked); 0416 KSharedConfig::openConfig()->group(QStringLiteral("settings")).sync(); 0417 0418 if ( checked ) 0419 { 0420 // system tray icon 0421 delete sysTray; 0422 sysTray = new KStatusNotifierItem(this); 0423 sysTray->setStandardActionsEnabled(false); 0424 0425 sysTray->contextMenu()->addAction(startBackupAction); 0426 sysTray->contextMenu()->addAction(cancelBackupAction); 0427 sysTray->contextMenu()->addAction(quitAction); 0428 0429 if ( Archiver::instance->isInProgress() ) 0430 { 0431 sysTray->setStatus(KStatusNotifierItem::Active); 0432 sysTray->setIconByName(QStringLiteral("kbackup_runs")); 0433 } 0434 else 0435 { 0436 sysTray->setStatus(KStatusNotifierItem::Passive); 0437 sysTray->setIconByName(QStringLiteral("kbackup")); 0438 } 0439 } 0440 else 0441 { 0442 delete sysTray; 0443 sysTray = nullptr; 0444 } 0445 } 0446 0447 //-------------------------------------------------------------------------------- 0448 0449 void MainWindow::showHiddenFiles(bool checked) 0450 { 0451 KSharedConfig::openConfig()->group(QStringLiteral("settings")).writeEntry("showHiddenFiles", checked); 0452 KSharedConfig::openConfig()->group(QStringLiteral("settings")).sync(); 0453 0454 selector->setShowHiddenFiles(checked); 0455 } 0456 0457 //-------------------------------------------------------------------------------- 0458 0459 void MainWindow::enableAllMessages() 0460 { 0461 KMessageBox::enableAllMessages(); 0462 } 0463 0464 //-------------------------------------------------------------------------------- 0465 0466 void MainWindow::setLoadedProfile(const QString &name) 0467 { 0468 loadedProfile = name; 0469 Archiver::instance->setLoadedProfile(name); 0470 setCaption(name); 0471 0472 if ( !name.isEmpty() ) 0473 { 0474 QUrl url; 0475 url.setPath(name); 0476 recentFiles->addUrl(url); 0477 recentFiles->saveEntries(KSharedConfig::openConfig()->group(QString())); 0478 KSharedConfig::openConfig()->group(QString()).sync(); 0479 } 0480 } 0481 0482 //-------------------------------------------------------------------------------- 0483 0484 #include "moc_MainWindow.cpp"