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

9.1-release9.2-releasereleng/10.0releng/10.0.1releng/10.0.2
Last change on this file since d386893 was d386893, checked in by Ken Moore <ken@…>, 16 months ago

Get the mount-tray menu all cleaned up, and add the option to open up a settings window (settings dialog not implemented yet)

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