Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of github.com:pcbsd/pcbsd

  • Loading branch information...
commit db5e0d0f53606d50df3129d40556cb8f46c1d186 2 parents 5fd031d + a493689
@beanpole135 beanpole135 authored
Showing with 5,414 additions and 19,047 deletions.
  1. +305 −0 src-qt4/life-preserver/LPBackend.cpp
  2. +37 −0 src-qt4/life-preserver/LPBackend.h
  3. +165 −0 src-qt4/life-preserver/LPConfig.cpp
  4. +39 −0 src-qt4/life-preserver/LPConfig.h
  5. +384 −0 src-qt4/life-preserver/LPConfig.ui
  6. +31 −0 src-qt4/life-preserver/LPContainers.h
  7. +229 −0 src-qt4/life-preserver/LPTray.cpp
  8. +48 −0 src-qt4/life-preserver/LPTray.h
  9. +55 −0 src-qt4/life-preserver/LPWizard.cpp
  10. +33 −0 src-qt4/life-preserver/LPWizard.h
  11. +627 −0 src-qt4/life-preserver/LPWizard.ui
  12. +0 −7 src-qt4/life-preserver/conf/life-preserver.conf
  13. 0  src-qt4/life-preserver/conf/rsync-excludes
  14. +0 −1  src-qt4/life-preserver/conf/rsync-includes
  15. +0 −11 src-qt4/life-preserver/externals.h
  16. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_af.ts
  17. +71 −363 src-qt4/life-preserver/i18n/LifePreserver_ar.ts
  18. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_az.ts
  19. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_bg.ts
  20. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_bn.ts
  21. +71 −384 src-qt4/life-preserver/i18n/LifePreserver_bs.ts
  22. +71 −364 src-qt4/life-preserver/i18n/LifePreserver_ca.ts
  23. +71 −369 src-qt4/life-preserver/i18n/LifePreserver_cs.ts
  24. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_cy.ts
  25. +71 −362 src-qt4/life-preserver/i18n/LifePreserver_da.ts
  26. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_de.ts
  27. +71 −379 src-qt4/life-preserver/i18n/LifePreserver_el.ts
  28. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_en_GB.ts
  29. +125 −0 src-qt4/life-preserver/i18n/LifePreserver_en_US.ts
  30. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_en_ZA.ts
  31. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_es.ts
  32. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_et.ts
  33. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_eu.ts
  34. +71 −437 src-qt4/life-preserver/i18n/LifePreserver_fa.ts
  35. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_fi.ts
  36. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_fr.ts
  37. +70 −364 src-qt4/life-preserver/i18n/LifePreserver_fr_CA.ts
  38. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_fur.ts
  39. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_gl.ts
  40. +71 −420 src-qt4/life-preserver/i18n/LifePreserver_he.ts
  41. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_hi.ts
  42. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_hr.ts
  43. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_hu.ts
  44. +71 −367 src-qt4/life-preserver/i18n/LifePreserver_id.ts
  45. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_is.ts
  46. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_it.ts
  47. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_ja.ts
  48. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_ka.ts
  49. +71 −448 src-qt4/life-preserver/i18n/LifePreserver_ko.ts
  50. +71 −376 src-qt4/life-preserver/i18n/LifePreserver_lt.ts
  51. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_lv.ts
  52. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_mk.ts
  53. +71 −368 src-qt4/life-preserver/i18n/LifePreserver_mn.ts
  54. +71 −448 src-qt4/life-preserver/i18n/LifePreserver_ms.ts
  55. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_mt.ts
  56. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_nb.ts
  57. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_ne.ts
  58. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_nl.ts
  59. +71 −387 src-qt4/life-preserver/i18n/LifePreserver_pa.ts
  60. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_pl.ts
  61. +71 −381 src-qt4/life-preserver/i18n/LifePreserver_pt.ts
  62. +71 −365 src-qt4/life-preserver/i18n/LifePreserver_pt_BR.ts
  63. +71 −453 src-qt4/life-preserver/i18n/LifePreserver_ro.ts
Sorry, we could not display the entire diff because it was too big.
View
305 src-qt4/life-preserver/LPBackend.cpp
@@ -0,0 +1,305 @@
+#include "LPBackend.h"
+
+// ==============
+// Informational
+// ==============
+QStringList LPBackend::listPossibleDatasets(){
+ QString cmd = "zpool list -H -o name";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output (one dataset per line - no headers)
+ QStringList list;
+ for(int i=0; i<out.length(); i++){
+ QString ds = out[i].section("/",0,0).simplified();
+ if(!ds.isEmpty()){ list << ds; }
+ }
+ list.removeDuplicates();
+ return list;
+}
+
+QStringList LPBackend::listDatasets(){
+ QString cmd = "lpreserver listcron";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output
+ QStringList list;
+ for(int i=2; i<out.length(); i++){ //skip the first two lines (headers)
+ QString ds = out[i].section(" - ",0,0).simplified();
+ if(!ds.isEmpty()){ list << ds; }
+ }
+ return list;
+}
+
+QStringList LPBackend::listDatasetSubsets(QString dataset){
+ QString cmd = "zfs list -H -t filesystem -o name,mountpoint,mounted";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output (one dataset per line - no headers)
+ QStringList list;
+ for(int i=0; i<out.length(); i++){
+ if(out[i].startsWith(dataset+"/")){
+ if(out[i].section("\t",2,2,QString::SectionSkipEmpty).simplified() == "yes"){
+ QString ds = out[i].section("\t",1,1).simplified(); //save the mountpoint
+ if(!ds.isEmpty()){ list << ds; }
+ }
+ }
+ }
+ list.removeDuplicates();
+ return list;
+}
+
+QStringList LPBackend::listSnapshots(QString dsmountpoint){
+ //List all the snapshots available for the given dataset mountpoint
+ QDir dir(dsmountpoint+"/.zfs/snapshot");
+ QStringList list;
+ if(dir.exists()){
+ list = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
+ }
+ return list;
+}
+
+QStringList LPBackend::listLPSnapshots(QString dataset){
+ QString cmd = "lpreserver listsnap "+dataset;
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output
+ QStringList list;
+ for(int i=out.length()-1; i>=0; i--){ //go in reverse order for proper time format (newest first)
+ if(out[i].startsWith(dataset+"@")){
+ QString snap = out[i].section("@",1,3).section(" ",0,0).simplified();;
+ if(!snap.isEmpty()){ list << snap; }
+ }
+ }
+ return list;
+}
+
+QStringList LPBackend::listReplicationTargets(){
+ QString cmd = "lpreserver replicate list";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output
+ QStringList list;
+ for(int i=0; i<out.length(); i++){
+ if(out[i].contains("->")){
+ QString ds = out[i].section("->",0,0).simplified();
+ if(!ds.isEmpty()){ list << ds; }
+ }
+ }
+ return list;
+}
+
+QStringList LPBackend::listCurrentStatus(){
+ QString cmd = "lpreserver status";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ QStringList list;
+ //Now process the output
+ for(int i=2; i<out.length(); i++){ //first 2 lines are headers
+ //Format: <dataset>:::<lastsnapshot | NONE>:::<lastreplication | NONE>
+ QString ds = out[i].section(" - ",0,0).simplified();
+ QString snap = out[i].section(" - ",1,1).simplified();
+ QString rep = out[i].section(" - ",2,2).simplified();
+ if(snap == "NONE"){ snap = "-"; }
+ if(rep == "NONE"){ rep = "-"; }
+ list << ds +":::"+ snap+":::"+rep;
+ }
+ return list;
+}
+
+// ==================
+// Dataset Management
+// ==================
+bool LPBackend::setupDataset(QString dataset, int time, int numToKeep){
+ //Configure inputs
+ QString freq;
+ if(time == -30){ freq = "30min"; }
+ else if(time == -10){ freq = "10min"; }
+ else if(time == -5){ freq = "5min"; }
+ else if(time >= 0 && time < 24){ freq = "daily@"+QString::number(time); }
+ else{ freq = "hourly"; }
+
+ //Create the command
+ QString cmd = "lpreserver cronsnap "+dataset+" start "+freq+" "+QString::number(numToKeep);
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+bool LPBackend::removeDataset(QString dataset){
+ QString cmd = "lpreserver cronsnap "+dataset+" stop";
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+bool LPBackend::datasetInfo(QString dataset, int& time, int& numToKeep){
+ QString cmd = "lpreserver listcron";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output
+ bool ok = false;
+ for(int i=0; i<out.length(); i++){
+ if(out[i].section(" - ",0,0).simplified() == dataset){
+ //Get time schedule (in integer format)
+ QString sch = out[i].section(" - ",1,1).simplified();
+ if(sch.startsWith("daily@")){ time = sch.section("@",1,1).simplified().toInt(); }
+ else if(sch=="5min"){time = -5;}
+ else if(sch=="10min"){time = -10;}
+ else if(sch=="30min"){time = -30;}
+ else{ time = -60; } //hourly
+ //Get total snapshots
+ numToKeep = out[i].section("- total:",1,1).simplified().toInt();
+ ok=true;
+ break;
+ }
+ }
+ //qDebug() << "lpreserver cronsnap:\n" << out << QString::number(time) << QString::number(numToKeep);
+ return ok;
+}
+
+// ==================
+// Snapshop Management
+// ==================
+bool LPBackend::newSnapshot(QString dataset){
+ QString cmd = "lpreserver mksnap "+dataset;
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+bool LPBackend::removeSnapshot(QString dataset, QString snapshot){
+ QString cmd = "lpreserver rmsnap "+dataset +" "+snapshot;
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+bool LPBackend::revertSnapshot(QString dataset, QString snapshot){
+ QString cmd = "lpreserver revertsnap "+dataset +" "+snapshot;
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+QString LPBackend::revertSnapshotFile(QString dsmountpoint, QString snapshot, QString filepath){
+ //Copy the given file from the snapshot back into the main dataset
+ // -- filepath: full path to the file in the snapshot directory
+
+ //Check that the file path is complete and the file exists
+ if(!QFile::exists(filepath)){
+ //invalid file given
+ return "";
+ }
+ //Generate the new file path
+ QString newfilepath = filepath.replace(dsmountpoint+"/.zfs/snapshot/"+snapshot, dsmountpoint);
+ if( QFile::exists(newfilepath) ){
+ //get the file extension
+ QString filename = newfilepath.section("/",-1);
+ QString ext = filename.section(".",-1);
+ if( !ext.isEmpty() && !filename.startsWith("."+ext) && ext!=filename){
+ newfilepath.chop(ext.length()+1);
+ newfilepath.append("-reversion."+ext);
+ int i=1;
+ //append a number to the end if a reversion file already exists
+ while(QFile::exists(newfilepath)){
+ newfilepath.chop(ext.length()+1);
+ newfilepath.append(QString::number(i)+"."+ext);
+ i ++;
+ }
+ }else{
+ //File without an extension - just append a number
+ newfilepath.append("-reversion");
+ int i=1;
+ QString npath = newfilepath;
+ while(QFile::exists(npath)){
+ npath = newfilepath.append(QString::number(i));
+ i++;
+ }
+ newfilepath = npath;
+ }
+ }
+ //perform the copy
+ bool ok = QFile::copy(filepath,newfilepath);
+ //return the path to the new file if the copy was successful
+ if(ok){
+ //reset the permissions on the reverted file to match the original
+ QFile::setPermissions(newfilepath, QFile::permissions(filepath));
+ return newfilepath;
+ }else{ return ""; }
+}
+
+// ==================
+// Replication Management
+// ==================
+bool LPBackend::setupReplication(QString dataset, QString remotehost, QString user, int port, QString remotedataset, int time){
+ QString stime = "sync"; //synchronize on snapshot creation (default)
+ if(time >= 0 || time < 24){ stime = QString::number(time); } //daily at a particular hour (24 hour notation)
+
+ QString cmd = "lpreserver replicate add "+remotehost+" "+user+" "+ QString::number(port)+" "+dataset+" "+remotedataset+" "+stime;
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+bool LPBackend::removeReplication(QString dataset){
+ QString cmd = "lpreserver replicate remove "+dataset;
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+bool LPBackend::replicationInfo(QString dataset, QString& remotehost, QString& user, int& port, QString& remotedataset, int& time){
+ QString cmd = "lpreserver replicate list";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output
+ bool ok = false;
+ for(int i=0; i<out.length(); i++){
+ if(out[i].contains("->") && out[i].startsWith(dataset)){
+ QString data = out[i].section("->",1,1);
+ user = data.section("@",0,0);
+ remotehost = data.section("@",1,1).section("[",0,0);
+ port = data.section("[",1,1).section("]",0,0).toInt();
+ remotedataset = data.section(":",1,1).section(" Time",0,0);
+ QString synchro = data.section("Time:",1,1).simplified();
+ if(synchro == "sync"){ time = -1; }
+ else{ time = synchro.toInt(); }
+ ok = true;
+ break;
+ }
+ }
+ return ok;
+}
View
37 src-qt4/life-preserver/LPBackend.h
@@ -0,0 +1,37 @@
+#ifndef _LP_BACKEND_H
+#define _LP_BACKEND_H
+
+#include <QProcess>
+#include <QString>
+#include <QStringList>
+#include <QDebug>
+#include <QDir>
+
+//Class of static functions for using the "lpreserver" backend
+class LPBackend{
+
+public:
+ //Informational
+ static QStringList listPossibleDatasets(); //list all possible datasets on the system
+ static QStringList listDatasets(); //list all current lifepreserver datasets
+ static QStringList listDatasetSubsets(QString dataset); //list all subsets of the main dataset
+ static QStringList listSnapshots(QString dsmountpoint); //list all snapshots for a particular dataset mountpoint
+ static QStringList listLPSnapshots(QString dataset); //list all snapshots created by life preserver
+ static QStringList listReplicationTargets(); //list all datasets with replication enabled
+ static QStringList listCurrentStatus(); //list the current snapshot/replication status
+ //Dataset Management
+ static bool setupDataset(QString dataset, int time, int numToKeep); //add or configure dataset
+ static bool removeDataset(QString dataset);
+ static bool datasetInfo(QString dataset, int& time, int& numToKeep); //get current settings for a dataset
+ //Snapshop Management
+ static bool newSnapshot(QString dataset);
+ static bool removeSnapshot(QString dataset, QString snapshot);
+ static bool revertSnapshot(QString dataset, QString snapshot); //revert to given snapshot
+ static QString revertSnapshotFile(QString dataset, QString snapshot, QString filepath);
+ //Replication Management
+ static bool setupReplication(QString dataset, QString remotehost, QString user, int port, QString remotedataset, int time);
+ static bool removeReplication(QString dataset);
+ static bool replicationInfo(QString dataset, QString& remotehost, QString& user, int& port, QString& remotedataset, int& time);
+
+};
+#endif
View
165 src-qt4/life-preserver/LPConfig.cpp
@@ -0,0 +1,165 @@
+#include "LPConfig.h"
+#include "ui_LPConfig.h"
+
+LPConfig::LPConfig(QWidget *parent) : QDialog(parent), ui(new Ui::LPConfig){
+ ui->setupUi(this); //initialize the designer UI
+ qDebug() << "Initializing Configuration Dialog";
+ //initialize the output variables as necessary
+ localChanged = false;
+ remoteChanged = false;
+ //Variables that will be changed when loading the dataset properties
+
+ //now connect the buttons
+ connect(ui->tool_apply,SIGNAL(clicked()), this,SLOT(slotApplyChanges()) );
+ connect(ui->tool_cancel,SIGNAL(clicked()), this, SLOT(slotCancelConfig()) );
+}
+
+LPConfig::~LPConfig(){
+
+}
+
+void LPConfig::loadDataset(QString ds, bool replicated){
+ ui->label_dataset->setText(ds);
+ loadDatasetConfiguration(ds, replicated);
+}
+
+//==========
+// PRIVATE
+// ==========
+void LPConfig::loadDatasetConfiguration(QString dataset, bool replicated){
+ qDebug() <<" - Loading dataset configuration:" << dataset;
+ //Load the dataset values
+ isReplicated = replicated;
+ // - Local settings
+ if( !LPBackend::datasetInfo(dataset, localSchedule, localSnapshots) ){
+ localSchedule = 1; //daily at 1 AM
+ localSnapshots = 7;
+ }
+ // - Replication settings
+ bool ok=false;
+ if(isReplicated){
+ ok = LPBackend::replicationInfo(dataset, remoteHost, remoteUser, remotePort, remoteDataset, remoteFreq);
+ }
+ if(!ok){
+ isReplicated = false;
+ remotePort = 22;
+ remoteFreq = -1; //sync
+ remoteHost = "";
+ remoteUser = "";
+ remoteDataset = "";
+ }
+ //Now put the values into the UI
+ // - local settings
+ if(localSchedule == -5){ //5 minutes
+ ui->combo_local_schedule->setCurrentIndex(4);
+ }else if(localSchedule == -10){ //10 minutes
+ ui->combo_local_schedule->setCurrentIndex(3);
+ }else if(localSchedule == -30){ //30 minutes
+ ui->combo_local_schedule->setCurrentIndex(2);
+ }else if(localSchedule > 0 && localSchedule < 24){ //daily @ hour
+ ui->combo_local_schedule->setCurrentIndex(0);
+ ui->time_local_daily->setTime( QTime(localSchedule, 0) );
+ }else{ //assume hourly
+ localSchedule = -60;
+ ui->combo_local_schedule->setCurrentIndex(1);
+ }
+ setLocalKeepNumber();
+
+ // - Replication settings
+ ui->groupReplicate->setChecked(isReplicated);
+ ui->lineHostName->setText(remoteHost);
+ ui->lineUserName->setText(remoteUser);
+ ui->lineRemoteDataset->setText(remoteDataset);
+ ui->spinPort->setValue(remotePort);
+ if(remoteFreq >=0 && remoteFreq < 24){
+ ui->radioRepTime->setChecked(true);
+ ui->time_replicate->setTime( QTime(remoteFreq,0) );
+ }else{
+ ui->radioSYNC->setChecked(true);
+ }
+
+}
+
+void LPConfig::checkForChanges(){
+ //Checks for changes to the settings while also updating the output variables to match the GUI
+
+ localChanged = false;
+ remoteChanged = false;
+ //Local Settings
+ int nSchedule;
+ int schint = ui->combo_local_schedule->currentIndex();
+ if(schint == 0){ nSchedule = ui->time_local_daily->time().hour(); } //daily @ hour
+ else if(schint == 1){ nSchedule = -60; } //hourly
+ else if(schint == 2){ nSchedule = -30; } //30 min
+ else if(schint == 3){ nSchedule = -10; } //10 min
+ else{ nSchedule = -5; } //5 min
+ int nTotSnaps;
+ if( ui->combo_local_keepunits->currentIndex() == 0 && (schint != 0) ){ //days
+ int numperday = 1440/(-nSchedule);
+ nTotSnaps = numperday * ui->spin_local_numkeep->value();
+ }else{ //total number (or daily snapshots)
+ nTotSnaps = ui->spin_local_numkeep->value();
+ }
+ if(nSchedule != localSchedule){localChanged = true; localSchedule = nSchedule; }
+ if(nTotSnaps != localSnapshots){ localChanged = true; localSnapshots = nTotSnaps; }
+
+ //Replication Settings
+ if(isReplicated != ui->groupReplicate->isChecked()){
+ remoteChanged = true;
+ isReplicated = ui->groupReplicate->isChecked();
+ }
+ QString tmp = ui->lineHostName->text().simplified();
+ if( tmp != remoteHost ){ remoteChanged = true; remoteHost = tmp; }
+ tmp = ui->lineUserName->text().simplified();
+ if( tmp != remoteUser ){ remoteChanged = true; remoteUser = tmp; }
+ tmp = ui->lineRemoteDataset->text().simplified();
+ if( tmp != remoteDataset ){ remoteChanged = true; remoteDataset = tmp; }
+ if( ui->spinPort->value() != remotePort){ remoteChanged = true; remotePort = ui->spinPort->value(); }
+ int nFreq = -1;
+ if(ui->radioRepTime->isChecked()){
+ nFreq = ui->time_replicate->time().hour();
+ }
+ if(nFreq < 0){
+ if( remoteFreq >= 0 && remoteFreq < 24){remoteChanged = true; remoteFreq = nFreq;}
+ }else{
+ if( nFreq != remoteFreq ){ remoteChanged = true; remoteFreq = nFreq; }
+ }
+}
+
+void LPConfig::setLocalKeepNumber(){
+ if(localSchedule >=0){
+ ui->combo_local_keepunits->setCurrentIndex(0); //num days
+ ui->spin_local_numkeep->setValue(localSnapshots);
+ }else{
+ int numperday = 1440/(-localSchedule);
+ if( localSnapshots % numperday == 0 ){
+ //daily
+ ui->combo_local_keepunits->setCurrentIndex(0); //num days
+ ui->spin_local_numkeep->setValue(localSnapshots/numperday);
+ }else{
+ //odd number of snapshots - must be total
+ ui->combo_local_keepunits->setCurrentIndex(1); //num total
+ ui->spin_local_numkeep->setValue(localSnapshots);
+ }
+ }
+}
+
+// =============
+// PRIVATE SLOTS
+// =============
+void LPConfig::slotApplyChanges(){
+ checkForChanges();
+ this->close();
+}
+
+void LPConfig::slotCancelConfig(){
+ //Make sure it is flagged as unchanged before closing
+ localChanged = false;
+ remoteChanged = false;
+ this->close();
+}
+
+void LPConfig::on_combo_local_schedule_currentIndexChanged(int index){
+ //Adjust whether the daily time box is visible
+ ui->time_local_daily->setVisible( (index == 0) );
+}
View
39 src-qt4/life-preserver/LPConfig.h
@@ -0,0 +1,39 @@
+#ifndef _LP_CONFIG_H
+#define _LP_CONFIG_H
+
+#include <QDialog>
+#include <QString>
+#include <QDebug>
+
+#include "LPBackend.h"
+
+namespace Ui{
+ class LPConfig;
+}
+
+class LPConfig : public QDialog{
+ Q_OBJECT
+public:
+ LPConfig(QWidget* parent = 0);
+ ~LPConfig();
+
+ void loadDataset(QString, bool);
+
+ //Output variables
+ bool localChanged, remoteChanged, isReplicated;
+ int localSchedule, localSnapshots, remotePort, remoteFreq;
+ QString remoteHost, remoteUser, remoteDataset;
+
+private:
+ Ui::LPConfig *ui;
+ void loadDatasetConfiguration(QString, bool);
+ void checkForChanges();
+ void setLocalKeepNumber();
+
+private slots:
+ void slotApplyChanges();
+ void slotCancelConfig();
+ void on_combo_local_schedule_currentIndexChanged(int);
+};
+
+#endif
View
384 src-qt4/life-preserver/LPConfig.ui
@@ -0,0 +1,384 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LPConfig</class>
+ <widget class="QDialog" name="LPConfig">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>315</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Dataset</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Data Set:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label_dataset">
+ <property name="text">
+ <string notr="true">sample</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_local">
+ <attribute name="title">
+ <string>Local Snapshots</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Schedule:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="combo_local_schedule">
+ <item>
+ <property name="text">
+ <string>Daily</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Hourly</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>30 minutes</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>10 minutes</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>5 minutes</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTimeEdit" name="time_local_daily">
+ <property name="maximumTime">
+ <time>
+ <hour>23</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="minimumTime">
+ <time>
+ <hour>1</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="displayFormat">
+ <string>@ h AP</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QSpinBox" name="spin_local_numkeep">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>800</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_local_keepunits">
+ <item>
+ <property name="text">
+ <string>Days</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Total</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Keep:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_remote">
+ <attribute name="title">
+ <string>Replication</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupReplicate">
+ <property name="title">
+ <string>Replicate on a Remote System</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Host Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineHostName"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>User Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineUserName"/>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>SSH Port</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinPort">
+ <property name="maximum">
+ <number>999999</number>
+ </property>
+ <property name="value">
+ <number>22</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>Remote Dataset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineRemoteDataset"/>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="0">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Frequency</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="radioSYNC">
+ <property name="text">
+ <string>With snapshot creation (Best for daily snapshots)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QRadioButton" name="radioRepTime">
+ <property name="text">
+ <string>Daily at:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTimeEdit" name="time_replicate">
+ <property name="displayFormat">
+ <string>h AP</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_apply">
+ <property name="text">
+ <string>Apply</string>
+ </property>
+ <property name="icon">
+ <iconset resource="lPreserve.qrc">
+ <normaloff>:/images/backup-ok.png</normaloff>:/images/backup-ok.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_cancel">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="icon">
+ <iconset resource="lPreserve.qrc">
+ <normaloff>:/images/application-exit.png</normaloff>:/images/application-exit.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="lPreserve.qrc"/>
+ </resources>
+ <connections/>
+</ui>
View
31 src-qt4/life-preserver/LPContainers.h
@@ -0,0 +1,31 @@
+#ifndef _LP_CONTAINERS_H
+#define _LP_CONTAINERS_H
+
+#include <QHash>
+#include <QStringList>
+#include <QString>
+
+
+class LPDataset{
+public:
+ LPDataset(){}
+ ~LPDataset(){}
+
+ //Information needed on each dataset
+ QString latestReplication;
+ QString latestSnapshot;
+ QString numberOfSnapshots;
+ QHash<QString,QStringList> subsetHash; //<subset, snapshot list> (complete dataset name should be <ds><subset>)
+
+ //Simplification functions for getting info from the hash
+ QStringList subsets(){ return QStringList(subsetHash.keys()); }
+ QStringList snapshots(QString subset){
+ if(subsetHash.contains(subset)){
+ return subsetHash[subset];
+ }else{
+ return QStringList();
+ }
+ }
+};
+
+#endif
View
229 src-qt4/life-preserver/LPTray.cpp
@@ -0,0 +1,229 @@
+#include "LPTray.h"
+
+//PUBLIC
+LPTray::LPTray() : QSystemTrayIcon(){
+ //Start up the log file watcher
+ QString logfile = "/var/log/lpreserver/lpreserver.log";
+ watcher = new QFileSystemWatcher();
+ if(!QFile::exists(logfile)){
+ if(!QFile::exists("/var/log/lpreserver")){ system( "mkdir /var/log/lpreserver"); }
+ system( QString("touch "+logfile).toUtf8() );
+ }
+ watcher->addPath(logfile);
+ logFile = new QFile(logfile);
+ logFile->open(QIODevice::ReadOnly | QIODevice::Text); //open it now, for faster reading
+ LFStream = new QTextStream(logFile);
+ connect(watcher, SIGNAL(fileChanged(QString)),this,SLOT(slotNewLogMessage(QString)) ); //now connect the signal/slot
+ //Setup the context menu
+ menu = new QMenu;
+ menu->addAction(new QAction(QIcon(":/images/application-exit.png"),tr("Close Life Preserver Tray"),this) );
+ connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(slotClose()) );
+ this->setContextMenu(menu);
+ //Setup the animated icon timer
+ timer = new QTimer();
+ timer->setInterval(100);
+ connect(timer, SIGNAL(timeout()), this, SLOT(displayWorkingIcon()) );
+ //Setup initial icon for the tray
+ this->setIcon( QIcon(":/images/tray-icon-idle.png") );
+ //Create the configuration GUI
+ GUI = new mainUI();
+ //connect other signals/slots
+ connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason)) );
+ //Make sure we check the latest line in the logfile
+ QTimer::singleShot(1000, this,SLOT(firstCheck()));
+}
+
+LPTray::~LPTray(){
+ if(statFile != 0){ statFile->close(); }
+ logFile->close();
+ delete statFile;
+ delete logFile;
+ delete watcher;
+ delete menu;
+ delete timer;
+}
+
+// ===============
+// PRIVATE FUNCTIONS
+// ===============
+void LPTray::parseLogMessage(QString log){
+ //Divide up the log into it's sections
+ QString timestamp = log.section(":",0,2).simplified();
+ QString time = timestamp.section(" ",3,3).simplified();
+ QString message = log.section(":",3,3).toLower().simplified();
+ QString dev = log.section(":",4,4).simplified(); //dataset/snapshot/nothing
+ //Now decide what to do/show because of the log message
+ qDebug() << "New Log Message:" << log;
+ if(message.contains("creating snapshot")){
+ dev = message.section(" ",-1).simplified();
+ this->showMessage( time, QString(tr("Creating snapshot for %1")).arg(dev), QSystemTrayIcon::Information, 5000);
+ //Just set the standard idle icon
+ this->setIcon( QIcon(":/images/tray-icon-idle.png") );
+// }else if(message.contains("pruning snapshot")){
+ }else if(message.contains("starting replication")){
+ startWorkingIcon();
+ //Setup the file watcher for this new log file
+ sFile = dev;
+ if(!sFile.isEmpty()){
+ if(!QFile::exists(sFile)){ system( QString("touch "+sFile).toUtf8() ); }
+ statFile = new QFile(sFile);
+ statFile->open(QIODevice::ReadOnly | QIODevice::Text);
+ SFStream = new QTextStream(statFile);
+ watcher->addPath(sFile); //will update/set tooltips
+ }
+ }else if(message.contains("finished replication")){
+ stopWorkingIcon();
+ //Stop the file wather from watching the status file and clean up
+ if(!sFile.isEmpty()){
+ watcher->removePath(sFile);
+ statFile->close();
+ sFile.clear();
+ }
+ //Clean up and show messages
+ repTotK.clear();
+ this->setToolTip("");
+ dev = message.section(" ",-1).simplified();
+ this->showMessage( time, QString(tr("Finished replication for %1")).arg(dev), QSystemTrayIcon::Information, 5000);
+ }else if( message.contains("FAILED replication") ){
+ stopWorkingIcon();
+ //Stop the file wather from watching the status file and clean up
+ if(!sFile.isEmpty()){
+ watcher->removePath(sFile);
+ statFile->close();
+ sFile.clear();
+ }
+ //Clean up and show messages
+ repTotK.clear();
+ dev = message.section(" ",-1).simplified();
+ QString file = log.section("LOGFILE:",1,1).simplified();
+ QString tt = QString(tr("%1: Replication Failed on %2")).arg(time,dev) +"\n"+ QString(tr("Logfile available at: %1")).arg(file);
+ this->setToolTip(tt);
+ this->showMessage( time, QString(tr("Replication Error for %1")).arg(dev), QSystemTrayIcon::Information, 5000);
+ this->setIcon(QIcon(":/images/tray-icon-failed.png"));
+ }else{
+ //Just set the standard idle icon
+ //this->setIcon( QIcon(":/images/tray-icon-idle.png") );
+ }
+ if(GUI->isVisible()){
+ GUI->updateDisplay();
+ }
+}
+
+void LPTray::parseStatusMessage(QString stat){
+ qDebug() << "New Status Message:" << stat;
+ //Divide up the status message into sections
+ stat.replace("\t"," ");
+ QString dataset = stat.section(" ",2,2,QString::SectionSkipEmpty).section("/",0,0).simplified();
+ QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
+ //Now Setup the tooltip
+ if(cSize != lastSize){ //don't update the tooltip if the same size info
+ QString percent;
+ if(!repTotK.isEmpty()){
+ //calculate the percentage
+ double tot = displayToDoubleK(repTotK);
+ double c = displayToDoubleK(cSize);
+ if( tot!=-1 & c!=-1){
+ double p = (c*100)/tot;
+ p = int(p*10)/10.0; //round to 1 decimel places
+ percent = QString::number(p) + "%";
+ }
+ }
+ if(repTotK.isEmpty()){ repTotK = "??"; }
+ //Format the tooltip String
+ QString status = cSize+"/"+repTotK;
+ if(!percent.isEmpty()){ status.append(" ("+percent+")"); }
+ QString txt = QString(tr("Replicating %1: %2")).arg(dataset, status);
+ this->setToolTip(txt);
+ lastSize = cSize; //save the current size for later
+ }
+}
+
+void LPTray::startWorkingIcon(){
+ this->setIcon( QIcon(":/images/tray-icon-active7.png"));
+ //wNum = 1; //start on the first image
+ //timer->start();
+}
+
+void LPTray::stopWorkingIcon(){
+ //timer->stop();
+ this->setIcon( QIcon(":/images/tray-icon-idle.png") );
+}
+
+double LPTray::displayToDoubleK(QString displayNumber){
+ QStringList labels;
+ labels << "K" << "M" << "G" << "T" << "P" << "E";
+ QString clab = displayNumber.right(1); //last character is the size label
+ displayNumber.chop(1); //remove the label from the number
+ double num = displayNumber.toDouble();
+ //Now format the number properly
+ bool ok = false;
+ for(int i=0; i<labels.length(); i++){
+ if(labels[i] == clab){ ok = true; break; }
+ else{ num = num*1024; } //get ready for the next size
+ }
+ if(!ok){ num = -1; } //could not determine the size
+ return num;
+}
+
+// ===============
+// PRIVATE SLOTS
+// ===============
+void LPTray::firstCheck(){
+ slotNewLogMessage("/var/log/lpreserver/lpreserver.log");
+}
+
+void LPTray::slotNewLogMessage(QString file){
+ //qDebug() << "New Log Message in file:" << file;
+ if(file == "/var/log/lpreserver/lpreserver.log"){
+ //Backend Status Update
+ //get the last line from the log file
+ QString log;
+ while( !LFStream->atEnd() ){ log = LFStream->readLine(); }
+ //Now parse the log line and do stuff with it
+ parseLogMessage(log);
+ }else{
+ //Replication status update
+ //get the last line from the file
+ QString stat;
+ while( !SFStream->atEnd() ){
+ QString line = SFStream->readLine();
+ if(line.contains("total estimated size")){ repTotK = line.section(" ",-1).simplified(); } //save the total size to replicate
+ else if(line.startsWith("send from ")){}
+ else if(line.startsWith("TIME ")){}
+ else{ stat = line; } //only save the relevant status line
+ }
+ //parse the status line
+ if(!stat.isEmpty()){ parseStatusMessage(stat); }
+ }
+}
+
+void LPTray::slotTrayClicked(QSystemTrayIcon::ActivationReason reason){
+ if(reason == QSystemTrayIcon::Trigger){
+ if(GUI->isVisible()){ GUI->hide(); }
+ else{ startGUI(); }
+ }else if( reason == QSystemTrayIcon::Context){
+ this->contextMenu()->popup(QCursor::pos());
+ }
+}
+
+void LPTray::slotClose(){
+ exit(0);
+}
+
+void LPTray::slotSingleInstance(){
+ this->show();
+}
+
+void LPTray::startGUI(){
+ //Start up the GUI
+ GUI->setupUI();
+ GUI->raise();
+ GUI->show();
+}
+
+void LPTray::displayWorkingIcon(){
+ QString ico = ":/images/tray-icon-active"+QString::number(wNum)+".png";
+ this->setIcon(QIcon(ico));
+ if(wNum == 16){ wNum = 1; } //go back to the beginning of the loop
+ else{ wNum++; }
+}
View
48 src-qt4/life-preserver/LPTray.h
@@ -0,0 +1,48 @@
+#ifndef _LP_TRAY_H
+#define _LP_TRAY_H
+
+#include <QSystemTrayIcon>
+#include <QMenu>
+#include <QFileSystemWatcher>
+#include <QString>
+#include <QTimer>
+#include <QProcess>
+#include <QFile>
+#include <QTextStream>
+
+#include "mainUI.h"
+
+class LPTray : public QSystemTrayIcon{
+ Q_OBJECT
+public:
+ LPTray();
+ ~LPTray();
+
+private:
+ QFileSystemWatcher *watcher;
+ QMenu *menu;
+ QTimer *timer;
+ mainUI *GUI;
+ QString sFile; //location of the replication status file
+ QFile *logFile, *statFile;
+ QTextStream *LFStream, *SFStream;
+ QString repTotK, lastSize;
+ int wNum; //internal tracking of which frame of the icon animation we are on
+
+ void parseLogMessage(QString);
+ void parseStatusMessage(QString);
+ void startWorkingIcon();
+ void stopWorkingIcon();
+ double displayToDoubleK(QString);
+
+private slots:
+ void firstCheck();
+ void slotNewLogMessage(QString);
+ void slotTrayClicked(QSystemTrayIcon::ActivationReason);
+ void slotClose();
+ void slotSingleInstance();
+ void startGUI();
+ void displayWorkingIcon();
+};
+
+#endif
View
55 src-qt4/life-preserver/LPWizard.cpp
@@ -0,0 +1,55 @@
+#include "LPWizard.h"
+#include "ui_LPWizard.h"
+
+LPWizard::LPWizard(QWidget *parent = 0) : QWizard(parent), ui(new Ui::LPWizard){
+ //Initialize the graphical items
+ ui->setupUi(this); //load the mainUI.ui file
+ cancelled = true; //Make sure this is always set by default
+ connect(this,SIGNAL(accepted()), this,SLOT(slotFinished()) );
+ connect(this,SIGNAL(rejected()),this,SLOT(slotCancelled()) );
+}
+
+LPWizard::~LPWizard(){
+
+}
+
+void LPWizard::setDataset(QString ds){
+ ui->label_dataset->setText(ds);
+}
+
+void LPWizard::slotFinished(){
+ qDebug() << "Wizard Finished";
+ cancelled = false; //use the values from the UI
+ //Now load the information from the UI
+ enableReplication = ui->groupReplicate->isChecked();
+ if(enableReplication){
+ remotePort = ui->spinPort->value();
+ if(ui->radioSYNC->isChecked()){
+ remoteTime = -1;
+ }else{
+ remoteTime = ui->time_replicate->time().hour();
+ }
+ remoteHost = ui->lineHostName->text();
+ remoteUser = ui->lineUserName->text();
+ remoteDataset = ui->lineRemoteDataset->text();
+ }
+ if(ui->radioDaily->isChecked()){ localTime = ui->timeEdit->time().hour(); }
+ else if( ui->radio10Min->isChecked()){ localTime = -10; }
+ else if( ui->radio30Min->isChecked()){ localTime = -30; }
+ else if( ui->radio5Min->isChecked()){ localTime = -5; }
+ else{ localTime = -60; } //hourly
+ if( ui->radioKeepTotal->isChecked() ){
+ totalSnapshots = ui->spin_keepTotal->value();
+ }else{
+ if(localTime >0){ totalSnapshots = ui->spin_keepDays->value(); }
+ else{ totalSnapshots = ui->spin_keepDays->value() * (1440/(-localTime)); } //convert to number of snapshots a day
+ }
+ //Now close the UI
+ this->close();
+}
+
+void LPWizard::slotCancelled(){
+ qDebug() << "Wizard Cancelled";
+ cancelled = true; //just to make sure
+ this->close();
+}
View
33 src-qt4/life-preserver/LPWizard.h
@@ -0,0 +1,33 @@
+#ifndef _LP_WIZARD_H
+#define _LP_WIZARD_H
+
+#include <QWizard>
+#include <QString>
+#include <QDebug>
+
+namespace Ui{
+ class LPWizard;
+}
+
+class LPWizard : public QWizard{
+ Q_OBJECT
+public:
+ explicit LPWizard(QWidget*);
+ ~LPWizard();
+
+ //Input dataset
+ void setDataset(QString);
+ //Output variables
+ bool cancelled, enableReplication;
+ int localTime, totalSnapshots, remotePort, remoteTime;
+ QString remoteHost, remoteUser, remoteDataset;
+
+private:
+ Ui::LPWizard *ui;
+
+private slots:
+ void slotFinished();
+ void slotCancelled();
+};
+
+#endif
View
627 src-qt4/life-preserver/LPWizard.ui
@@ -0,0 +1,627 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LPWizard</class>
+ <widget class="QWizard" name="LPWizard">
+ <property name="windowModality">
+ <enum>Qt::ApplicationModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>474</width>
+ <height>381</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>New Life Preserver</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="lPreserve.qrc">
+ <normaloff>:/images/lifepreserver.png</normaloff>:/images/lifepreserver.png</iconset>
+ </property>
+ <property name="options">
+ <set>QWizard::IndependentPages</set>
+ </property>
+ <widget class="QWizardPage" name="wizardPage1">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>This wizard will walk you through the process of setting up a new snapshot schedule for the following ZFS dataset:</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_dataset">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">SAMPLE</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWizardPage" name="wizardPage">
+ <property name="title">
+ <string/>
+ </property>
+ <property name="subTitle">
+ <string/>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_8">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="title">
+ <string>Snapshot schedule</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Snapshots can be scheduled anywhere from daily, down to every 5 minutes. Snapshots consume very little disk space, and will only grow as the current data on disk changes. </string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="radioHourly">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Hourly</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <item>
+ <widget class="QRadioButton" name="radioDaily">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Daily @</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTimeEdit" name="timeEdit">
+ <property name="time">
+ <time>
+ <hour>1</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="maximumTime">
+ <time>
+ <hour>23</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="minimumTime">
+ <time>
+ <hour>1</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="displayFormat">
+ <string>h AP</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <widget class="QRadioButton" name="radio30Min">
+ <property name="text">
+ <string>30 minutes</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QRadioButton" name="radio10Min">
+ <property name="text">
+ <string>10 minutes</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QRadioButton" name="radio5Min">
+ <property name="text">
+ <string>5 minutes</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>48</width>
+ <height>74</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWizardPage" name="wizardPage_5">
+ <layout class="QGridLayout" name="gridLayout_11">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="groupBox_5">
+ <property name="title">
+ <string>Snapshot pruning</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The oldest snapshots will be auto-pruned after reaching either the number of days or the total number of snapshots that you specify. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_9">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_13">
+ <item>
+ <widget class="QRadioButton" name="radio_keepDays">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Keep</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spin_keepDays">
+ <property name="suffix">
+ <string/>
+ </property>
+ <property name="maximum">
+ <number>800</number>
+ </property>
+ <property name="value">
+ <number>7</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>days worth of snapshots</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_14">
+ <item>
+ <widget class="QRadioButton" name="radioKeepTotal">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Keep</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spin_keepTotal">
+ <property name="maximum">
+ <number>800</number>
+ </property>
+ <property name="value">
+ <number>7</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_13">
+ <property name="text">
+ <string>total snapshots </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>17</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>48</width>
+ <height>74</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWizardPage" name="wizardPage_3">
+ <layout class="QGridLayout" name="gridLayout_10">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Replication Server</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Replication will keep a copy of your data on a remote system in the case of a total disk failure.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>NOTE: A valid replication target system must be running a compatible version of ZFS and have SSH enabled, such as on a FreeNAS system.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupReplicate">
+ <property name="title">
+ <string>Replicate my data</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="4" column="0">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Frequency</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QRadioButton" name="radioSYNC">
+ <property name="text">
+ <string>With snapshot creation (Best for daily snapshots)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QRadioButton" name="radioRepTime">
+ <property name="text">
+ <string>Daily at:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTimeEdit" name="time_replicate">
+ <property name="maximumDateTime">
+ <datetime>
+ <hour>23</hour>
+ <minute>0</minute>
+ <second>0</second>
+ <year>2000</year>
+ <month>1</month>
+ <day>1</day>
+ </datetime>
+ </property>
+ <property name="maximumTime">
+ <time>
+ <hour>23</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="minimumTime">
+ <time>
+ <hour>1</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </time>
+ </property>
+ <property name="displayFormat">
+ <string>h AP</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Host Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineHostName"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>User Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineUserName"/>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>SSH Port</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinPort">
+ <property name="maximum">
+ <number>999999</number>
+ </property>
+ <property name="value">
+ <number>22</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>Remote Dataset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineRemoteDataset"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWizardPage" name="wizardPage_4">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelFinished">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Your new Life Preserver schedule is now set up! You may go back and change your configuration at any time from within the main Life Preserver window.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Click the Finish button to apply these settings and create the new backup schedule.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <resources>
+ <include location="lPreserve.qrc"/>
+ </resources>
+ <connections/>
+</ui>
View
7 src-qt4/life-preserver/conf/life-preserver.conf
@@ -1,7 +0,0 @@
-#!/bin/sh
-# Configuration defaults for life-preserver
-# Some of these settings can be overridden per preserver
-#############################################################################
-
-DEFAULT_BACKDIR="life-preserver"
-export DEFAULT_BACKDIR
View
0  src-qt4/life-preserver/conf/rsync-excludes
No changes.
View
1  src-qt4/life-preserver/conf/rsync-includes
@@ -1 +0,0 @@
-/usr/home/
View
11 src-qt4/life-preserver/externals.h
@@ -1,11 +0,0 @@
-#include <QString>
-#include "lifePreserverMain.h"
-#include "lifePreserverWelcome.h"
-#include "../config.h"
-
-const QString LIFEPRESERVERPATH( PREFIX + "/share/lifePreserver");
-const QString LIFEPRESERVERSDIR( LIFEPRESERVERPATH + QString("/preservers"));
-
-extern bool havePreservers;
-extern lifePreserver *m;
-extern lifePreserverWelcome *w;
View
524 src-qt4/life-preserver/i18n/LifePreserver_af.ts
@@ -1,507 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.0">
+<TS version="2.0" language="af_ZA">
<context>
- <name>PRESERVER</name>
+ <name>LPTray</name>
<message>
- <source>No Previous Backup</source>
- <translation type="unfinished">
- </translation>
- </message>
-</context>
-<context>
- <name>lifeListBackups</name>
- <message>
- <source>No Backups Found</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>No backups could be found on this server!</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Failed connecting to server</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Failed connecting to the server! Check connection and try again!</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>The following backups are available:</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Select Backup</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Fetching backup list from server, please wait...</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Available Backups</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Select Backup</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Cancel</source>
- <translation type="unfinished">
- </translation>
- </message>
-</context>
-<context>
- <name>lifePreserver</name>
- <message>
- <source>Edit</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Restore From</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Remove</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Start</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Not running</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Stop</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Life Preserver</source>
- <translation type="unfinished">
- </translation>
+ <location filename="../LPTray.cpp" line="13"/>
+ <source>Close Life Preserver Tray</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Last Backup</source>
- <translation type="unfinished">
- </translation>
+ <location filename="../LPTray.cpp" line="45"/>
+ <source>Creating snapshot for %1</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Status</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;File</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Preservers</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;New Preserver</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Quit</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Edit</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Remove</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Mi&amp;nimize</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Restore</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Backup Server</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Schedule</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Life Preserver Backups</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Running...</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>Backup in progress...</source>
- <translation type="unfinished">
- </translation>
- </message>
- <message>
- <source>&amp;Start at login</source>
- <translation type="unfinished">
- </translation>
+ <location filename="../LPTray.cpp" line="54"/>
+ <source>Finished replication for %1</source>