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

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