source: src-qt4/life-preserver/lp-gui/LPMain.cpp @ 8b3a780

9.2-releasereleng/10.0releng/10.0.1
Last change on this file since 8b3a780 was 8b3a780, checked in by Ken Moore <ken@…>, 6 months ago

Clean up the LP waitbox, so that it no longer shows the "ok" button.

  • Property mode set to 100644
File size: 29.3 KB
Line 
1#include "LPMain.h"
2#include "ui_LPMain.h"
3#include <unistd.h>
4
5LPMain::LPMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::LPMain){
6  ui->setupUi(this); //load the Qt-designer UI file
7  //Initialize the waitbox pointer
8  waitBox = 0;
9  //Create the basic/advanced view options
10  viewBasic = new QRadioButton(tr("Basic"), ui->menuView);
11        QWidgetAction *WABasic = new QWidgetAction(this); WABasic->setDefaultWidget(viewBasic);
12        ui->menuView->addAction(WABasic);
13  viewAdvanced = new QRadioButton(tr("Advanced"), ui->menuView);
14        QWidgetAction *WAAdv = new QWidgetAction(this); WAAdv->setDefaultWidget(viewAdvanced);
15        ui->menuView->addAction(WAAdv);
16  connect(viewBasic, SIGNAL(toggled(bool)), this, SLOT(viewChanged()) );
17  //Now set the default view type
18  viewBasic->setChecked(true); //will automatically call the "viewChanged" function
19  //Create the filesystem model and tie it to the treewidget
20  fsModel = new QFileSystemModel(this);
21        fsModel->setReadOnly(true);
22        ui->treeView->setModel(fsModel);
23  //Connect the UI to all the functions
24  connect(ui->tool_refresh, SIGNAL(clicked()), this, SLOT(updatePoolList()) );
25  connect(ui->combo_pools, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTabs()) );
26  connect(ui->combo_datasets, SIGNAL(currentIndexChanged(int)), this, SLOT(updateDataset()) );
27  connect(ui->slider_snapshots, SIGNAL(valueChanged(int)), this, SLOT(updateSnapshot()) );
28  connect(ui->push_prevsnap, SIGNAL(clicked()), this, SLOT(prevSnapshot()) );
29  connect(ui->push_nextsnap, SIGNAL(clicked()), this, SLOT(nextSnapshot()) );
30  connect(ui->check_hidden, SIGNAL(stateChanged(int)), this, SLOT(setFileVisibility()) );
31  connect(ui->push_restore, SIGNAL(clicked()), this, SLOT(restoreFiles()) );
32  connect(ui->push_configure, SIGNAL(clicked()), this, SLOT(openConfigGUI()) );
33  //Connect the Menu buttons
34  connect(ui->menuManage_Pool, SIGNAL(triggered(QAction*)), this, SLOT(menuAddPool(QAction*)) );
35  connect(ui->menuUnmanage_Pool, SIGNAL(triggered(QAction*)), this, SLOT(menuRemovePool(QAction*)) );
36  connect(ui->action_SaveKeyToUSB, SIGNAL(triggered()), this, SLOT(menuSaveSSHKey()) );
37  connect(ui->actionClose_Window, SIGNAL(triggered()), this, SLOT(menuCloseWindow()) );
38  connect(ui->menuCompress_Home_Dir, SIGNAL(triggered(QAction*)), this, SLOT(menuCompressHomeDir(QAction*)) );
39  connect(ui->actionExtract_Home_Dir, SIGNAL(triggered()), this, SLOT(menuExtractHomeDir()) );
40  connect(ui->actionAdd_Disk, SIGNAL(triggered()), this, SLOT(menuAddDisk()) );
41  connect(ui->menuRemove_Disk, SIGNAL(triggered(QAction*)), this, SLOT(menuRemoveDisk(QAction*)) );
42  connect(ui->menuSet_Disk_Offline, SIGNAL(triggered(QAction*)), this, SLOT(menuOfflineDisk(QAction*)) );
43  connect(ui->menuSet_Disk_Online, SIGNAL(triggered(QAction*)), this, SLOT(menuOnlineDisk(QAction*)) );
44  connect(ui->action_startScrub, SIGNAL(triggered()), this, SLOT(menuStartScrub()) );
45  connect(ui->action_stopScrub, SIGNAL(triggered()), this, SLOT(menuStopScrub()) );
46  connect(ui->action_newSnapshot, SIGNAL(triggered()), this, SLOT(menuNewSnapshot()) );
47  connect(ui->menuDelete_Snapshot, SIGNAL(triggered(QAction*)), this, SLOT(menuRemoveSnapshot(QAction*)) );
48  //Update the interface
49  QTimer::singleShot(0,this,SLOT(updatePoolList()) );
50 
51  //Make sure the status tab is shown initially
52  ui->tabWidget->setCurrentWidget(ui->tab_status);
53}
54
55LPMain::~LPMain(){
56       
57}
58
59// ==============
60//      PUBLIC SLOTS
61// ==============
62void LPMain::slotSingleInstance(){
63  this->raise();
64  this->show();
65}
66
67// ==============
68//          PRIVATE
69// ==============
70void LPMain::showErrorDialog(QString title, QString message, QString errors){
71  QMessageBox MB(QMessageBox::Warning, title, message, QMessageBox::Ok, this);
72    MB.setDetailedText(errors);
73    MB.exec();
74}
75
76void LPMain::showWaitBox(QString message){
77  if(waitBox == 0){
78    qDebug() << "New Wait Box";
79    waitBox = new QMessageBox(QMessageBox::NoIcon, tr("Please Wait"), message, QMessageBox::NoButton, this);
80    waitBox->setStandardButtons(QMessageBox::NoButton);
81    waitBox->setWindowModality(Qt::WindowModal);
82  }else{
83    qDebug() << "Update Wait Box:" << message;
84    try{
85      waitBox->setText(message);
86    }catch(...){
87      waitBox = 0; //reset flag if necessary
88      showWaitBox(message);
89      return;
90    }
91  }
92  if(!waitBox->isVisible()){ waitBox->show(); waitBox->raise(); }
93  QCoreApplication::processEvents();
94}
95
96void LPMain::hideWaitBox(){
97  if(waitBox != 0){
98    if(waitBox->isVisible()){ waitBox->hide(); }
99  }
100       
101}
102
103// ==============
104//     PRIVATE SLOTS
105// ==============
106void LPMain::updatePoolList(){
107  //Get the currently selected pool (if there is one)
108  qDebug() << "Update Pool List";
109  QString cPool;
110  if(ui->combo_pools->currentIndex() != -1){ cPool = ui->combo_pools->currentText(); }
111  //Get the list of managed pools
112  qDebug() << "[DEBUG] Fetching list of pools";
113  QStringList pools = LPBackend::listDatasets();
114  QStringList poolsAvail = LPBackend::listPossibleDatasets();
115  //Now put the lists into the UI
116  ui->combo_pools->clear();
117  if(!pools.isEmpty()){ ui->combo_pools->addItems(pools); }
118  //Now set the currently selected pools
119  qDebug() << "[DEBUG] Pool list:" << pools;
120  if(pools.length() > 0){
121    poolSelected=true;   
122    int index = pools.indexOf(cPool);
123    if(index < 0){ ui->combo_pools->setCurrentIndex(0); }
124    else{ ui->combo_pools->setCurrentIndex(index); }
125  }else{
126    //No managed pools
127    poolSelected=false;
128    ui->combo_pools->addItem("No Managed Pools!");
129    ui->combo_pools->setCurrentIndex(0);
130  }
131  qDebug() << "[DEBUG] Update pool menu options";
132  //Now update the add/remove pool menu's
133  ui->menuManage_Pool->clear();
134  for( int i=0; i<poolsAvail.length(); i++){
135    if(pools.contains(poolsAvail[i])){ continue; } //already managed
136    ui->menuManage_Pool->addAction(poolsAvail[i]);
137  }
138  ui->menuManage_Pool->setEnabled( !ui->menuManage_Pool->isEmpty() );
139  ui->menuUnmanage_Pool->clear();
140  for( int i=0; i<pools.length(); i++){
141    ui->menuUnmanage_Pool->addAction(pools[i]);
142  }
143  ui->menuUnmanage_Pool->setEnabled( !ui->menuUnmanage_Pool->isEmpty() );
144  qDebug() << "[DEBUG] Update user menus";
145  //Now update the user's that are available for home-dir packaging
146  QDir hdir("/usr/home");
147  QStringList users = hdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
148  ui->menuCompress_Home_Dir->clear();
149  for(int i=0; i<users.length(); i++){
150    ui->menuCompress_Home_Dir->addAction(users[i]);
151  }
152  //Now update the interface appropriately
153  ui->combo_pools->setEnabled(poolSelected);
154  qDebug() << "[DEBUG] Finished updatePoolList()";
155  updateTabs();
156}
157
158void LPMain::viewChanged(){
159  ui->menuView->hide();
160  ui->menubar->clear();
161  if(viewBasic->isChecked()){
162    ui->menubar->addMenu(ui->menuFile);
163    ui->menubar->addMenu(ui->menuView);
164    ui->menubar->addMenu(ui->menuClassic_Backups);
165  }else{
166    ui->menubar->addMenu(ui->menuFile);
167    ui->menubar->addMenu(ui->menuView);
168    ui->menubar->addMenu(ui->menuClassic_Backups);
169    ui->menubar->addMenu(ui->menuSnapshots);
170    ui->menubar->addMenu(ui->menuDisks);
171  }
172}
173
174void LPMain::updateTabs(){
175  //qDebug() << "Update Tabs" << poolSelected;
176  qDebug() << "[DEBUG] start updateTabs():" << poolSelected;
177  viewChanged();
178  ui->tabWidget->setEnabled(poolSelected);
179  ui->menuView->setEnabled(poolSelected);       
180  ui->menuDisks->setEnabled(poolSelected); 
181  ui->menuSnapshots->setEnabled(poolSelected);
182  ui->push_configure->setVisible(poolSelected);
183  ui->action_SaveKeyToUSB->setEnabled(poolSelected);
184  if(poolSelected){
185    showWaitBox(tr("Loading zpool information"));
186    qDebug() << "[DEBUG] loadPoolData:" << ui->combo_pools->currentText();
187    POOLDATA = LPGUtils::loadPoolData(ui->combo_pools->currentText());
188    qDebug() << "[DEBUG] loaded data";
189    hideWaitBox();
190    //Now list the status information
191    ui->label_status->setText(POOLDATA.poolStatus);
192    ui->label_numdisks->setText( QString::number(POOLDATA.harddisks.length()) );
193    ui->label_latestsnapshot->setText(POOLDATA.latestSnapshot);
194    if(POOLDATA.finishedStatus.isEmpty()){ ui->label_finishedstat->setVisible(false); }
195    else{
196      ui->label_finishedstat->setText(POOLDATA.finishedStatus);
197      ui->label_finishedstat->setVisible(true);
198    }
199    if(POOLDATA.runningStatus.isEmpty()){ ui->label_runningstat->setVisible(false); }
200    else{
201      ui->label_runningstat->setText(POOLDATA.runningStatus);
202      ui->label_runningstat->setVisible(true);
203    }       
204    if(POOLDATA.errorStatus.isEmpty()){ ui->label_errorstat->setVisible(false); }
205    else{
206      ui->label_errorstat->setText(POOLDATA.errorStatus);
207      ui->label_errorstat->setVisible(true);
208    }       
209    //Now list the data restore options
210    QString cds = ui->combo_datasets->currentText();
211    ui->combo_datasets->clear();
212    QStringList dslist = POOLDATA.subsets();
213    ui->combo_datasets->addItems(dslist);
214    int dsin = dslist.indexOf(cds);
215    if(dsin >= 0){ ui->combo_datasets->setCurrentIndex(dsin); }
216    else if( !dslist.isEmpty() ){ ui->combo_datasets->setCurrentIndex(0); }
217    else{ ui->combo_datasets->addItem(tr("No datasets available")); }
218    //NOTE: this automatically calls the "updateDataset()" function in a new thread
219   
220    //Now update the snapshot removal menu list
221    QStringList snaps = LPBackend::listLPSnapshots(ui->combo_pools->currentText());
222    ui->menuDelete_Snapshot->clear();
223    for(int i=0; i<snaps.length(); i++){
224       ui->menuDelete_Snapshot->addAction(snaps[i]);
225    }
226    ui->menuDelete_Snapshot->setEnabled( !ui->menuDelete_Snapshot->isEmpty() );
227    //Now update the disk menu items
228    ui->menuRemove_Disk->clear();
229    ui->menuSet_Disk_Offline->clear();
230    ui->menuSet_Disk_Online->clear();
231    for(int i=0; i<POOLDATA.harddisks.length(); i++){
232      ui->menuRemove_Disk->addAction(POOLDATA.harddisks[i]);
233      if(POOLDATA.harddiskStatus[i] == "OFFLINE"){
234        ui->menuSet_Disk_Online->addAction(POOLDATA.harddisks[i]);
235      }else{
236        ui->menuSet_Disk_Offline->addAction(POOLDATA.harddisks[i]);     
237      }
238    }
239    ui->menuRemove_Disk->setEnabled(!ui->menuRemove_Disk->isEmpty());
240    ui->menuSet_Disk_Offline->setEnabled(!ui->menuSet_Disk_Offline->isEmpty());
241    ui->menuSet_Disk_Online->setEnabled(!ui->menuSet_Disk_Online->isEmpty());
242  }else{
243    //No Pool selected
244    ui->label_numdisks->clear();
245    ui->label_latestsnapshot->clear();
246    ui->label_status->clear();
247          ui->label_errorstat->setVisible(false);
248          ui->label_runningstat->setVisible(false);
249          ui->label_finishedstat->setVisible(false);
250  }
251
252}
253
254void LPMain::updateDataset(){
255  //Update the snapshots for the currently selected dataset
256  QString cds = ui->combo_datasets->currentText();
257  if(POOLDATA.subsets().indexOf(cds) >= 0){
258    QStringList snaps = POOLDATA.snapshots(cds);
259      qDebug() << "Update Dataset";
260      ui->slider_snapshots->setEnabled(true);
261      ui->slider_snapshots->setMinimum(0);
262      int max = snaps.length() -1;
263      if(max < 0){ max = 0; ui->slider_snapshots->setEnabled(false); }
264      ui->slider_snapshots->setMaximum(max);
265      ui->slider_snapshots->setValue(max); //most recent snapshot
266      updateSnapshot();
267  }else{
268    ui->slider_snapshots->setEnabled(false);
269    ui->label_snapshot->clear();
270    ui->push_nextsnap->setEnabled(false);
271    ui->push_prevsnap->setEnabled(false);
272  }
273       
274}
275
276void LPMain::updateSnapshot(){
277  int sval = ui->slider_snapshots->value();
278  QStringList snaps = POOLDATA.snapshots(ui->combo_datasets->currentText());
279  //qDebug() << "Update Snapshot";
280  //Update the previous/next buttons
281  if(sval == ui->slider_snapshots->minimum() ){ ui->push_prevsnap->setEnabled(false); }
282  else{ ui->push_prevsnap->setEnabled(true); }
283  if(sval == ui->slider_snapshots->maximum() ){ ui->push_nextsnap->setEnabled(false); }
284  else{ ui->push_nextsnap->setEnabled(true); }
285  //Now update the snapshot viewer
286  if(snaps.isEmpty()){ ui->label_snapshot->clear(); ui->slider_snapshots->setEnabled(false); }
287  else{
288    QString snap = snaps.at(sval);
289    QString path = ui->combo_datasets->currentText() + "/.zfs/snapshot/"+snap;
290    //qDebug() << "Snapshot path:" << path;
291    ui->label_snapshot->setText(snap);
292    //Now update the snapshot view
293    ui->treeView->setRootIndex( fsModel->setRootPath(path) );
294   
295  }
296}
297
298void LPMain::nextSnapshot(){
299  ui->slider_snapshots->setValue( ui->slider_snapshots->value()+1 );
300}
301
302void LPMain::prevSnapshot(){
303  ui->slider_snapshots->setValue( ui->slider_snapshots->value()-1 );
304}
305
306void LPMain::setFileVisibility(){
307  if(ui->check_hidden->isChecked()){
308    fsModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden );
309  }else{
310    fsModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot );
311  }
312}
313
314void LPMain::restoreFiles(){
315  QString filePath = fsModel->filePath( ui->treeView->currentIndex() );
316  qDebug() << " Restore file(s):" << filePath;
317  QString destDir = filePath.remove("/.zfs/snapshot/"+ui->label_snapshot->text());
318        destDir.chop( filePath.section("/",-1).size()+1 ); //get rid of the filename at the end
319        while(!QFile::exists(destDir)){ destDir.chop( destDir.section("/",-1).size() +1); }
320  QString newFilePath = destDir+"/"+LPGUtils::generateReversionFileName(filePath, destDir);
321  //qDebug() << "Destination:" << newFilePath;
322  //Perform the reversion(s)
323  QStringList errors;
324  if(QFileInfo(filePath).isDir()){
325    //Is a directory
326    showWaitBox( QString(tr("Restoring Directory: %1")).arg(newFilePath) );
327    errors = LPGUtils::revertDir(filePath, newFilePath);
328    hideWaitBox();
329    if(!errors.isEmpty()){
330      qDebug() << "Failed Reversions:" << errors;
331      errors.prepend(tr("File destination(s) that could not be restored:")+"\n");
332      showErrorDialog(tr("Reversion Error"), tr("Some files could not be restored from the snapshot."), errors.join("\n") );
333    }else{
334      qDebug() << "Reversion successful";           
335      QMessageBox::information(this,tr("Restore Successful"),QString(tr("The following directory was succesfully restored: %1")).arg(newFilePath) );
336    }
337  }else{
338    //Just a single file
339    showWaitBox( QString(tr("Restoring file: %1")).arg(newFilePath) );
340    bool ok = LPGUtils::revertFile(filePath, newFilePath);
341    hideWaitBox();
342    if( !ok ){
343      qDebug() << "Failed Reversion:" << newFilePath;
344      errors << QString(tr("Snapshot file: %1")).arg(filePath);
345      errors << QString(tr("Destination: %1")).arg(newFilePath);
346      errors << tr("Please check that the destination directory exists and is writable");
347      showErrorDialog(tr("Reversion Error"), tr("The file could not be restored from the snapshot."), errors.join("\n") );
348    }else{
349      qDebug() << "Reversion successful";
350      QMessageBox::information(this,tr("Restore Successful"),QString(tr("The following file was succesfully restored: %1")).arg(newFilePath) );
351    }
352  }       
353       
354}
355
356void LPMain::openConfigGUI(){
357  qDebug() << "Open Configuration UI";
358  QString ds = ui->combo_pools->currentText();
359  if(ds.isEmpty()){ return; }
360  LPConfig CFG(this);
361  CFG.loadDataset(ds, LPBackend::listReplicationTargets().contains(ds));
362  CFG.exec();
363  //Now check for return values and update appropriately
364  bool change = false;
365  if(CFG.localChanged){
366    ui->statusbar->showMessage(QString(tr("Configuring dataset: %1")).arg(ds),0);
367    LPBackend::setupDataset(ds, CFG.localSchedule, CFG.localSnapshots);
368    ui->statusbar->clearMessage();
369    change = true;
370  }
371  if(CFG.remoteChanged){
372    change = true;
373    if(CFG.isReplicated){
374      ui->statusbar->showMessage(QString(tr("Configuring replication: %1")).arg(ds),0);
375      LPBackend::setupReplication(ds, CFG.remoteHost, CFG.remoteUser, CFG.remotePort, CFG.remoteDataset, CFG.remoteFreq);
376      QMessageBox::information(this,tr("Reminder"),tr("Don't forget to save your SSH key to a USB stick so that you can restore your system from the remote host later!!"));
377    }else{
378      ui->statusbar->showMessage(QString(tr("Removing replication: %1")).arg(ds),0);
379      LPBackend::removeReplication(ds);
380    }
381    ui->statusbar->clearMessage();
382  }
383  //Now update the UI if appropriate
384  if(change){
385    updateTabs();
386  }     
387}
388
389// -----------------------------------------------
390//   MENU SLOTS
391// -----------------------------------------------
392// ==== File Menu ====
393void LPMain::menuAddPool(QAction *act){
394  QString dataset = act->text();
395  qDebug() << "Start Wizard for new managing pool:" << dataset;
396  LPWizard wiz(this);
397  wiz.setDataset(dataset);
398  wiz.exec();
399  //See if the wizard was cancelled or not
400  if(!wiz.cancelled){
401    ui->statusbar->showMessage(QString(tr("Enabling dataset management: %1")).arg(dataset),0);
402    //run the proper commands to get the dataset enabled
403    if( LPBackend::setupDataset(dataset, wiz.localTime, wiz.totalSnapshots) ){
404      if(wiz.enableReplication){
405         LPBackend::setupReplication(dataset, wiz.remoteHost, wiz.remoteUser, wiz.remotePort, wiz.remoteDataset, wiz.remoteTime);     
406         QMessageBox::information(this,tr("Reminder"),tr("Don't forget to save your SSH key to a USB stick so that you can restore your system from the remote host later!!"));
407      }
408    }
409    ui->statusbar->clearMessage();
410    //Now update the list of pools
411    updatePoolList();
412  }     
413}
414
415void LPMain::menuRemovePool(QAction *act){
416  QString ds = act->text();
417  qDebug() << "Remove Pool:" << ds;
418  if(!ds.isEmpty()){
419    //Verify the removal of the dataset
420    if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Dataset Backup Removal"),tr("Are you sure that you wish to cancel automated snapshots and/or replication of the following dataset?")+"\n\n"+ds,QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){           
421      //verify the removal of all the snapshots for this dataset
422      QStringList snaps = LPBackend::listLPSnapshots(ds);
423      if(!snaps.isEmpty()){
424        if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Snapshot Deletion"),tr("Do you wish to remove the local snapshots for this dataset?")+"\n"+tr("WARNING: This is a permanant change that cannot be reversed"),QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
425          //Remove all the snapshots
426          ui->statusbar->showMessage(QString(tr("%1: Removing snapshots")).arg(ds),0);
427          showWaitBox(tr("Removing snapshots"));
428          for(int i=0; i<snaps.length(); i++){
429            LPBackend::removeSnapshot(ds,snaps[i]);
430          }
431          ui->statusbar->clearMessage();
432        }
433      }
434      //Remove the dataset from life-preserver management
435      if(LPBackend::listReplicationTargets().contains(ds)){ 
436        ui->statusbar->showMessage(QString(tr("%1: Disabling Replication")).arg(ds),0);
437        showWaitBox(tr("Disabling Replication"));
438        LPBackend::removeReplication(ds); 
439        ui->statusbar->clearMessage();     
440      }
441      ui->statusbar->showMessage(QString(tr("%1: Disabling Life-Preserver Management")).arg(ds),0);
442      showWaitBox(tr("Removing Life Preserver Schedules"));
443      LPBackend::removeDataset(ds);
444      ui->statusbar->clearMessage();
445      updatePoolList();
446      hideWaitBox();
447    }
448  } //end check for empty ds
449
450}
451
452void LPMain::menuSaveSSHKey(){
453  QString ds = ui->combo_pools->currentText(); 
454  qDebug() << "Save SSH Key:" << ds;
455  if(ds.isEmpty()){ return; }
456  //Get the local hostname
457  char host[1023] = "\0";
458  gethostname(host,1023);
459  QString localHost = QString(host).simplified();
460  qDebug() << " - hostname:" << localHost;
461  //Scan for mounted USB devices
462  QStringList devs = LPBackend::findValidUSBDevices();
463  qDebug() << " - devs:" << devs;
464  if(devs.isEmpty()){
465    QMessageBox::warning(this,tr("No Valid USB Devices"), tr("No valid USB devices could be found. Please mount a FAT32 formatted USB stick and try again."));
466    return;
467  }
468  //Ask the user which one to save the file to
469  bool ok;
470  QString dev = QInputDialog::getItem(this, tr("Select USB Device"), tr("Available USB Devices:"), devs,0,false,&ok);   
471  if(!ok or dev.isEmpty()){ return; } //cancelled
472  QString devPath = dev.section("(",0,0).simplified();
473  //Now copy the file over
474  ok = LPBackend::copySSHKey(devPath, localHost);
475  if(ok){
476    QMessageBox::information(this,tr("Success"), tr("The public SSH key file was successfully copied onto the USB device."));
477  }else{
478    QMessageBox::information(this,tr("Failure"), tr("The public SSH key file could not be copied onto the USB device."));
479  }
480}
481
482void LPMain::menuCloseWindow(){
483  this->close();
484}
485
486// ==== Classic Backups Menu ====
487void LPMain::menuCompressHomeDir(QAction* act){
488  QString user = act->text();
489  qDebug() << "Compress Home Dir:" << user;
490  //Prompt for the package name
491  QString pkgName = user+"-"+QDateTime::currentDateTime().toString("yyyyMMdd-hhmm");
492  bool ok;
493  pkgName = QInputDialog::getText(this, tr("Package Name"), tr("Name of the package to create:"), QLineEdit::Normal, pkgName, &ok);
494  if(!ok || pkgName.isEmpty() ){ return; } //cancelled
495  //Now create the package
496  showWaitBox(tr("Packaging home directory"));
497  QString pkgPath = LPGUtils::packageHomeDir(user, pkgName);
498  hideWaitBox();
499  //Now inform the user of the result
500  if(pkgPath.isEmpty()){
501    qDebug() << "No Package created";
502    QMessageBox::warning(this,tr("Package Failure"), tr("The home directory package could not be created."));
503  }else{
504    qDebug() << "Package created at:" << pkgPath;
505    QMessageBox::information(this,tr("Package Success"), tr("The home directory package was successfully created.")+"\n\n"+pkgPath);
506  }       
507}
508
509void LPMain::menuExtractHomeDir(){
510  qDebug() << "Extract Home Dir";
511  //Get the file path from the user
512  QString filePath = QFileDialog::getOpenFileName(this,tr("Find Home Dir Package"), "/usr/home", tr("Home Dir Package (*.home.tar.gz)") );
513  if(filePath.isEmpty() || !QFile::exists(filePath)){ return; } //cancelled
514  //Now check if the user in the package is also on the system
515  QString username;
516  bool ok = LPGUtils::checkPackageUserPath(filePath, &username);
517  if(!ok){
518    QMessageBox::warning(this,tr("User Missing"),QString(tr("The user (%1) does not exist on this system. Please create this user first and then try again.")).arg(username) );
519    return;
520  }
521  //Now extract the package
522  showWaitBox(tr("Extracting Home Directory"));
523  ok = LPGUtils::extractHomeDirPackage(filePath);
524  hideWaitBox();
525  //Now report the results
526  if(ok){
527    QMessageBox::information(this,tr("Package Extracted"), QString(tr("The package was successfully extracted within %1")).arg("/usr/home/"+username) );
528  }else{
529    QMessageBox::warning(this, tr("Package Failure"), QString(tr("The package could not be extracted within %1")).arg("/usr/home/"+username) );
530  }
531 
532}
533
534// ==== Disks Menu ====
535void LPMain::menuAddDisk(){
536  QString pool = ui->combo_pools->currentText();
537  //Get the available disks and remove the current disks
538  QStringList adisks = LPGUtils::listAvailableHardDisks();
539  for(int i=0; i<POOLDATA.harddisks.length(); i++){
540    adisks.removeAll( POOLDATA.harddisks[i].section("s",0,0,QString::SectionSkipEmpty) );
541  }
542  if(adisks.isEmpty()){
543    QMessageBox::information(this,tr("Attach New Disk"), tr("No available disks could be found"));
544    return;
545  }
546  //Find a disk that can be added to the system
547  bool ok=false;
548  QString disk = QInputDialog::getItem(this, tr("Attach New Disk"),tr("Detected Disks:"), adisks,0,false, &ok);
549  if( !ok || disk.isEmpty() ){ return; }
550  qDebug() << "Add Disk:" << disk << pool;
551  showWaitBox(tr("Attaching disk"));
552  ok = LPBackend::attachDisk(pool, disk);
553  hideWaitBox();
554  if(ok){
555    QMessageBox::information(this,tr("Disk Attached"),QString(tr("Success: %1 was added to %2")).arg(disk,pool) );
556    QTimer::singleShot(0,this,SLOT(updateTabs()) );
557  }else{
558    QMessageBox::warning(this,tr("Disk Attach Error"),QString(tr("Failure: %1 could not be attached to %2.")).arg(disk,pool) );
559  }     
560}
561
562void LPMain::menuRemoveDisk(QAction *act){
563  QString disk = act->text();
564  QString pool = ui->combo_pools->currentText();
565  //Verify action
566  if(QMessageBox::Yes != QMessageBox::question(this,tr("Verify Disk Removal"),QString(tr("Are you sure that you want to remove %1 from %2?")).arg(disk,pool) + "\n\n" + tr("CAUTION: This disk can only be re-attached later as a brand new disk"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
567    return; //cancelled
568  }
569  qDebug() << "Remove Disk:" << disk << pool;
570  showWaitBox(tr("Detaching disk"));
571  bool ok = LPBackend::detachDisk(pool, disk);
572  hideWaitBox();
573  if(ok){
574    QMessageBox::information(this,tr("Disk Removal Success"),QString(tr("Success: %1 was removed from %2")).arg(disk, pool) );
575    QTimer::singleShot(0,this,SLOT(updateTabs()) );
576  }else{
577    QMessageBox::warning(this,tr("Disk Removal Failure"),QString(tr("Failure: %1 could not be removed from %2 at this time.")).arg(disk, pool) );
578  }
579}
580
581void LPMain::menuOfflineDisk(QAction *act){
582  QString disk = act->text();
583  QString pool = ui->combo_pools->currentText();
584  //Verify action
585  if(QMessageBox::Yes != QMessageBox::question(this,tr("Verify Disk Offline"),QString(tr("Are you sure you wish to set %1 offline?")).arg(disk), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
586    return; //cancelled
587  }
588  qDebug() << "Offline Disk:" << disk << pool;
589  showWaitBox(tr("Setting disk offline"));
590  bool ok = LPBackend::setDiskOffline(pool, disk);
591  hideWaitBox();
592  if(ok){
593    QMessageBox::information(this,tr("Disk Offline Success"),QString(tr("Success: %1 has been taken offline.")).arg(disk) );
594    QTimer::singleShot(0,this,SLOT(updateTabs()) );
595  }else{
596    QMessageBox::warning(this,tr("Disk Offline Failure"),QString(tr("Failure: %1 could not be taken offline at this time.")).arg(disk) );
597  }
598}
599
600void LPMain::menuOnlineDisk(QAction *act){
601  QString disk = act->text();
602  QString pool = ui->combo_pools->currentText();
603  //Verify action
604  if(QMessageBox::Yes != QMessageBox::question(this,tr("Verify Disk Online"),QString(tr("Are you sure you wish to set %1 online?")).arg(disk), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
605    return; //cancelled
606  }
607  qDebug() << "Online Disk:" << disk << pool;
608  showWaitBox(tr("Setting disk online"));
609  bool ok = LPBackend::setDiskOnline(pool, disk);
610  hideWaitBox();
611  if(ok){
612    QMessageBox::information(this,tr("Disk Online Success"),QString(tr("Success: %1 has been set online.")).arg(disk) );
613    QTimer::singleShot(0,this,SLOT(updateTabs()) );
614  }else{
615    QMessageBox::warning(this,tr("Disk Online Failure"),QString(tr("Failure: %1 could not be set online at this time.")).arg(disk) );
616  }
617}
618
619void LPMain::menuStartScrub(){
620  QString pool = ui->combo_pools->currentText();
621  //Verify starting a scrub
622  if( QMessageBox::Yes != QMessageBox::question(this,tr("Verify Scrub"),QString(tr("Are you sure you want to start a scrub on %1?")).arg(pool) + "\n"+tr("NOTE: This may take quite a while to complete"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
623    return; //cancelled   
624  }
625  qDebug() << "Start Scrub:" << pool;
626  QString cmd = "zpool scrub "+pool;
627  showWaitBox(tr("Trying to start a scrub"));
628  int ret = system(cmd.toUtf8());
629  hideWaitBox();
630  if(ret == 0){
631    //Now let te user know that one has been triggered
632    QMessageBox::information(this,tr("Scrub Started"),QString(tr("A scrub has just been started on %1")).arg(pool));
633    QTimer::singleShot(0,this,SLOT(updateTabs()) );
634  }else{
635    QMessageBox::warning(this,tr("Scrub Not Started"), QString(tr("A scrub on %1 could not be started at this time.")).arg(pool) + "\n"+tr("Please wait until any current resilvering or scrubs are finished before trying again.") );
636  }
637}
638
639void LPMain::menuStopScrub(){
640  QString pool = ui->combo_pools->currentText();
641  //Verify stopping a scrub
642  if( QMessageBox::Yes != QMessageBox::question(this,tr("Verify Scrub"),QString(tr("Are you sure you want to stop the scrub on %1?")).arg(pool), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
643    return; //cancelled   
644  }
645  qDebug() << "Stop Scrub:" << pool;
646  QString cmd = "zpool scrub -s "+pool;
647  showWaitBox(tr("Trying to stop scrub"));
648  int ret = system(cmd.toUtf8());
649  hideWaitBox();
650  if(ret == 0){
651    //Now let te user know that one has been triggered
652    QMessageBox::information(this,tr("Scrub Stopped"),QString(tr("The scrub on %1 has been stopped.")).arg(pool));
653    QTimer::singleShot(0,this,SLOT(updateTabs()) );
654  }else{
655    QMessageBox::warning(this,tr("Scrub Not Running"), QString(tr("There was no scrub running on %1.")).arg(pool) );
656  }     
657}
658
659// ==== Snapshots Menu ====
660void LPMain::menuNewSnapshot(){
661  qDebug() << "New Snapshot";
662  QString ds = ui->combo_pools->currentText();
663  if(ds.isEmpty()){return; }
664  //Get the new snapshot name from the user
665  bool ok;
666  QString name = QInputDialog::getText(this,tr("New Snapshot Name"), tr("Snapshot Name:"), QLineEdit::Normal, tr("Name"), &ok, 0, Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly | Qt::ImhDigitsOnly );
667  if(!ok || name.isEmpty()){ return; } //cancelled
668  qDebug() << "Creating a new snapshot:" << ds << name;
669  //Now create the new snapshot
670  LPBackend::newSnapshot(ds,name);
671  QMessageBox::information(this,tr("Snapshot Pending"), tr("The new snapshot creation has been added to the queue"));
672  updateTabs();
673}
674
675void LPMain::menuRemoveSnapshot(QAction *act){
676  QString snapshot = act->text();
677  QString pool = ui->combo_pools->currentText();
678  qDebug() << "Remove Snapshot:" << snapshot;
679  //verify snapshot removal
680  if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Snapshot Deletion"),QString(tr("Do you wish to delete this snapshot? %1")).arg(pool+"/"+snapshot)+"\n"+tr("WARNING: This is a permanant change that cannot be reversed"),QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
681    bool ok = LPBackend::removeSnapshot(ui->combo_pools->currentText(), snapshot);
682    if(ok){
683      QMessageBox::information(this,tr("Snapshot Removed"),tr("The snapshot was successfully deleted"));
684    }else{
685      QMessageBox::information(this,tr("Snapshot Removal Failure"),tr("The snapshot removal experienced an error and it not be completed at this time."));
686    }
687    updateTabs();
688  }
689}
Note: See TracBrowser for help on using the repository browser.