1 //===========================================
2 //  Lumina-DE source code
3 //  Copyright (c) 2015, Ken Moore
4 //  Available under the 3-clause BSD license
5 //  See the LICENSE file for full details
6 //===========================================
7 #include <QtConcurrent/QtConcurrentRun>
8 #include "MainUI.h"
9 #include "ui_MainUI.h"
10 
11 #include <QVideoFrame>
12 #include <QFileDialog>
13 #include <QMessageBox>
14 
15 #include <LUtils.h>
16 #include <LuminaOS.h>
17 
MainUI()18 MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){
19   ui->setupUi(this); //load the designer form
20   canwrite = false;
21   terminate_thread = false;
22   INFO = new LFileInfo();
23   UpdateIcons(); //Set all the icons in the dialog
24   SetupConnections();
25 
26   //Disable buttons that are not working yet
27   //ui->actionOpen_File->setVisible(false);
28   //ui->actionOpen_Directory->setVisible(false);
29   //ui->menuSave_As->setEnabled(false);
30 }
31 
~MainUI()32 MainUI::~MainUI(){
33   terminate_thread = true;
34   this->close();
35 }
36 
37 //=============
38 //      PUBLIC
39 //=============
LoadFile(QString path,QString type)40 void MainUI::LoadFile(QString path, QString type){
41 
42   //Do the first file information tab
43   qDebug() << "Load File:" << path << type;
44   INFO = new LFileInfo(path);
45   //First load the general file information
46   if(!INFO->filePath().isEmpty()){
47     SyncFileInfo();
48   }else{
49     SetupNewFile();
50   }
51 }
52 
UpdateIcons()53 void MainUI::UpdateIcons(){
54 
55 }
56 
57 //==============
58 //     PRIVATE
59 //==============
ReloadAppIcon()60 void MainUI::ReloadAppIcon(){
61   //qDebug() << "Reload App Icon:";
62   ui->label_xdg_icon->setPixmap( LXDG::findIcon(ui->line_xdg_icon->text(),"").pixmap(64,64) );
63   //qDebug() << "Check Desktop File entry";
64   if(INFO->iconfile()!=ui->line_xdg_icon->text()){
65     xdgvaluechanged();
66   }
67   //qDebug() << "Done with app icon";
68 }
69 
stopDirSize()70 void MainUI::stopDirSize(){
71   if(sizeThread.isRunning()){
72     terminate_thread = true;
73     sizeThread.waitForFinished();
74     QApplication::processEvents(); //throw away any last signals waiting to be processed
75   }
76   terminate_thread = false;
77 }
78 
GetDirSize(const QString dirname) const79 void MainUI::GetDirSize(const QString dirname) const {
80   const quint16 update_frequency = 2000; //For reducing the number of folder_size_changed calls
81   quint64 filesize = 0;
82   quint64 file_number = 0;
83   quint64 dir_number = 1;
84   QDir folder(dirname);
85   QFileInfoList file_list;
86   QString dir_name;
87   QList<QString> head;
88   folder.setFilter(QDir::Hidden|QDir::AllEntries|QDir::NoDotAndDotDot);
89   file_list = folder.entryInfoList();
90   for(int i=0; i<file_list.size(); ++i) {
91     if(terminate_thread)
92         break;
93     if(file_list[i].isDir() && !file_list[i].isSymLink()) {
94       ++dir_number;
95       head.prepend(file_list[i].absoluteFilePath());
96     }
97     else
98       ++file_number;
99     if(!file_list[i].isSymLink())
100       filesize += file_list[i].size();
101   }
102   while(!head.isEmpty()) {
103     if(terminate_thread)
104       break;
105     dir_name = head.takeFirst();
106     if(!folder.cd(dir_name)) {
107       qDebug() << "The folder " << dir_name << " doesn't exist";
108       continue;
109     }
110     file_list = folder.entryInfoList();
111     for(int i=0; i<file_list.size(); ++i) {
112       if(file_list[i].isDir() && !file_list[i].isSymLink()) {
113         ++dir_number;
114         head.prepend(file_list[i].absoluteFilePath());
115       }
116       else
117         ++file_number;
118       if(!file_list[i].isSymLink())
119         filesize += file_list[i].size();
120       if(i%update_frequency == 0)
121         emit folder_size_changed(filesize, file_number, dir_number, false);
122     }
123   }
124   emit folder_size_changed(filesize, file_number, dir_number, true);
125 }
126 
SyncFileInfo()127 void MainUI::SyncFileInfo(){
128   qDebug() << "Sync File Info";
129   stopDirSize();
130   if(INFO->filePath().isEmpty()){ return; }
131   if(INFO->exists()){ canwrite = INFO->isWritable(); }
132   else{
133     //See if the containing directory can be written
134     QFileInfo chk(INFO->absolutePath());
135     canwrite = (chk.isDir() && chk.isWritable());
136   }
137     ui->label_file_name->setText( INFO->fileName() );
138     ui->label_file_mimetype->setText( INFO->mimetype() );
139     if(!INFO->isDir()){ ui->label_file_size->setText( LUtils::BytesToDisplaySize( INFO->size() ) ); }
140     else {
141       ui->label_file_size->setText(tr("---Calculating---"));
142       sizeThread = QtConcurrent::run(this, &MainUI::GetDirSize, INFO->absoluteFilePath());
143     }
144     ui->label_file_owner->setText(INFO->owner());
145     ui->label_file_group->setText(INFO->group());
146     ui->label_file_created->setText( INFO->birthTime().toString(Qt::SystemLocaleLongDate) );
147     ui->label_file_modified->setText( INFO->lastModified().toString(Qt::SystemLocaleLongDate) );
148     //Get the file permissions
149     QString perms;
150     if(INFO->isReadable() && INFO->isWritable()){ perms = tr("Read/Write"); }
151     else if(INFO->isReadable()){ perms = tr("Read Only"); }
152     else if(INFO->isWritable()){ perms = tr("Write Only"); }
153     else{ perms = tr("No Access"); }
154     ui->label_file_perms->setText(perms);
155     //Now the special "type" for the file
156     QString ftype;
157     if(INFO->suffix().toLower()=="desktop"){ ftype = tr("XDG Shortcut"); }
158     else if(INFO->isDir()){ ftype = tr("Directory"); }
159     else if(INFO->isExecutable()){ ftype = tr("Binary"); }
160     else{ ftype = INFO->suffix().toUpper(); }
161     if(INFO->isHidden()){ ftype = QString(tr("Hidden %1")).arg(ftype); }
162     ui->label_file_type->setText(ftype);
163 
164     //Now load the icon for the file
165     if(INFO->isImage()){
166       QPixmap pix(INFO->absoluteFilePath());
167       ui->label_file_icon->setPixmap(pix.scaledToHeight(64));
168       ui->label_file_size->setText( ui->label_file_size->text()+" ("+QString::number(pix.width())+" x "+QString::number(pix.height())+" px)" );
169     }else if(INFO->isVideo()){
170       ui->label_file_icon->hide();
171       LVideoLabel *mediaLabel = new LVideoLabel(INFO->absoluteFilePath(), true, ui->tab_file);
172       mediaLabel->setFixedSize(64,64);
173       ui->formLayout->replaceWidget(ui->label_file_icon, mediaLabel);
174     }else{
175       ui->label_file_icon->setPixmap( LXDG::findIcon( INFO->iconfile(), "unknown").pixmap(QSize(64,64)) );
176     }
177 
178   //qDebug() << "Check XDG Info:"
179   //qDebug() << INFO->isDesktopFile() << type;
180   syncXdgStruct(INFO->XDG());
181   //Make sure the right tabs are available
182   if(ui->tabWidget->indexOf(ui->tab_file)<0){
183     //qDebug() << "Add File Info Tab";
184     ui->tabWidget->insertTab(0, ui->tab_file, tr("File Information"));
185   }
186   if(!INFO->isDesktopFile()){
187     if(ui->tabWidget->indexOf(ui->tab_deskedit)>=0){
188       ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_deskedit) );
189     }
190   }else if(ui->tabWidget->indexOf(ui->tab_deskedit)<0){
191     ui->tabWidget->addTab( ui->tab_deskedit, tr("XDG Shortcut") );
192   }
193   ui->tabWidget->setCurrentIndex(ui->tabWidget->indexOf(ui->tab_file) );
194   SyncZfsInfo();
195 }
196 
SyncZfsInfo()197 void MainUI::SyncZfsInfo(){
198   bool showtab = false;
199   if(INFO->zfsPool().isEmpty()){
200     //Not on a ZFS pool - hide the tab if it is available
201     showtab = false;
202   }else{
203     qDebug() << "Is a ZFS Dataset:" << INFO->isZfsDataset();
204     ui->label_zfs_pool->setText(INFO->zfsPool());
205     if(INFO->isZfsDataset()){
206       ui->tree_zfs_props->clear();
207       QJsonObject props = INFO->zfsProperties();
208       QStringList keys = props.keys();
209       for(int i=0; i<keys.length(); i++){
210         ui->tree_zfs_props->addTopLevelItem( new QTreeWidgetItem(QStringList() << keys[i] << props.value(keys[i]).toObject().value("value").toString() << props.value(keys[i]).toObject().value("source").toString() ) );
211         ui->tree_zfs_props->resizeColumnToContents(0);
212         ui->tree_zfs_props->resizeColumnToContents(1);
213       }
214       ui->tree_zfs_props->setVisible(!keys.isEmpty());
215       showtab = !keys.isEmpty();
216     }else{
217       ui->tree_zfs_props->setVisible(false);
218     }
219     QStringList snaps = INFO->zfsSnapshots();
220     ui->tree_zfs_snaps->clear();
221     for(int i=0; i<snaps.length(); i++){
222       QFileInfo finfo(snaps[i].section("::::",1,-1));
223       ui->tree_zfs_snaps->addTopLevelItem( new QTreeWidgetItem(QStringList() << snaps[i].section("::::",0,0) << finfo.birthTime().toString(Qt::SystemLocaleShortDate) << finfo.lastModified().toString(Qt::SystemLocaleShortDate) ) );
224       ui->tree_zfs_snaps->resizeColumnToContents(0);
225     }
226     ui->tree_zfs_snaps->setVisible(!snaps.isEmpty());
227     showtab = showtab || !snaps.isEmpty();
228   }
229   if(showtab){
230     //Make sure the tab is visible
231     if(ui->tabWidget->indexOf(ui->tab_zfs)<0){
232       ui->tabWidget->addTab( ui->tab_zfs, tr("Advanced") );
233     }
234   }else{
235     //hide the tab if it is visible right now
236     if(ui->tabWidget->indexOf(ui->tab_zfs)>=0){
237       ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_zfs) );
238     }
239   }
240 }
241 
SetupNewFile()242 void MainUI::SetupNewFile(){
243   //qDebug() << "Setup New File";
244   if(!INFO->filePath().isEmpty()){
245     INFO = new LFileInfo();
246   }
247   stopDirSize();
248   canwrite = true; //can always write a new file
249   syncXdgStruct(INFO->XDG());
250   //Make sure the right tabs are enabled
251   if(ui->tabWidget->indexOf(ui->tab_file)>=0){
252     ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_file) );
253   }
254   if(ui->tabWidget->indexOf(ui->tab_deskedit)<0){
255     //qDebug() << "Adding the deskedit tab";
256     ui->tabWidget->addTab(ui->tab_deskedit, tr("XDG Shortcut"));
257   }
258   //Not on a ZFS pool - hide the tab if it is available
259   if(ui->tabWidget->indexOf(ui->tab_zfs)>=0){
260     ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_zfs) );
261   }
262   ui->tabWidget->setCurrentIndex(ui->tabWidget->indexOf(ui->tab_deskedit) );
263 }
264 
syncXdgStruct(XDGDesktop * XDG)265 void MainUI::syncXdgStruct(XDGDesktop *XDG){
266   bool cleanup = false;
267   if(XDG==0){ XDG = new XDGDesktop(); cleanup = true;} //make sure nothing crashes
268   if(XDG->type == XDGDesktop::APP){
269       ui->line_xdg_command->setText(XDG->exec);
270       ui->line_xdg_wdir->setText(XDG->path);
271       ui->check_xdg_useTerminal->setChecked( XDG->useTerminal );
272       ui->check_xdg_startupNotify->setChecked( XDG->startupNotify );
273     }else if(XDG->type==XDGDesktop::LINK){
274       //Hide the options that are unavailable for links
275       //Command  line (exec)
276       ui->line_xdg_command->setVisible(false);
277       ui->tool_xdg_getCommand->setVisible(false);
278       ui->lblCommand->setVisible(false);
279       //Options
280       ui->lblOptions->setVisible(false);
281       ui->check_xdg_useTerminal->setVisible(false);
282       ui->check_xdg_startupNotify->setVisible(false);
283       //Now load the variables for this type of shortcut
284       ui->lblWorkingDir->setText(tr("URL:"));
285       ui->line_xdg_wdir->setText( XDG->url );
286       ui->tool_xdg_getDir->setVisible(false); //the dir selection button
287     }
288     ui->line_xdg_name->setText(XDG->name);
289     ui->line_xdg_comment->setText(XDG->comment);
290     ui->line_xdg_icon->setText( XDG->icon );
291     ReloadAppIcon();
292     ui->actionSave_Shortcut->setVisible(true);
293     ui->actionSave_Shortcut->setEnabled(false);
294   if(cleanup){ delete XDG; }
295   checkXDGValidity();
296 }
297 
saveFile(QString path)298 bool MainUI::saveFile(QString path){
299   //qDebug() << "Request save file:" << path;
300   XDGDesktop *XDG = INFO->XDG();
301   if(XDG==0){ XDG = new XDGDesktop(); }
302   if(XDG->type == XDGDesktop::BAD){ XDG->type = XDGDesktop::APP; }
303   //Update the file path in the data structure
304   XDG->filePath = path;
305   //Now change the structure
306   XDG->name = ui->line_xdg_name->text();
307   XDG->genericName = ui->line_xdg_name->text().toLower();
308   XDG->comment = ui->line_xdg_comment->text();
309   XDG->icon = ui->line_xdg_icon->text();
310   //Now do the type-specific fields
311   if(XDG->type == XDGDesktop::APP){
312     XDG->exec = ui->line_xdg_command->text();
313     XDG->tryexec = ui->line_xdg_command->text().section(" ",0,0); //use the first word/binary for the existance check
314     XDG->path = ui->line_xdg_wdir->text(); //working dir/path
315     XDG->useTerminal = ui->check_xdg_useTerminal->isChecked();
316     XDG->startupNotify = ui->check_xdg_startupNotify->isChecked();
317   }else if(XDG->type==XDGDesktop::LINK){
318     XDG->url = ui->line_xdg_wdir->text(); //we re-used this field
319   }
320   //Clear any info which this utility does not support at the moment
321   XDG->actionList.clear();
322   XDG->actions.clear();
323   //Now save the structure to file
324   //qDebug() << "Saving File:" << XDG->filePath;
325   return XDG->saveDesktopFile(true); //Try to merge the file/structure as necessary
326 }
327 
findOpenDirFile(bool isdir)328 QString MainUI::findOpenDirFile(bool isdir){
329   static QList<QUrl> urls;
330   if(urls.isEmpty()){
331     urls << QUrl::fromLocalFile("/");
332     QStringList dirs = QString(getenv("XDG_DATA_DIRS")).split(":");
333     for(int i=0; i<dirs.length(); i++){
334       if(QFile::exists(dirs[i]+"/applications")){ urls << QUrl::fromLocalFile(dirs[i]+"/applications"); }
335     }
336     //Now do the home-directory folders
337     urls << QUrl::fromLocalFile(QDir::homePath());
338     QString localapps = QString(getenv("XDG_DATA_HOME"))+"/applications";
339     if(QFile::exists(localapps)){ urls << QUrl::fromLocalFile(localapps); }
340   }
341   static QString lastdir = QDir::homePath();
342   QFileDialog dlg(this);
343   dlg.setAcceptMode(QFileDialog::AcceptOpen);
344   dlg.setFileMode( isdir ? QFileDialog::Directory : QFileDialog::ExistingFiles );
345   dlg.setOptions(QFileDialog::ReadOnly | QFileDialog::HideNameFilterDetails);
346   dlg.setViewMode(QFileDialog::Detail);
347   dlg.setSidebarUrls( urls );
348   dlg.setDirectory(lastdir);
349   if(!dlg.exec() ){ return ""; } //cancelled
350   if(dlg.selectedFiles().isEmpty()){ return ""; }
351   QString path = dlg.selectedFiles().first();
352   //Update the last used directory
353   if(isdir){ lastdir = path; } //save this for next time
354   else{ lastdir = path.section("/",0,-2); }
355   //return the path
356   return path;
357 }
358 
359 
360 // Initialization procedures
SetupConnections()361 void MainUI::SetupConnections(){
362   connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(closeApplication()) );
363   connect(ui->actionSave_Shortcut, SIGNAL(triggered()), this, SLOT(save_clicked()) );
364   connect(ui->actionLocal_Shortcut, SIGNAL(triggered()), this, SLOT(save_as_local_clicked()) );
365   connect(ui->actionRegister_Shortcut, SIGNAL(triggered()), this, SLOT(save_as_register_clicked()) );
366   connect(ui->actionNew_Shortcut, SIGNAL(triggered()), this, SLOT(SetupNewFile()) );
367   connect(ui->actionOpen_File, SIGNAL(triggered()), this, SLOT(open_file_clicked()) );
368   connect(ui->actionOpen_Directory, SIGNAL(triggered()), this, SLOT(open_dir_clicked()) );
369   connect(ui->line_xdg_command, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) );
370   connect(ui->line_xdg_comment, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) );
371   connect(ui->line_xdg_icon, SIGNAL(textChanged(QString)), this, SLOT(ReloadAppIcon()) );
372   connect(ui->tool_xdg_getCommand, SIGNAL(clicked()), this, SLOT(getXdgCommand()) );
373   connect(ui->line_xdg_name, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) );
374   connect(ui->line_xdg_wdir, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) );
375   connect(ui->check_xdg_useTerminal, SIGNAL(clicked()), this, SLOT(xdgvaluechanged()) );
376   connect(ui->check_xdg_startupNotify, SIGNAL(clicked()), this, SLOT(xdgvaluechanged()) );
377   connect(this, SIGNAL(folder_size_changed(quint64, quint64, quint64, bool)), this, SLOT(refresh_folder_size(quint64, quint64, quint64, bool)));
378 }
379 
380 //UI Buttons
closeApplication()381 void MainUI::closeApplication(){
382   terminate_thread = true;
383   if(ui->actionSave_Shortcut->isEnabled()){
384     //Still have unsaved changes
385     //TO-DO - prompt for whether to save the changes
386   }
387   this->close();
388 }
389 
save_clicked()390 void MainUI::save_clicked(){
391   //Save all the xdg values into the structure
392   QString filePath = INFO->filePath();
393   if( !filePath.isEmpty() && !INFO->isDesktopFile() ){ return; }
394   if(filePath.isEmpty() || !canwrite){
395     //Need to prompt for where to save the file and what to call it
396     QString appdir = QString(getenv("XDG_DATA_HOME"))+"/applications/";
397     if(!QFile::exists(appdir)){ QDir dir; dir.mkpath(appdir); }
398     filePath = QFileDialog::getSaveFileName(this, tr("Save Application File"), appdir, tr("XDG Shortcuts (*.desktop)") );
399     if(filePath.isEmpty()){ return; }
400     if(!filePath.endsWith(".desktop")){ filePath.append(".desktop"); }
401   }
402   //qDebug() << " -Try Saving File:" << filePath;
403   bool saved = saveFile(filePath);
404   //qDebug() << "File Saved:" << saved;
405   ui->actionSave_Shortcut->setEnabled( !saved );
406   if(saved){
407     //Re-load the file info
408     LoadFile(filePath);
409   }
410 }
411 
save_as_local_clicked()412 void MainUI::save_as_local_clicked(){
413   QString filePath = QFileDialog::getSaveFileName(this, tr("Save Application File"), QDir::homePath(), tr("XDG Shortcuts (*.desktop)") );
414     if(filePath.isEmpty()){ return; }
415     if(!filePath.endsWith(".desktop")){ filePath.append(".desktop"); }
416 
417   //qDebug() << " -Try Saving File:" << filePath;
418   bool saved = saveFile(filePath);
419   //qDebug() << "File Saved:" << saved;
420   ui->actionSave_Shortcut->setEnabled( !saved );
421   if(saved){
422     //Re-load the file info
423     LoadFile(filePath);
424   }
425 }
426 
save_as_register_clicked()427 void MainUI::save_as_register_clicked(){
428   QString appdir = QString(getenv("XDG_DATA_HOME"))+"/applications/";
429     if(!QFile::exists(appdir)){ QDir dir; dir.mkpath(appdir); }
430   QString filePath = QFileDialog::getSaveFileName(this, tr("Save Application File"), appdir, tr("XDG Shortcuts (*.desktop)") );
431     if(filePath.isEmpty()){ return; }
432     if(!filePath.endsWith(".desktop")){ filePath.append(".desktop"); }
433 
434   //qDebug() << " -Try Saving File:" << filePath;
435   bool saved = saveFile(filePath);
436   //qDebug() << "File Saved:" << saved;
437   ui->actionSave_Shortcut->setEnabled( !saved );
438   if(saved){
439     //Re-load the file info
440     LoadFile(filePath);
441   }
442 }
443 
open_dir_clicked()444 void MainUI::open_dir_clicked(){
445   QString path = findOpenDirFile(true); //directory only
446   if(path.isEmpty()){ return; }
447   LoadFile(path, "");
448 }
449 
open_file_clicked()450 void MainUI::open_file_clicked(){
451   QString path = findOpenDirFile(false); //files only
452   if(path.isEmpty()){ return; }
453   LoadFile(path, "");
454 }
455 
getXdgCommand(QString prev)456 void MainUI::getXdgCommand(QString prev){
457   //Find a binary to run
458   QString dir = prev; //start with the previous attempt (if there was one)
459   if(dir.isEmpty()){ ui->line_xdg_command->text(); }//then try current selection
460   if(dir.isEmpty()){ dir = LOS::AppPrefix()+"bin"; } //then open the application binaries directory
461   QString file = QFileDialog::getOpenFileName(this, tr("Select a binary"), dir );
462   if(file.isEmpty()){ return; } //cancelled
463   if(!LUtils::isValidBinary(file)){
464     QMessageBox::warning(this, tr("Error"), tr("Invalid selection: Not a valid executable"));
465     getXdgCommand(file);
466     return;
467   }
468   ui->line_xdg_command->setText(file);
469   xdgvaluechanged();
470 }
471 
on_tool_xdg_getDir_clicked()472 void MainUI::on_tool_xdg_getDir_clicked(){
473   //Find a directory
474   QString dir = ui->line_xdg_wdir->text();
475   if(dir.isEmpty()){ dir = QDir::homePath(); }
476   dir = QFileDialog::getExistingDirectory(this, tr("Select a directory"), dir);
477   if(dir.isEmpty()){ return; } //cancelled
478   ui->line_xdg_wdir->setText(dir);
479   xdgvaluechanged();
480 }
481 
on_push_xdg_getIcon_clicked()482 void MainUI::on_push_xdg_getIcon_clicked(){
483   //Find an image file
484   QString dir = ui->push_xdg_getIcon->whatsThis(); //then try current selection
485   if(dir.isEmpty()){ dir = QDir::homePath(); }
486   //Get the known file extensions
487   QStringList ext = LUtils::imageExtensions();
488   for(int i=0; i<ext.length(); i++){ ext[i].prepend("*."); } //turn them into valid filters
489   QString file = QFileDialog::getOpenFileName(this, tr("Select an icon"), dir ,QString(tr("Images (%1);; All Files (*)")).arg(ext.join(" ")) );
490   if(file.isEmpty()){ return; } //cancelled
491   ui->line_xdg_icon->setText(file);
492   ReloadAppIcon();
493   xdgvaluechanged();
494 }
495 
496 //XDG Value Changed
checkXDGValidity()497 bool MainUI::checkXDGValidity(){
498   XDGDesktop tmp;
499   tmp.type = XDGDesktop::APP; //make this adjustable later (GUI radio buttons?)
500   tmp.name = ui->line_xdg_name->text();
501   tmp.genericName = ui->line_xdg_name->text().toLower();
502   tmp.comment = ui->line_xdg_comment->text();
503   tmp.icon = ui->line_xdg_icon->text();
504   //Now do the type-specific fields
505   if(tmp.type == XDGDesktop::APP){
506     tmp.exec = ui->line_xdg_command->text();
507     tmp.tryexec = ui->line_xdg_command->text().section(" ",0,0); //use the first word/binary for the existance check
508     tmp.path = ui->line_xdg_wdir->text(); //working dir/path
509     tmp.useTerminal = ui->check_xdg_useTerminal->isChecked();
510     tmp.startupNotify = ui->check_xdg_startupNotify->isChecked();
511   }else if(tmp.type==XDGDesktop::LINK){
512     tmp.url = ui->line_xdg_wdir->text(); //we re-used this field
513   }
514   bool valid = tmp.isValid();
515   ui->label_xdg_statusicon->setPixmap( LXDG::findIcon( valid ? "dialog-ok" : "dialog-cancel", "").pixmap(32,32) );
516   ui->label_xdg_status->setText( valid ? tr("Valid Settings") : tr("Invalid Settings") );
517   return tmp.isValid();
518 }
519 
xdgvaluechanged()520 void MainUI::xdgvaluechanged(){
521   //qDebug() << "xdgvaluechanged";
522   if( INFO->isDesktopFile() || INFO->filePath().isEmpty()  ){
523     bool valid = checkXDGValidity();
524     //Compare the current UI values to the file values
525     ui->menuSave_As->setEnabled(valid);
526     ui->actionSave_Shortcut->setEnabled(canwrite && valid); //assume changed at this point
527 
528   }else{
529     ui->actionSave_Shortcut->setEnabled(false);
530   }
531 }
532 
refresh_folder_size(quint64 size,quint64 files,quint64 folders,bool finished)533 void MainUI::refresh_folder_size(quint64 size, quint64 files, quint64 folders, bool finished) {
534   if(finished)
535     ui->label_file_size->setText( LUtils::BytesToDisplaySize( size ) + " -- " + tr(" Folders: ") + QString::number(folders) + " / " + tr("Files: ") + QString::number(files) );
536   else
537     ui->label_file_size->setText( LUtils::BytesToDisplaySize( size ) + " -- " + tr(" Folders: ") + QString::number(folders) + " / " + tr("Files: ") + QString::number(files) + tr("  Calculating..." ));
538 }
539