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

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

Get the new watcher class up to the same (or slightly more) functionality thatn the old implementation. Now to start adding the new checking for mirroring/resilvering and or zpool errors.

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