source: src-qt4/life-preserver/LPTray.cpp @ 50676f3

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2
Last change on this file since 50676f3 was 50676f3, checked in by Ken Moore <ken@…>, 11 months ago

Adjust the tooltip strings a bit

  • Property mode set to 100644
File size: 8.7 KB
Line 
1#include "LPTray.h"
2
3//PUBLIC
4LPTray::LPTray() : QSystemTrayIcon(){
5  initPhase = true; //flag that we are in the startup process
6  //Start up the log file watcher
7  QString logfile = "/var/log/lpreserver/lpreserver.log";
8  watcher = new QFileSystemWatcher();
9        if(!QFile::exists(logfile)){ 
10          if(!QFile::exists("/var/log/lpreserver")){ system( "mkdir /var/log/lpreserver"); }
11          system( QString("touch "+logfile).toUtf8() ); 
12        }
13        watcher->addPath(logfile);
14  logFile = new QFile(logfile);
15        logFile->open(QIODevice::ReadOnly | QIODevice::Text); //open it now, for faster reading
16  LFStream = new QTextStream(logFile);
17        connect(watcher, SIGNAL(fileChanged(QString)),this,SLOT(slotNewLogMessage(QString)) ); //now connect the signal/slot
18  //Setup the context menu
19  menu = new QMenu;
20        menu->addAction(new QAction(QIcon(":/images/application-exit.png"),tr("Close Life Preserver Tray"),this) );
21        connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(slotClose()) );
22  this->setContextMenu(menu);
23  //Setup the animated icon timer
24  timer = new QTimer();
25        timer->setInterval(100);
26        connect(timer, SIGNAL(timeout()), this, SLOT(displayWorkingIcon()) );
27  //Setup initial icon for the tray
28  this->setIcon( QIcon(":/images/tray-icon-idle.png") );
29  //Create the configuration GUI
30  GUI = new mainUI();
31  //connect other signals/slots
32  connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason)) );
33  //Make sure we check the latest line in the logfile
34  QTimer::singleShot(1000, this,SLOT(firstCheck()));
35}
36
37LPTray::~LPTray(){
38  if(statFile != 0){ statFile->close(); }
39  logFile->close();
40  delete statFile;
41  delete logFile;
42  delete watcher;
43  delete menu;
44  delete timer;
45}
46
47// ===============
48//  PRIVATE FUNCTIONS
49// ===============
50void LPTray::parseLogMessage(QString log, bool quiet){
51  //Divide up the log into it's sections
52  QString timestamp = log.section(":",0,2).simplified();
53  QString time = timestamp.section(" ",3,3).simplified();
54  QString message = log.section(":",3,3).toLower().simplified();
55  QString dev = log.section(":",4,4).simplified(); //dataset/snapshot/nothing
56  //Now decide what to do/show because of the log message
57  qDebug() << "New Log Message:" << log;
58  if(message.contains("creating snapshot")){
59    dev = message.section(" ",-1).simplified();
60    if(!quiet){ this->showMessage( time, QString(tr("Creating snapshot for %1")).arg(dev), QSystemTrayIcon::Information, 5000); }
61    //Just set the standard idle icon
62    this->setIcon( QIcon(":/images/tray-icon-idle.png") );   
63    setIdleToolTip();
64  }else if(message.contains("starting replication")){
65    startWorkingIcon();
66    //Setup the file watcher for this new log file
67    sFile = dev;
68    if(!sFile.isEmpty()){
69      if(!QFile::exists(sFile)){ system( QString("touch "+sFile).toUtf8() ); }
70      statFile = new QFile(sFile);
71        statFile->open(QIODevice::ReadOnly | QIODevice::Text);
72        SFStream = new QTextStream(statFile);
73      watcher->addPath(sFile); //will update/set tooltips
74    }
75  }else if(message.contains("finished replication")){
76    stopWorkingIcon();
77    //Stop the file wather from watching the status file and clean up
78    if(!sFile.isEmpty()){
79      watcher->removePath(sFile);
80          statFile->close();
81          sFile.clear();
82    }
83    //Clean up and show messages
84    repTotK.clear();
85    setIdleToolTip();
86    dev = message.section(" ",-1).simplified();
87    if(!quiet){ this->showMessage( time, QString(tr("Finished replication for %1")).arg(dev), QSystemTrayIcon::Information, 5000); }
88  }else if( message.contains("FAILED replication") ){
89    stopWorkingIcon();
90    //Stop the file wather from watching the status file and clean up
91    if(!sFile.isEmpty()){
92      watcher->removePath(sFile);
93          statFile->close();
94          sFile.clear();
95    }
96    //Clean up and show messages
97    repTotK.clear();
98    dev = message.section(" ",-1).simplified();
99    QString file = log.section("LOGFILE:",1,1).simplified();
100    QString tt = QString(tr("%1: Replication Failed on %2")).arg(time,dev) +"\n"+ QString(tr("Logfile available at: %1")).arg(file);
101    this->setToolTip(tt);   
102    if(!quiet){ this->showMessage( time, QString(tr("Replication Error for %1")).arg(dev), QSystemTrayIcon::Information, 5000); }
103    this->setIcon(QIcon(":/images/tray-icon-failed.png"));
104  }else{
105    //Just set the standard idle icon
106    //this->setIcon( QIcon(":/images/tray-icon-idle.png") );   
107  }
108  if(GUI->isVisible()){
109    GUI->setupUI();
110  }
111}
112
113void LPTray::parseStatusMessage(QString stat){
114  qDebug() << "New Status Message:" << stat;
115  //Divide up the status message into sections
116  stat.replace("\t"," ");
117  QString dataset = stat.section(" ",2,2,QString::SectionSkipEmpty).section("/",0,0).simplified();
118  QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
119  //Now Setup the tooltip
120  if(cSize != lastSize){ //don't update the tooltip if the same size info
121    QString percent;
122    if(!repTotK.isEmpty()){
123      //calculate the percentage
124      double tot = displayToDoubleK(repTotK);
125      double c = displayToDoubleK(cSize);
126      if( tot!=-1 & c!=-1){
127        double p = (c*100)/tot;
128        p = int(p*10)/10.0; //round to 1 decimel places
129        percent = QString::number(p) + "%";
130      }
131    }
132    if(repTotK.isEmpty()){ repTotK = "??"; }
133    //Format the tooltip String
134    QString status = cSize+"/"+repTotK;
135    if(!percent.isEmpty()){ status.append(" ("+percent+")"); }
136    QString txt = QString(tr("Replicating %1: %2")).arg(dataset, status);
137    this->setToolTip(txt);
138    lastSize = cSize; //save the current size for later
139  }
140}
141
142void LPTray::setIdleToolTip(){
143  //Get the last snapshot created
144  QStringList dsList = LPBackend::listDatasets();
145  if(dsList.isEmpty()){
146    this->setToolTip(tr("Automatic Snapshots Disabled"));
147  }else{
148    //Grab the newest snapshot from each dataset
149    QString tt; //tooltip
150    for(int i=0; i<dsList.length(); i++){
151      QStringList snaps = LPBackend::listLPSnapshots(dsList[0]);
152      if(!tt.isEmpty()){ tt.append("\n"); } //put each dataset on a new line
153      if(snaps.isEmpty()){
154        tt.append( QString(tr("%1: No snapshots available")).arg(dsList[0]) );
155      }else{
156        tt.append( QString(tr("%1: Latest snapshot: %2")).arg(dsList[0],snaps[0]) );
157      }
158    }
159    this->setToolTip(tt);
160  }
161       
162}
163
164void LPTray::startWorkingIcon(){
165  this->setIcon( QIcon(":/images/tray-icon-active7.png"));
166  //wNum = 1; //start on the first image
167  //timer->start();
168}
169
170void LPTray::stopWorkingIcon(){
171  //timer->stop();
172  this->setIcon( QIcon(":/images/tray-icon-idle.png") );     
173}
174
175double LPTray::displayToDoubleK(QString displayNumber){
176  QStringList labels; 
177    labels << "K" << "M" << "G" << "T" << "P" << "E";
178  QString clab = displayNumber.right(1); //last character is the size label
179        displayNumber.chop(1); //remove the label from the number
180  double num = displayNumber.toDouble();
181  //Now format the number properly
182  bool ok = false;
183  for(int i=0; i<labels.length(); i++){
184    if(labels[i] == clab){ ok = true; break; }
185    else{ num = num*1024; } //get ready for the next size
186  }
187  if(!ok){ num = -1; } //could not determine the size
188  return num;
189}
190
191// ===============
192//     PRIVATE SLOTS
193// ===============
194void LPTray::firstCheck(){
195  slotNewLogMessage("/var/log/lpreserver/lpreserver.log");
196  initPhase = false; //done with initializations
197}
198
199void LPTray::slotNewLogMessage(QString file){
200  //qDebug() << "New Log Message in file:" << file;
201  if(file == "/var/log/lpreserver/lpreserver.log"){
202    //Backend Status Update
203    //Now parse the log lines and do stuff with it
204    while( !LFStream->atEnd() ){ parseLogMessage(LFStream->readLine(), initPhase); }
205  }else{
206    //Replication status update
207      //get the last line from the file
208      QString stat;
209      while( !SFStream->atEnd() ){ 
210        QString line = SFStream->readLine(); 
211        if(line.contains("total estimated size")){ repTotK = line.section(" ",-1).simplified(); } //save the total size to replicate
212        else if(line.startsWith("send from ")){}
213        else if(line.startsWith("TIME ")){}
214        else{ stat = line; } //only save the relevant status line
215      }
216      //parse the status line
217      if(!stat.isEmpty()){ parseStatusMessage(stat); }
218  }
219}
220
221void LPTray::slotTrayClicked(QSystemTrayIcon::ActivationReason reason){
222  if(reason == QSystemTrayIcon::Trigger){ 
223    if(GUI->isVisible()){ GUI->hide(); }
224    else{ startGUI(); }
225  }else if( reason == QSystemTrayIcon::Context){
226    this->contextMenu()->popup(QCursor::pos());
227  }
228}
229
230void LPTray::slotClose(){
231  exit(0);
232}
233
234void LPTray::slotSingleInstance(){
235  this->show();
236}
237
238void LPTray::startGUI(){
239  //Start up the GUI
240    GUI->setupUI();
241    GUI->raise();
242    GUI->show();
243}
244
245void LPTray::displayWorkingIcon(){
246  QString ico = ":/images/tray-icon-active"+QString::number(wNum)+".png";
247  this->setIcon(QIcon(ico));
248  if(wNum == 16){ wNum = 1; } //go back to the beginning of the loop
249  else{ wNum++; }
250}
Note: See TracBrowser for help on using the repository browser.