source: src-qt4/life-preserver/lp-gui/LPMain.cpp @ 1708d30

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since 1708d30 was 6a2483b, checked in by Ken Moore <ken@…>, 14 months ago

Remove the old life-preserver from the src-qt4/life-preserver dir, and replace it with src-qt4/life-preserver/lp-tray and src-qt4/life-preserver/lp-gui.

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