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

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

Remove all the commented out sections for the old file manager detection routine.

  • Property mode set to 100644
File size: 16.5 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  MTINIT=true; //set the flag that the mount tray is initializing;
22  getInitialUsername(); //try to detect the non-root user who is running the program with root permissions
23  loadSavedSettings();
24 
25  trayIcon = new QSystemTrayIcon(this);
26  trayIconMenu = new QMenu();
27  //Generate the system menu options (these don't change)
28  sysMenu = new QMenu( tr("More Options") );
29    sysMenu->setIcon( QIcon(":icons/config.png") );
30    //Add the additional options
31    sysMenu->addAction( QIcon(":icons/folder.png"), tr("Open Media Directory"), this, SLOT(slotOpenMediaDir()) );
32    sysMenu->addAction( QIcon(":icons/harddrive.png"), tr("View Disk Usage"),this,SLOT(slotOpenFSDialog()) );
33    sysMenu->addAction( QIcon(":icons/refresh.png"),tr("Rescan Devices"), this, SLOT(slotRescan()) );
34    //Add the setting dialog option seperately
35    sysMenu->addSeparator();
36    sysMenu->addAction( QIcon(":icons/dvd.png"), tr("Load ISO File"), this, SLOT(slotOpenISO()) );
37    sysMenu->addAction( QIcon(":icons/config.png"), tr("Change Settings"), this, SLOT(slotOpenSettings()) );
38    //Add the Close button seperately
39    sysMenu->addSeparator();
40    sysMenu->addAction( QIcon(":icons/application-exit.png"), tr("Close Tray"), this, SLOT(closeTray()) );
41 
42  // Tie the left-click signal to open the context menu
43  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayActivated(QSystemTrayIcon::ActivationReason)) );
44  //Connect the message clicked slot
45  connect(trayIcon,SIGNAL(messageClicked()),this,SLOT(slotPopupClicked()) );
46  //Set the default Tray Icon (will change once tray menus are set)
47  trayIcon->setIcon(QIcon(":icons/CDdevices-inactive.png"));
48  trayIcon->show();
49
50  //Startup the devd watching process
51  qDebug() << "-Starting up the DEVD watcher";
52  devdTimer = new QTimer();
53  devdTimer->setSingleShot(TRUE);
54  connect(devdTimer,SIGNAL(timeout()),this,SLOT(slotDevChanges()));
55  startupDevdProc();
56 
57  //Do an initial scan of the devices with dmesg
58  qDebug() << "-Performing initial device scan";
59  scanInitialDevices();
60 
61  //Start up the filesystem watcher
62  diskWatcher = new FSWatcher();
63  connect(diskWatcher,SIGNAL(FSWarning(QString,QString)),this,SLOT(slotDisplayWarning(QString,QString)));
64  if(useDiskWatcher){ 
65    qDebug() << "-Starting up the disk space alert system";
66    diskWatcher->start(diskTimerMaxMS); 
67  }
68 
69  //Update the tray menu and icons
70  updateMenu();
71
72  qDebug() << "-Program now ready for use";
73  MTINIT=false;
74}
75
76void MountTray::updateMenu(){
77  //Clear the menu
78  trayIconMenu->clear();
79  trayIconMenu->disconnect();
80  numAvail = 0;
81  numMount = 0;
82  //Iterate through all the devices and add them as necessary
83  for(int i=0; i<deviceList.length(); i++){
84    if(deviceList[i]->isConnected()) { 
85      trayIconMenu->addAction(deviceList[i]);
86      numAvail++;
87      if(deviceList[i]->isMounted() ){ numMount++; }
88      deviceList[i]->updateItem(); //refresh the item now as well
89    }else{
90      //Remove any devices that are not connected
91      deviceList.removeAt(i);
92      i--; //roll back one to catch the new index values for the list
93    }
94  }
95  //Separate the extra options at the end
96  trayIconMenu->addSeparator();
97  trayIconMenu->addMenu(sysMenu);
98  //Apply the menu to the Tray
99  trayIcon->setContextMenu(trayIconMenu);
100
101  //Update the main icon based upon whether devices have been found
102  if(numAvail==0){
103    trayIcon->setIcon( QIcon(":icons/CDdevices-inactive.png") );
104  }else{
105    if(numMount==0){
106      trayIcon->setIcon( QIcon(":icons/CDdevices.png") );
107    }else{
108      trayIcon->setIcon( QIcon(":icons/CDdevices.png") );
109    }
110  }
111}
112
113void MountTray::scanInitialDevices(){
114  slotDevChanges(FALSE);
115  return;
116}
117
118int MountTray::findDeviceInList(QString newDev){
119  for(int i=0; i<deviceList.length(); i++){
120    if( deviceList[i]->device == newDev ){ return i; }
121  }
122  return -1;
123}
124
125bool MountTray::addDevice(QString dev, QString label, QString type, QString filesys){
126  if(!dev.startsWith(DEVICEDIR)){ dev.prepend(DEVICEDIR); }
127 
128  //Check if the device is already in the list
129  int tot=0;
130  for(int i=0; i<deviceList.length(); i++){
131    if( deviceList[i]->device == dev ){ return false; } //already exists, do nothing
132    if( deviceList[i]->getDeviceName().startsWith(label) ){ tot++; }
133  }
134  //See if the label is unique as well, otherwise add a number to the end to make it unique
135  if(tot > 0 && !label.isEmpty()){ label.append("-"+QString::number(tot)); }
136 
137  qDebug() << "Valid Device Connection:" << dev << type << label << filesys;
138  //Create the menu item (will automount if necessary)
139  MenuItem *tmp = new MenuItem(this, dev, label, type, filesys);
140  //connect the signals/slots
141  connect(tmp, SIGNAL(itemMounted(QString)), this, SLOT(openMediaDir(QString)) );
142  connect(tmp, SIGNAL(newMessage(QString,QString)), this, SLOT(slotDisplayPopup(QString,QString)) );
143  connect(tmp, SIGNAL(itemRemoved(QString)), this, SLOT(removeDevice(QString)) );
144  deviceList << tmp;
145  //Update the menu
146  updateMenu();
147  return true;
148}
149
150void MountTray::removeDevice(QString dev){
151  if(!dev.startsWith(DEVICEDIR)){ dev.prepend(DEVICEDIR); }
152 
153  //Find the device in the list
154  int index = findDeviceInList(dev);
155  if( index == -1 ){ return; } //does not exist, do nothing
156  //Remove the menu entry from the list
157  deviceList[index]->cleanup(); //make sure it is unmounted with mountpoint removed
158  deviceList.removeAt(index);
159  //Update the menu
160  updateMenu();
161  qDebug() << "Valid Device Removal:" <<  dev;
162}
163
164void MountTray::slotTrayActivated(QSystemTrayIcon::ActivationReason reason) {
165   if(reason == QSystemTrayIcon::Trigger) {
166     //Make sure all the items are updated
167     for(int i=0; i<deviceList.length(); i++){
168        deviceList[i]->updateItem();
169     }
170     trayIcon->contextMenu()->popup(QCursor::pos());
171   }
172}
173
174
175void MountTray::startupDevdProc(){
176  devdProc = new QLocalSocket(this);
177  devdProc->connectToServer("/var/run/devd.pipe",QIODevice::ReadOnly | QIODevice::Text);
178  if( devdProc->waitForConnected(3000) ){ //Max wait of 3 sec
179    connect(devdProc, SIGNAL(readyRead()), this, SLOT(newDevdMessage()) );
180  }else{
181    qDebug() << " - Could not startup the devd watching process";
182  }
183}
184
185void MountTray::newDevdMessage(){       
186  devdTimer->start(1500); //wait 1.5 seconds before checking for device changes
187  return;
188}
189
190void MountTray::slotDevChanges(bool showPopup){
191  //This function actually checks the system device list for changes
192  //  and updates the available devices appropriately
193 
194  if(DEBUG_MODE){ qDebug() << "Checking for Device Changes:"; }
195  //Get the current list of devices
196  QStringList nsd = DCheck->devChildren("");
197  //Remove all the currently managed devices
198  qDebug() << "Rescanning Device List";
199  for(int i=0; i<deviceList.length(); i++){
200    QString dev = deviceList[i]->device.section("/",-1);
201    if(DEBUG_MODE){ qDebug() << " - Check device:" << dev; }
202    int ni = nsd.indexOf(dev);
203    if(ni == -1){
204      //Device Removed
205      if(DEBUG_MODE){ qDebug() << " - Device no longer connected:" << dev; }
206      removeDevice(dev);
207      i--;
208    }else{
209      //Probe the device for validity if not currently mounted
210      if( !deviceList[i]->isMounted() ){
211        QString ja, jb, jc, jd; //junk variables
212        if( !DCheck->devInfo(dev,&ja,&jb,&jc,&jd) ){
213          if(DEBUG_MODE){ qDebug() << " - Device no longer valid:" << dev; }
214          //no longer valid device
215          removeDevice(dev);
216          i--;
217        }
218      }
219      nsd.removeAt(ni);
220    }
221  }
222  //Now Iterate through all available devices and probe them for validity
223  // (This should catch devices that do not "announce" their presence by creating a new device node)
224  for(int i=0; i<nsd.length(); i++){
225    //Check if it is a good device
226    QString dlabel, dtype, dfs, dsize; //additional output info
227    bool good = DCheck->devInfo(nsd[i],&dtype,&dlabel,&dfs,&dsize);
228    if(good){
229      //Now create a new entry for this device
230      bool added = addDevice(nsd[i],dlabel,dtype,dfs); 
231      //Show a message bubble
232      if(showPopup && added){ //make sure this is not shown for previously added devices
233        QString title = tr("New Device");
234        QString message = QString( tr("%1 can now be accessed")).arg(dlabel);
235        slotDisplayPopup(title, message, nsd[i]);
236      }
237    }
238  }
239 
240  //Run the disk space check if appropriate
241  if(useDiskWatcher && useDiskTimerDevd && showPopup){ diskWatcher->checkFS(); }
242}
243
244void MountTray::closeTray(){
245  qDebug() << "pc-mounttray: closing down";
246  //Kill the devd watching process
247  qDebug() << " -Shutting down DEVD watcher";
248  devdProc->disconnectFromServer();
249  qDebug() << " -Unmounting managed devices and mount points";
250  for(int i=0; i<deviceList.length(); i++){
251    deviceList[i]->cleanup();
252  }
253  //Close down the application
254  exit(0);
255}
256
257void MountTray::getInitialUsername(){
258  //Get the original user who started the tray app
259  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
260  //qDebug() << "System Environment:" << env.toStringList();
261  QString username = env.value( "LOGNAME" );
262  //qDebug() << "First attempt user detected:" << username;
263  if(username=="root"){
264    username = env.value( "SUDO_USER" ); //try this environment variable instead
265    //qDebug() << "Second attempt user detected:" << username;
266  }
267  if(username=="root" || username.isEmpty() ){
268   //attempt another method of determining the username
269   QStringList uList = pcbsd::Utils::runShellCommand("who");
270   if( uList.length() > 0 ){ 
271     username = uList[0].section(" ",0,0,QString::SectionSkipEmpty);
272     for(int i=0; i<uList.length(); i++){
273       if( !uList[i].section(" ",0,0,QString::SectionSkipEmpty).contains(username) ){
274         username = "root"; //too many users logged in; this method will not work
275         break;
276       }
277     }
278     //qDebug() << "Third attempt user detected:" << username;
279   }
280  }
281  if(username=="root"){
282    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") );
283    return;
284  }
285  USERNAME=username.simplified(); //set the global variable
286  if(DEBUG_MODE){ qDebug() << "-User detected:" << USERNAME; }
287}
288
289void MountTray::slotOpenMediaDir(){
290  openMediaDir(MOUNTDIR);
291}
292
293void MountTray::openMediaDir(QString dir){
294  if(MTINIT){ return; } //don't open the FM during program initialization
295  //Open the default file-manager to the directory listed
296  if(dir.isEmpty()){ dir = MOUNTDIR; }
297  if(!dir.endsWith("/")){ dir.append("/"); } //make sure the filemanager knows it is a directory
298  //Make sure we can setup user permissions
299  if(USERNAME=="root"){
300    qDebug() << "Cannot open filemanager with root permissions";
301    return;
302  }
303  //Open the default file manager to the given directory as that user
304  qDebug() << "Opening the media directory with user permissions";
305  QString cmd = "su -m "+USERNAME+" -c \'xdg-open \""+dir+"\"\' &";
306  if(DEBUG_MODE){ qDebug() << " -cmd:" << cmd; }
307  system( cmd.toUtf8() ); 
308}
309
310void MountTray::slotRescan(){
311  //Display a notification
312  qDebug() << "Re-scanning devices:";
313  slotDisplayPopup(tr("Please Wait"),tr("Rescanning devices attached to the system"));
314  //Rescan the device list for new devices
315  scanInitialDevices();
316  //Check that all the existing devices still exist
317  for(int i=0; i<deviceList.length(); i++){
318    deviceList[i]->updateItem();
319  }
320  //Run the disk check if appropriate
321  if(useDiskWatcher){ diskWatcher->checkFS(); }
322}
323
324void MountTray::slotOpenFSDialog(){
325  //Open up the Filesystem disk space monitoring dialog
326  diskDisplay = new FSDialog();
327  diskDisplay->show();
328}
329
330void MountTray::slotOpenSettings(){
331  //Stop the refresh timer on the watcher
332  diskWatcher->stop();
333  //Open up the settings window and apply changes as necessary
334  SettingsDialog *sdlg = new SettingsDialog();
335  sdlg->useDiskWatcher = useDiskWatcher;
336  sdlg->useDiskAutoTimer = useDiskTimerDevd;
337  sdlg->diskRefreshMS = diskTimerMaxMS;
338  sdlg->showDialog();
339  //Now parse the output and save if necessary
340  if(sdlg->SettingsChanged){
341    useDiskWatcher = sdlg->useDiskWatcher;
342    useDiskTimerDevd = sdlg->useDiskAutoTimer;
343    diskTimerMaxMS = sdlg->diskRefreshMS;
344    qDebug() << "INFO: Saving updated settings to file";
345    saveCurrentSettings(); //update the saved settings
346  }
347  //Now restart the disk watcher if enabled
348  if(useDiskWatcher){ diskWatcher->start(diskTimerMaxMS); }
349}
350
351void MountTray::slotOpenISO(){
352  //prompt for the user to select a file
353  QString file = QFileDialog::getOpenFileName( this, tr("Select ISO File"), QDir::homePath(), tr("ISO Files (*.iso)") );
354  if(file.isEmpty()){ return; } //cancelled
355  //check for available device node number /dev/md<number>
356  int num = 1;
357  while( QFile::exists("/dev/md"+QString::number(num)) ){ num++; }
358  //add it to the device tree (will automatically get picked up by the device detection method)
359  QString cmd = "mdconfig -a -f "+file+" -u "+QString::number(num);
360  system(cmd.toUtf8());
361}
362
363void MountTray::slotSingleInstance()
364{
365  trayIcon->show();
366}
367
368void MountTray::slotDisplayPopup(QString title, QString msg, QString device){
369  popupSave = device; //so we know what to do when it is clicked
370  //Display a popup bubble with the given message for 3 seconds
371  trayIcon->contextMenu()->hide(); //close the menu list
372  trayIcon->showMessage(title, msg , QSystemTrayIcon::NoIcon,3000 );
373}
374
375void MountTray::slotDisplayWarning(QString title, QString msg){
376  popupSave="FSCHECK";
377  //Display a popup bubble with the given message for 5 seconds
378  trayIcon->contextMenu()->hide(); //close the menu list
379  trayIcon->showMessage(title, msg , QSystemTrayIcon::Warning,5000 );
380}
381
382void MountTray::slotPopupClicked(){
383  //Check the saved variable for what to do with this popup
384  if(popupSave == "FSCHECK"){
385    //Open up the filesystem disk space UI
386    slotOpenFSDialog();
387  }else if(!popupSave.isEmpty()){
388    //Check if it is a currently valid device
389    if(!popupSave.startsWith(DEVICEDIR)){ popupSave.prepend(DEVICEDIR); }
390    for(int i=0; i<deviceList.length(); i++){
391      if( deviceList[i]->device == popupSave){
392        //See if the device is mounted
393        if(deviceList[i]->isMounted()){
394          //Open up the mountpoint directory
395          openMediaDir(deviceList[i]->mountpoint);
396        }else{
397          //Mount the device
398          deviceList[i]->mountItem();
399        }
400        break;
401      }
402    }
403  }
404
405}
406
407void MountTray::loadSavedSettings(){
408  //The saved settings file
409  QString filename = QDir::homePath()+"/.mounttray.settings";
410  //Set the defaults
411  useDiskWatcher=TRUE; useDiskTimerDevd=TRUE;
412  diskTimerMaxMS=3600000; //1 hour refresh timer
413  //Now load the file
414  QFile file(filename);
415  if(file.exists()){
416    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ 
417      qDebug() << "-Could not open settings file: using defaults";
418      return; 
419    }
420    QTextStream in(&file);
421    while(!in.atEnd()){
422      QString line = in.readLine();
423      if(!line.startsWith("#")){ //skip comment lines
424        QString var = line.section(")",0,0,QString::SectionSkipEmpty).simplified();
425        QString val = line.section(")",1,30,QString::SectionSkipEmpty).simplified();
426        if(var=="UseDiskSpaceMonitoring"){ 
427          if(val.toLower() == "true"){ useDiskWatcher = TRUE;}
428          else{ useDiskWatcher = FALSE; }
429        }else if(var=="UseDiskSpaceDevdTiming"){
430          if(val.toLower() == "true"){ useDiskTimerDevd = TRUE;}
431          else{ useDiskTimerDevd = FALSE; }     
432        }else if(var=="DiskSpaceTimingMaxMilliseconds"){
433          diskTimerMaxMS = val.toInt(); 
434        }
435      }
436    }
437    file.close();
438  }else{
439    qDebug() << "-Creating new settings file with defaults";
440    saveCurrentSettings();
441  }
442}
443
444void MountTray::saveCurrentSettings(){
445  //The saved settings file
446  QString filename = QDir::homePath()+"/.mounttray.settings";
447  //Now write the current values to the file
448  QFile file(filename);
449  if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
450    qDebug() << "ERROR: Could not open file to save settings:"<<filename;
451    return;
452  }
453  QTextStream out(&file);
454  out << "#pc-mounttray saved settings file\n";
455  out << "# DO NOT EDIT: Use the settings dialog in the application instead!!\n";
456  //Save the settings
457  out << "UseDiskSpaceMonitoring)";
458  if(useDiskWatcher){ out << "true\n";}
459  else{ out << "false\n"; }
460  out << "UseDiskSpaceDevdTiming)";
461  if(useDiskTimerDevd){ out << "true\n";}
462  else{ out << "false\n"; }
463  out << "DiskSpaceTimingMaxMilliseconds)"+QString::number(diskTimerMaxMS)+"\n";
464  //Now close the file
465  file.close();
466}
Note: See TracBrowser for help on using the repository browser.