source: src-qt4/pc-mounttray/menuItem.cpp @ 03aedf0

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

Setup the pc-mounttray to allow for mounting a *.iso file via memory disk. This option is available under the "Load ISO File" option in the menu. Once the ISO file is unmounted, the memory disk is also detached from the system.

  • Property mode set to 100644
File size: 13.1 KB
Line 
1#include <pcbsd-utils.h>
2#include "menuItem.h"
3
4
5MenuItem::MenuItem(QWidget* parent, QString newdevice, QString newlabel, QString newtype, QString newfs) : QWidgetAction(parent)
6{
7  AMFILE= QDir::homePath() + "/.pc-automounttray";   //File to save/load all the devices to be automounted
8  //Set the device info variables
9  if( !newdevice.startsWith(DEVICEDIR) ){ newdevice.prepend(DEVICEDIR); }
10  device = newdevice;
11  devType = newtype;
12  filesystem = newfs;
13  //Create the layout
14  QGridLayout* layout = new QGridLayout();
15  QHBoxLayout* hlayout = new QHBoxLayout();
16  //Create the gui items
17  devLabel = new QLabel;
18    devLabel->setToolTip(device);
19    devLabel->setText(newlabel);
20   
21  devIcon = new QLabel;
22    devIcon->setToolTip(device);
23  currentSpace = new QProgressBar;
24    currentSpace->setMinimum(0);
25  pushMount = new QPushButton;
26  checkAutomount = new QCheckBox;
27    checkAutomount->setChecked( checkSavedAutoMount() );
28    checkAutomount->setText( tr("Auto-mount this device") );
29  //Add the widgets to the layout
30  layout->addWidget(devIcon,0,0,3,1);   
31  hlayout->addWidget(devLabel);
32  hlayout->addWidget(pushMount);
33  layout->addLayout(hlayout,0,1);
34  layout->addWidget(currentSpace,1,1);
35  layout->addWidget(checkAutomount,2,1);
36  //Set the layout
37  frame = new QWidget();
38  frame->setLayout(layout);
39  this->setDefaultWidget(frame);
40
41  //Connect the signals/slots
42  connect(pushMount,SIGNAL(clicked()), this, SLOT(slotMountClicked()));
43  connect(checkAutomount,SIGNAL(toggled(bool)),this,SLOT(slotAutoMountToggled(bool)));
44
45  //Setup the device Icon based on the type
46  if(devType == "USB"){ devIcon->setPixmap(QPixmap(":icons/usb.png")); }
47  else if(devType == "SATA"){ devIcon->setPixmap(QPixmap(":icons/harddrive.png")); }
48  else if(devType == "SD"){ devIcon->setPixmap(QPixmap(":icons/sdcard.png")); }
49  else if(devType == "CD9660"){ devIcon->setPixmap(QPixmap(":icons/dvd.png")); }
50  else if(devType == "ISO"){devIcon->setPixmap(QPixmap(":icons/dvd.png")); }
51  //Start the automount procedure if necessary
52  if(checkAutomount->isChecked() || devType=="ISO"){
53    QTimer::singleShot(500,this,SLOT( slotMountClicked() ));
54  }
55  //Update the Item based upon current device status
56  updateItem();
57
58}
59
60MenuItem::~MenuItem(){
61}
62
63/*
64  PUBLIC FUNCTIONS
65*/
66
67void MenuItem::updateItem(){
68  //Update the item visuals, based upon current device status
69  if( isConnected() ){
70    if( isMounted() ){
71      if(mountpoint.isEmpty()){
72        //detect the current mountpoint
73        QString output = pcbsd::Utils::runShellCommandSearch("mount",device);
74        mountpoint = output.section(" on ",1,1).section(" (",0,0).replace(" ","-");
75      }
76      devIcon->setEnabled(TRUE);  //Make the icon full color
77      devIcon->setToolTip(device+"\n"+QString(tr("Mounted at %1")).arg(mountpoint));
78      pushMount->setText(tr("Eject"));
79      pushMount->setIcon(QIcon(":icons/eject.png"));
80      if(devType != "ISO"){ checkAutomount->setVisible(TRUE); }
81      else{ checkAutomount->setVisible(FALSE); }
82    }else{       
83      devIcon->setEnabled(FALSE); //Grey out the icon if not mounted
84      devIcon->setToolTip(device);
85      pushMount->setText(tr("Mount"));
86      pushMount->setIcon(QIcon(":icons/mount.png"));
87      checkAutomount->setVisible(FALSE);
88    }
89  }else{
90    emit itemRemoved(device);
91    return;
92  }
93  //Set visibility and sizes on progressbar
94  updateSizes();
95}
96       
97//Getters
98QString MenuItem::getDeviceName(){
99  return devLabel->text();     
100}
101       
102//Device information
103bool MenuItem::isConnected(){
104  if( QFile::exists(device) ){ return TRUE; }
105  else{ return FALSE; }
106}
107
108bool MenuItem::isMounted(){
109  //Check if device is mounted
110  QStringList chk = pcbsd::Utils::runShellCommand("mount");
111  bool mounted=false;
112  for(int i=0; i<chk.length(); i++){
113    mounted = chk[i].contains(device) || chk[i].contains(devLabel->text()) || chk[i].contains(devLabel->text().replace(" ","-"));
114    if(mounted){ 
115      //Save the mountpoint if it is mounted
116      mountpoint = chk[i].section(" on ",1,10).section("(",0,0).simplified();
117      break; 
118    }
119  }
120  return mounted;
121}
122
123//Cleanup function
124void MenuItem::cleanup(){
125  if( isMounted() ){
126    unmountItem(); //unmount and remove mountpoint
127  }else{
128    //Just check for mountpoint removal
129    if(QFile::exists(mountpoint)){
130      qDebug() << "Removing old mountpoint:" << mountpoint;
131      QString output = pcbsd::Utils::runShellCommand("rmdir "+mountpoint).join(" ");
132      if(!output.isEmpty()){ qDebug() << " -Error:" <<output; }
133    }
134  }
135}
136/*
137  PRIVATE FUNCTIONS
138*/
139void MenuItem::slotMountClicked(){
140  if( isConnected() ){
141    if( !isMounted() ){
142      mountItem();
143    }else{
144      unmountItem(); 
145    }
146  }else{
147    emit itemRemoved(device);     
148  }
149  updateItem();
150}
151
152void MenuItem::slotAutoMountToggled(bool checked){
153  qDebug() << "Auto-mount toggled for:" << device << checked;
154  QString entry = devLabel->text()+":::"+devType+":::"+filesystem;
155  if(checked){
156    //Add this entry to the auto-mount file
157    QString cmd = "echo \""+entry+"\" >> "+AMFILE;
158    system( cmd.toUtf8() );
159  }else{
160    //Remove this entry from the automount file
161    QString tmpFile = AMFILE+".tmp";
162    QString cmd = "cat "+AMFILE+" | grep -v "+entry+" > "+tmpFile+"; mv "+tmpFile+" "+AMFILE;
163    system( cmd.toUtf8() );
164  }
165}
166
167bool MenuItem::checkSavedAutoMount(){
168  if(QFile::exists(AMFILE)){
169    QString cmd = "cat "+AMFILE;
170    QString search = devLabel->text() +" "+ devType +" "+ filesystem;
171    QString chk = pcbsd::Utils::runShellCommandSearch(cmd, search);
172    if( chk.isEmpty() ){ return FALSE; }
173    else{ return TRUE; }
174  }else{
175    return FALSE;
176  }
177}
178
179void MenuItem::mountItem(){
180  //Mount the device
181 
182  //Create the full path to the mountpoint
183  QString deviceName = devLabel->text();
184  QString mntpoint = MOUNTDIR + deviceName.replace(" ","-"); //take into account spaces in the name
185
186  //Create the fileystem specific command for mounting
187  QString fstype;
188  QString fsopts="";
189  if( filesystem == "FAT" ){ fstype = "mount -t msdosfs"; fsopts = "-o large,-m=644,-M=777"; }
190  else if(filesystem == "NTFS"){ fstype = "ntfs-3g"; }
191  else if(filesystem == "EXT"){ fstype = "mount -t ext2fs"; }
192  else if(filesystem == "CD9660"){ fstype = "mount -t cd9660"; }
193  else if(filesystem == "UFS"){ fstype = "mount -t ufs"; }
194  else if(filesystem == "REISERFS"){ fstype = "mount -t reiserfs"; }
195  else if(filesystem == "XFS"){ fstype = "mount -t xfs"; }
196  else{
197    qDebug() << "Unknown device filesystem:" << device << filesystem << " attempting mount_auto command";
198    fstype = "mount_auto";
199    //QMessageBox::warning(this,tr("Unknown Device Filesystem"),tr("The filesystem on this device is unknown and cannot be mounted at this time") );
200    //return FALSE;
201  }
202  //Make sure the mntpoint is available
203  QDir mpd(mntpoint);
204  if(mpd.exists()){
205    //Remove the existing directory (will work only if it is empty)
206    mpd.cdUp();
207    mpd.rmdir(mntpoint);
208  }
209  //Prepare the commands to run
210  QString cmd1 = "mkdir " + mntpoint;
211  QString cmd2 = fstype + " " +fsopts + " " + device + " " + mntpoint;
212  QString cmd3 = "chmod 777 " + mntpoint; //to set full user/root access
213 
214  qDebug() << "Mounting device" << device << "on" << mntpoint << "("<<filesystem<<")";
215  if(DEBUG_MODE){ qDebug() << " - command:" << cmd2; }
216 
217  bool ok = FALSE;
218  QString result, title;
219  //Run the mounting commands
220  QStringList output = pcbsd::Utils::runShellCommand(cmd1);
221  if( output.join(" ").simplified().isEmpty() ){
222    //directory created, run the next commands
223    system(cmd3.toUtf8()); //set directory permissions before mounting device
224    output = pcbsd::Utils::runShellCommand(cmd2);
225    if( output.join(" ").simplified().isEmpty() ){
226      title = tr("Success");
227      result = QString( tr("%1 mounted at %2") ).arg(deviceName).arg(mntpoint);
228      ok = TRUE;
229    }else{
230      qDebug() << "pc-mounttray: Error mounting device:" << device;
231      qDebug() << " - Error message:" << output;
232      title = QString( tr("Error mounting %1 at %2") ).arg(deviceName).arg(mntpoint);
233      result =  output.join(" ");
234      //Remove the mount point just created
235      pcbsd::Utils::runShellCommand("rmdir "+mntpoint);
236    }
237  }else{
238    qDebug() << "pc-mounttray: Error creating mountpoint:" << mntpoint;
239    qDebug() << " - Error message:" << output;
240    title = QString( tr("Error mounting %1") ).arg(deviceName);
241    result =  QString( tr("Could not create mount point at %1") ).arg(mntpoint);
242  }
243  //Output the proper signals depending upon success
244  if(ok){
245    emit itemMounted(mntpoint);
246    mountpoint = mntpoint;
247  }else{
248    mountpoint.clear();
249  }
250  if( !checkAutomount->isChecked() ){
251    emit newMessage(title, result); //suppress the output message if it was automounted
252  }
253 
254}
255
256void MenuItem::unmountItem(){
257  //Unmount the device
258       
259  //Check to see if the current mountpoint exists or if it is somewhere else
260  if( !QFile::exists(mountpoint) ){
261    if( !isMounted() ){  //double check that it is actually mounted (and fix the mountpoint)
262      //it is not mounted to begin with
263      return;
264    }
265  }
266  //Make sure there are no spaces in the mounpoint path
267  QString cmd1 = "umount \"" + mountpoint +"\"";
268  QString cmd2 = "rmdir \"" + mountpoint +"\"";
269  qDebug() << "Unmounting device from" << mountpoint;
270  //Run the commands
271  QStringList output;
272  QString result, title;
273  bool ok = FALSE;
274  output = pcbsd::Utils::runShellCommand(cmd1);
275  if(output.join(" ").simplified().isEmpty()){
276    //unmounting successful, remove the mount point directory
277    output = pcbsd::Utils::runShellCommand(cmd2);
278    if(!output.join(" ").simplified().isEmpty()){
279      qDebug() << "pc-mounttray: Error removing mountpoint:" << mountpoint;
280      qDebug() << " - Error message:" << output;
281    }
282    ok = TRUE;
283    title = QString( tr("%1 has been successfully unmounted.") ).arg(devLabel->text());
284    if(devType == "ISO"){
285      result = tr("The ISO file has been completely detached from the system.");
286    }else{
287      result = tr("It is now safe to remove the device");
288    }
289  }else{
290    qDebug() << "pc-mounttray: Error unmounting mountpoint:" << mountpoint;
291    qDebug() << " - Error message:" << output;
292    title = QString( tr("Error: %1 could not be unmounted") ).arg(devLabel->text());
293    result = output.join(" ");
294  }
295  //emit the proper signals
296  if(ok){
297    mountpoint.clear();
298    if(devType=="ISO" && device.section("/",-1).startsWith("md") ){
299      //Get the md number
300      QString num = device.section("/md",-1).simplified();
301      //also remove the MD device from the system using "mdconfig"
302      qDebug() << "Detaching Memory Disk:" << num;
303      QString cmd = "mdconfig -d -u "+num;
304      system(cmd.toUtf8());
305    }
306    emit itemUnmounted(device);
307  }
308  emit newMessage(title, result);
309}
310
311void MenuItem::updateSizes(){
312  //this method only works if the device is currently mounted
313  bool ok = FALSE;
314  if(isMounted()){
315    QString cmd = "df \""+mountpoint+"\"";
316    QStringList output = systemCMD(cmd); //make sure we use the one with a 1K blocksize
317    if(output.length() > 1){
318      //parse the output (1K blocks) and save them
319      QString line = output[1].replace("\t"," ");
320      //qDebug() << "df output:" << output << cmd;
321      maxSize = line.section(" ",1,1,QString::SectionSkipEmpty).simplified();
322      currentSize = line.section(" ",2,2,QString::SectionSkipEmpty).simplified();
323      ok=TRUE;
324    }else{
325      maxSize.clear();
326      currentSize.clear();         
327    }
328  }else{
329    maxSize.clear();
330    currentSize.clear();
331  }
332  //Now setup the display progressbar display
333  if(ok){
334    currentSpace->setMaximum( maxSize.toInt() );
335    currentSpace->setValue( currentSize.toInt() );
336    currentSpace->setVisible(TRUE);
337    //display the actual size available in the tooltip
338    QString diskAvailable = getSizeDisplay( maxSize.toInt() - currentSize.toInt() );
339    //qDebug() << "MaxSize:" << maxSize << maxSize.toInt();
340    //qDebug() << "CurrentSize:" << currentSize << currentSize.toInt();
341    //qDebug() << "Disk Available:" << diskAvailable;
342    currentSpace->setToolTip( QString( tr("%1 of disk space available") ).arg(diskAvailable) );
343  }else{
344    currentSpace->setVisible(FALSE);
345  }
346       
347}
348
349QString MenuItem::getSizeDisplay(int kb){
350  //convert from KB to human readable output
351  if( kb > 1048576 ){ //display in GB
352    return QString::number( double(int( (kb*100)/1048576 )/100.0) )+"GB";
353  }else if( kb > 1024 ){ //display in MB
354    return QString::number( double(int( (kb*100)/1024 )/100.0) )+"MB";   
355  }else{ //display in KB
356    return QString::number( kb )+"KB";   
357  }
358       
359}
360
361QStringList MenuItem::systemCMD(QString command){ 
362   QProcess p;
363   QString outstr;
364   //Make sure we use the system environment to properly read system variables, etc.
365   QProcessEnvironment penv = QProcessEnvironment::systemEnvironment();
366   penv.insert("BLOCKSIZE","K"); //make sure we use a 1KB block size
367   p.setProcessEnvironment(penv);
368   //Merge the output channels to retrieve all output possible
369   p.setProcessChannelMode(QProcess::MergedChannels);   
370   p.start(command);
371   while(p.state()==QProcess::Starting || p.state() == QProcess::Running){
372     p.waitForFinished(200);
373     QCoreApplication::processEvents();
374   }
375   QString tmp = p.readAllStandardOutput();
376   outstr.append(tmp);
377   if(outstr.endsWith("\n")){outstr.chop(1);} //remove the newline at the end
378   QStringList out = outstr.split("\n");
379   return out;
380}
Note: See TracBrowser for help on using the repository browser.