source: src-qt4/pc-mounttray/mountTray.cpp @ bb6089a

9.1-release9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3
Last change on this file since bb6089a was bb6089a, checked in by beanpole135 <ken@…>, 17 months ago

Add the ability for the mount tray to monitor/warn the user about disks that are almost full. Also add a new dialog that will show the current disk usage for the entire system. Still need to clean up the menu a bit, and add the ability to change settings for this.

  • Property mode set to 100644
File size: 12.9 KB
Line 
1
2/* Qt */
3#include <QDebug>
4#include <QFile>
5#include <QDir>
6#include <QImage>
7#include <QMenu>
8#include <QTranslator>
9
10#include "mountTray.h"
11#include <pcbsd-hardware.h>
12#include <pcbsd-utils.h>
13
14MountTray::~MountTray(){
15}
16
17void MountTray::programInit()
18{
19  DCheck = new DevCheck(); //initialize class for checking devices
20  qDebug() << "pc-mounttray: starting up";
21  getInitialUsername(); //try to detect the non-root user who is running the program with root permissions
22  getDefaultFileManager(); //try to detect the default file-manager for opening the mount directory
23 
24  trayIcon = new QSystemTrayIcon(this);
25  trayIconMenu = new QMenu();
26       
27  // Tie the left-click signal to open the context menu
28  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayActivated(QSystemTrayIcon::ActivationReason)) );
29 
30  //Set the default Tray Icon (will change once tray menus are set)
31  trayIcon->setIcon(QIcon(":icons/CDdevices-inactive.png"));
32  trayIcon->show();
33
34  //Startup the devd watching process
35  qDebug() << "-Starting up the DEVD watcher";
36  devdTimer = new QTimer();
37  devdTimer->setSingleShot(TRUE);
38  connect(devdTimer,SIGNAL(timeout()),this,SLOT(slotDevChanges()));
39  startupDevdProc();
40 
41  //Do an initial scan of the devices with dmesg
42  qDebug() << "-Performing initial device scan";
43  scanInitialDevices();
44 
45  //Start up the filesystem watcher
46  qDebug() << "-Starting up the disk space alert system";
47  diskWatcher = new FSWatcher();
48  connect(diskWatcher,SIGNAL(FSWarning(QString,QString)),this,SLOT(slotDisplayWarning(QString,QString)));
49  diskWatcher->start(3600000); // check every 1 hour in milliseconds
50 
51  //Update the tray menu and icons
52  updateMenu();
53
54  qDebug() << "-Program now ready for use";
55}
56
57void MountTray::updateMenu(){
58  //Clear the menu
59  trayIconMenu->clear();
60  trayIconMenu->disconnect();
61  numAvail = 0;
62  numMount = 0;
63  //Iterate through all the devices and add them as necessary
64  for(int i=0; i<deviceList.length(); i++){
65    if(deviceList[i]->isConnected()) { 
66      trayIconMenu->addAction(deviceList[i]);
67      numAvail++;
68      if(deviceList[i]->isMounted() ){ numMount++; }
69      deviceList[i]->updateItem(); //refresh the item now as well
70    }else{
71      //Remove any devices that are not connected
72      deviceList.removeAt(i);
73      i--; //roll back one to catch the new index values for the list
74    }
75  }
76  //Separate the extra options at the end
77  trayIconMenu->addSeparator();
78  //Add the "open media" entry to the list
79  trayIconMenu->addAction( QIcon(":icons/folder.png"), tr("Open Media Directory"), this, SLOT(slotOpenMediaDir()) );
80  trayIconMenu->addSeparator();
81  trayIconMenu->addAction( QIcon(":icons/folder.png"), tr("Current Disk Usage"),this,SLOT(slotOpenFSDialog()) );
82  trayIconMenu->addAction( QIcon(":icons/refresh.png"),tr("Rescan Devices"), this, SLOT(slotRescan()) );
83  //Add the "close tray" entry to the list
84  trayIconMenu->addAction( QIcon(":icons/application-exit.png"), tr("Close Tray"), this, SLOT(closeTray()) );
85 
86  //Apply the menu to the Tray
87  trayIcon->setContextMenu(trayIconMenu);
88
89  //Update the main icon based upon whether devices have been found
90  if(numAvail==0){
91    trayIcon->setIcon( QIcon(":icons/CDdevices-inactive.png") );
92  }else{
93    if(numMount==0){
94      trayIcon->setIcon( QIcon(":icons/CDdevices.png") );
95    }else{
96      trayIcon->setIcon( QIcon(":icons/CDdevices.png") );
97    }
98  }
99}
100
101void MountTray::scanInitialDevices(){
102  slotDevChanges(FALSE);
103  return;
104}
105
106int MountTray::findDeviceInList(QString newDev){
107  for(int i=0; i<deviceList.length(); i++){
108    if( deviceList[i]->device == newDev ){ return i; }
109  }
110  return -1;
111}
112
113void MountTray::addDevice(QString dev, QString label, QString type, QString filesys){
114  if(!dev.startsWith(DEVICEDIR)){ dev.prepend(DEVICEDIR); }
115 
116  //Check if the device is already in the list
117  int tot=0;
118  for(int i=0; i<deviceList.length(); i++){
119    if( deviceList[i]->device == dev ){ return; } //already exists, do nothing
120    if( deviceList[i]->getDeviceName().startsWith(label) ){ tot++; }
121  }
122  //See if the label is unique as well, otherwise add a number to the end to make it unique
123  if(tot > 0 && !label.isEmpty()){ label.append("-"+QString::number(tot)); }
124 
125  qDebug() << "Valid Device Connection:" << dev << type << label << filesys;
126  //Create the menu item (will automount if necessary)
127  MenuItem *tmp = new MenuItem(this, dev, label, type, filesys);
128  //connect the signals/slots
129  connect(tmp, SIGNAL(itemMounted(QString)), this, SLOT(openMediaDir(QString)) );
130  connect(tmp, SIGNAL(newMessage(QString,QString)), this, SLOT(slotDisplayPopup(QString,QString)) );
131  connect(tmp, SIGNAL(itemRemoved(QString)), this, SLOT(removeDevice(QString)) );
132  deviceList << tmp;
133  //Update the menu
134  updateMenu();
135}
136
137void MountTray::removeDevice(QString dev){
138  if(!dev.startsWith(DEVICEDIR)){ dev.prepend(DEVICEDIR); }
139 
140  //Find the device in the list
141  int index = findDeviceInList(dev);
142  if( index == -1 ){ return; } //does not exist, do nothing
143  //Remove the menu entry from the list
144  deviceList[index]->cleanup(); //make sure it is unmounted with mountpoint removed
145  deviceList.removeAt(index);
146  //Update the menu
147  updateMenu();
148  qDebug() << "Valid Device Removal:" <<  dev;
149}
150
151void MountTray::slotTrayActivated(QSystemTrayIcon::ActivationReason reason) {
152   if(reason == QSystemTrayIcon::Trigger) {
153     trayIcon->contextMenu()->popup(QCursor::pos());
154   }
155}
156
157
158void MountTray::startupDevdProc(){
159  devdProc = new QLocalSocket(this);
160  devdProc->connectToServer("/var/run/devd.pipe",QIODevice::ReadOnly | QIODevice::Text);
161  if( devdProc->waitForConnected(3000) ){ //Max wait of 3 sec
162    connect(devdProc, SIGNAL(readyRead()), this, SLOT(newDevdMessage()) );
163  }else{
164    qDebug() << " - Could not startup the devd watching process";
165  }
166}
167
168void MountTray::newDevdMessage(){       
169  devdTimer->start(1000); //wait 1.5 seconds before checking for device changes
170  return;
171}
172
173void MountTray::slotDevChanges(bool showPopup){
174  //This function actually checks the system device list for changes
175  //  and updates the available devices appropriately
176 
177  if(DEBUG_MODE){ qDebug() << "Checking for Device Changes:"; }
178  //oldsysdev is the old device list for the system
179  QStringList osd = oldsysdev;
180  QStringList nsd = DCheck->devChildren("");
181  nsd.sort();
182  oldsysdev = nsd; //save the new list as the old list for later
183  //Now determine new/missing devices
184  nsd.sort();
185  QStringList rmList;
186  for(int i=0; i<osd.length(); i++){
187    int ni = nsd.indexOf(osd[i]); //new index
188    if( ni == -1){ //device removed
189      rmList << osd[i];
190      osd.removeAt(i);
191      i--;
192    }else{ //both lists have device
193      osd.removeAt(i); i--;
194      nsd.removeAt(ni);
195    }
196  }
197  //all that is left in nsd is the new additions
198
199  //Remove any devices that have been disconnected
200  if(DEBUG_MODE){ qDebug() << " -Device Removals:" << rmList; }
201  for(int i=0; i<rmList.length(); i++){
202    removeDevice(rmList[i]);
203  }
204  //Add any devices that have been connected
205  if(DEBUG_MODE){ qDebug() << " -Device Additions:" << nsd; } 
206  for(int i=0; i<nsd.length(); i++){
207    //Check if it is a good device
208    QString dlabel, dtype, dfs, dsize; //additional output info
209    bool good = DCheck->devInfo(nsd[i],&dtype,&dlabel,&dfs,&dsize);
210    if(good){
211      //Now create a new entry for this device
212      addDevice(nsd[i],dlabel,dtype,dfs); 
213      //Show a message bubble
214      if(showPopup){
215        QString title = tr("New Device");
216        QString message = QString( tr("%1 can now be accessed")).arg(dlabel);
217        slotDisplayPopup(title, message);
218      }
219    }
220  }
221  //==== CD/DVD Devices ====
222  //Always check cd/dvd devices because the device node will never be added/removed
223  QStringList diskList;
224  diskList << DCheck->devChildren("cd");
225  diskList << DCheck->devChildren("acd");
226  if(DEBUG_MODE){ qDebug() << " -Checking CD/DVD devices:" << diskList; }
227  for(int i=0; i<diskList.length(); i++){
228    if( rmList.contains(diskList[i]) || nsd.contains(diskList[i]) ){
229      continue; //do not double check a device that was just checked;       
230    }
231    //Check if it is a good device
232    QString dlabel, dtype, dfs, dsize; //additional output info
233    bool good = DCheck->devInfo(diskList[i],&dtype,&dlabel,&dfs,&dsize);
234    if(good){
235      //Now create a new entry for this device
236      addDevice(diskList[i],dlabel,dtype,dfs); 
237      //Show a message bubble
238      if(showPopup){
239        QString title = tr("New Device");
240        QString message = QString( tr("%1 can now be accessed")).arg(dlabel);
241        slotDisplayPopup(title, message);
242      }
243    }else{ //not good device
244      removeDevice(diskList[i]);           
245    }
246  } //end loop over cd/dvd devices
247}
248
249void MountTray::closeTray(){
250  qDebug() << "pc-mounttray: closing down";
251  //Kill the devd watching process
252  qDebug() << " -Shutting down DEVD watcher";
253  devdProc->disconnectFromServer();
254  qDebug() << " -Unmounting managed devices and mount points";
255  for(int i=0; i<deviceList.length(); i++){
256    deviceList[i]->cleanup();
257  }
258  //Close down the application
259  exit(0);
260}
261
262void MountTray::getInitialUsername(){
263  //Get the original user who started the tray app
264  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
265  //qDebug() << "System Environment:" << env.toStringList();
266  QString username = env.value( "LOGNAME" );
267  //qDebug() << "First attempt user detected:" << username;
268  if(username=="root"){
269    username = env.value( "SUDO_USER" ); //try this environment variable instead
270    //qDebug() << "Second attempt user detected:" << username;
271  }
272  if(username=="root" || username.isEmpty() ){
273   //attempt another method of determining the username
274   QStringList uList = pcbsd::Utils::runShellCommand("who");
275   if( uList.length() > 0 ){ 
276     username = uList[0].section(" ",0,0,QString::SectionSkipEmpty);
277     for(int i=0; i<uList.length(); i++){
278       if( !uList[i].section(" ",0,0,QString::SectionSkipEmpty).contains(username) ){
279         username = "root"; //too many users logged in; this method will not work
280         break;
281       }
282     }
283     //qDebug() << "Third attempt user detected:" << username;
284   }
285  }
286  if(username=="root"){
287    QMessageBox::warning(this,tr("User Detection Error"),tr("Unable to determine the non-root user who started the application \nCan not open the file manager with root permissions") );
288    return;
289  }
290  USERNAME=username.simplified(); //set the global variable
291  if(DEBUG_MODE){ qDebug() << "-User detected:" << USERNAME; }
292}
293
294void MountTray::getDefaultFileManager(){
295  //Get the command to open the appropriate file manager
296  QString fmcmd = pcbsd::Utils::runShellCommand("de-info -fileman").join(" ");
297  //qDebug() << "de-info result:" << fmcmd;
298  fmcmd = fmcmd.remove("%s").simplified();
299  //qDebug() << "FM command found:" << fmcmd;
300  if( fmcmd.isEmpty() || fmcmd.contains("File ") ){fmcmd= "openwith"; } //Default to the "openwith" command
301
302  FILEMAN = fmcmd.simplified();
303  if(DEBUG_MODE){ qDebug() << "-File manager detected:" << FILEMAN; }
304}
305
306void MountTray::slotOpenMediaDir(){
307  openMediaDir(MOUNTDIR);
308}
309
310void MountTray::openMediaDir(QString dir){
311  //Open the default file-manager to the directory listed
312  if(dir.isEmpty()){ dir = MOUNTDIR; }
313  if(!dir.endsWith("/")){ dir.append("/"); } //make sure the filemanager knows it is a directory
314  //Make sure we can setup user permissions
315  if(USERNAME=="root"){
316    qDebug() << "Cannot open filemanager with root permissions";
317    return;
318  }
319  //Open the default file manager to the given directory as that user
320  qDebug() << "Opening the file manager with user permissions";
321  QString cmd = "su -m "+USERNAME+" -c \'"+FILEMAN+" "+dir+"\' &";
322  //qDebug() << cmd;
323  system( cmd.toUtf8() ); 
324}
325
326void MountTray::slotRescan(){
327  //Display a notification
328  qDebug() << "Re-scanning devices:";
329  slotDisplayPopup(tr("Please Wait"),tr("Rescanning devices attached to the system"));
330  //Rescan the device list for new devices
331  scanInitialDevices();
332  //Check that all the existing devices still exist
333  for(int i=0; i<deviceList.length(); i++){
334    deviceList[i]->updateItem();
335  }
336}
337
338void MountTray::slotOpenFSDialog(){
339  //Open up the Filsystem disk space monitoring dialog
340  diskDisplay = new FSDialog();
341  diskDisplay->show();
342}
343
344void MountTray::slotSingleInstance()
345{
346  trayIcon->show();
347}
348
349void MountTray::slotDisplayPopup(QString title, QString msg){
350  //Display a popup bubble with the given message for 3 seconds
351  trayIcon->contextMenu()->hide(); //close the menu list
352  disconnect(trayIcon, SIGNAL(messageClicked()),0,0); //make sure only one signal/slot connection
353  connect(trayIcon,SIGNAL(messageClicked()),this,SLOT(slotOpenMediaDir()) );
354  trayIcon->showMessage(title, msg , QSystemTrayIcon::NoIcon,3000 );
355}
356
357void MountTray::slotDisplayWarning(QString title, QString msg){
358  //Display a popup bubble with the given message for 5 seconds
359  trayIcon->contextMenu()->hide(); //close the menu list
360  disconnect(trayIcon, SIGNAL(messageClicked()),0,0); //make sure only one signal/slot connection
361  connect(trayIcon,SIGNAL(messageClicked()),this,SLOT(slotOpenFSDialog()) );
362  trayIcon->showMessage(title, msg , QSystemTrayIcon::Warning,5000 );
363}
Note: See TracBrowser for help on using the repository browser.