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