1 //===========================================
2 //  Lumina-DE source code
3 //  Copyright (c) 2013, Ken Moore
4 //  Available under the 3-clause BSD license
5 //  See the LICENSE file for full details
6 //===========================================
7 #include "LFileDialog.h"
8 #include "ui_LFileDialog.h"
9 
LFileDialog(QWidget * parent)10 LFileDialog::LFileDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LFileDialog() ){
11   ui->setupUi(this); //load the designer file
12   //set the output flags to the defaults
13   appSelected = false;
14   setDefault = false;
15   appExec.clear();
16   appPath.clear();
17   appFile.clear();
18   settings = new QSettings("lumina-desktop", "lumina-open", this);
19   //Connect the signals/slots
20   connect(ui->combo_apps, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()) );
21   connect(ui->radio_rec, SIGNAL(toggled(bool)), this, SLOT(radioChanged()) );
22   connect(ui->radio_avail, SIGNAL(toggled(bool)), this, SLOT(radioChanged()) );
23   connect(ui->radio_custom, SIGNAL(toggled(bool)), this, SLOT(radioChanged()) );
24 }
25 
~LFileDialog()26 LFileDialog::~LFileDialog(){
27 
28 }
29 
30 // ----------
31 //   PUBLIC
32 // ----------
setFileInfo(QString filename,QString extension,bool isFile)33 void LFileDialog::setFileInfo(QString filename, QString extension, bool isFile){
34   //Set the labels for the file
35   qDebug() << "SetFileInfo:" << filename << extension << isFile;
36   filePath = filename; //save for later
37   ui->label_file->setText( this->fontMetrics().elidedText( filename, Qt::ElideMiddle, 300 ) );
38   bool shownetwork = false;
39   if(isFile){ ui->label_extension->setText( "("+extension+")"); }
40   else if(extension=="email"){ ui->label_extension->setText( QString(tr("(Email Link)")) ); shownetwork = true; }
41   else if(extension.startsWith("x-scheme-handler/")){  ui->label_extension->setText( QString(tr("(Internet URL - %1)")).arg(extension.section("/",-1)) ); shownetwork = true; }
42   else{ui->label_extension->setText("("+extension+" link)"); }
43   fileEXT = extension; //NOTE: this is the mime-type for the file now, not the extension
44   generateAppList(shownetwork);
45 }
46 
47 //static functions
getDefaultApp(QString extension)48 QString LFileDialog::getDefaultApp(QString extension){
49   if(!extension.contains("/")){ return ""; }
50   qDebug() << "Get Default App:" << extension;
51   return LXDG::findDefaultAppForMime(extension);
52 }
53 
setDefaultApp(QString extension,QString appFile)54 void LFileDialog::setDefaultApp(QString extension, QString appFile){
55   if(!extension.contains("/")){ extension = LXDG::findAppMimeForFile(appFile); }
56 
57   //mime type default: set on the system itself
58   //if(appFile.endsWith(".desktop")){ appFile = appFile.section("/",-1); } //only need the relative path
59   LXDG::setDefaultAppForMime(extension, appFile);
60 }
61 
62 // -----------
63 //   PRIVATE
64 // -----------
getPreferredApplications()65 QStringList LFileDialog::getPreferredApplications(){
66   QStringList out;
67   //First list all the applications registered for that same mimetype
68   QString mime = fileEXT;
69   out << LXDG::findAvailableAppsForMime(mime);
70 
71   //Now search the internal settings for that extension and find any applications last used
72   QStringList keys = settings->allKeys();
73   for(int i=0; i<keys.length(); i++){
74     if(keys[i].startsWith("default/")){ continue; } //ignore the defaults (they will also be in the main)
75     if(keys[i].toLower() == fileEXT.toLower()){
76       QStringList files = settings->value(keys[i]).toString().split(":::");
77       qDebug() << "Found Files:" << keys[i] << files;
78       bool cleaned = false;
79       for(int j=0; j<files.length(); j++){
80         if(QFile::exists(files[j])){ out << files[j]; }
81         else{ files.removeAt(j); j--; cleaned=true; } //file no longer available - remove it
82       }
83       if(cleaned){ settings->setValue(keys[i], files.join(":::")); } //update the registry
84       if(!out.isEmpty()){ break; } //already found files
85     }
86   }
87   //Make sure we don't have any duplicates before we return the list
88   out.removeDuplicates();
89   return out;
90 }
91 
setPreferredApplication(QString desktopfile)92 void LFileDialog::setPreferredApplication(QString desktopfile){
93   QStringList keys = settings->allKeys();
94   for(int i=0; i<keys.length(); i++){
95     if(keys[i].toLower() == fileEXT.toLower()){
96       QStringList files = settings->value(keys[i]).toString().split(":::");
97       files.removeAll(desktopfile);
98       QStringList newfiles;
99       newfiles << desktopfile;
100       //Only keep the 5 most recent preferred applications per extension
101       for(int j=0; j<5 && j<files.length(); j++){
102       	  newfiles << files[j];
103       }
104       settings->setValue(keys[i], newfiles.join(":::"));
105       return;
106     }
107   }
108   //No key found for this extension - make a new one
109   settings->setValue(fileEXT.toLower(), desktopfile);
110 }
111 
translateCat(QString cat)112 QString LFileDialog::translateCat(QString cat){
113   QString out;
114   if(cat=="Audio"){ out = tr("Audio"); }
115   else if(cat=="Video"){ out = tr("Video"); }
116   else if(cat=="Multimedia"){ out = tr("Multimedia"); }
117   else if(cat=="Development"){ out = tr("Development"); }
118   else if(cat=="Education"){ out = tr("Education"); }
119   else if(cat=="Game"){ out = tr("Game"); }
120   else if(cat=="Graphics"){ out = tr("Graphics"); }
121   else if(cat=="Network"){ out = tr("Network"); }
122   else if(cat=="Office"){ out = tr("Office"); }
123   else if(cat=="Science"){ out = tr("Science"); }
124   else if(cat=="Settings"){ out = tr("Settings"); }
125   else if(cat=="System"){ out = tr("System"); }
126   else if(cat=="Utility"){ out = tr("Utilities"); }
127   else if(cat=="Other"){ out = tr("Other"); }
128   else{ out = cat; }
129   return out;
130 }
131 
132 // -----------------
133 //   PRIVATE SLOTS
134 // -----------------
updateUI()135 void LFileDialog::updateUI(){
136   //Check for a selected application
137   bool good = false;
138   if(ui->radio_custom->isChecked()){
139     if(!ui->line_bin->text().isEmpty()){
140       QString bin = ui->line_bin->text();
141       good = LUtils::isValidBinary(bin);
142       //Now verify that the file exists and is executable
143       if( good ){
144         ui->label_goodbin->setPixmap(QPixmap(":/icons/good.png"));
145       }else{
146         ui->label_goodbin->setPixmap(QPixmap(":/icons/bad.png"));
147       }
148     }
149   }
150   else if(ui->radio_rec->isChecked()){
151     good = true; //a valid app is always selected on this page if it is available
152   }
153   else if(ui->combo_apps->count() > 0 && !ui->combo_apps->currentData().toString().isEmpty() ){
154       good=true;
155   }
156   ui->tool_ok->setEnabled(good);
157 }
158 
generateAppList(bool shownetwork)159 void LFileDialog::generateAppList(bool shownetwork){
160   //Now load the preferred applications
161   XDGDesktopList applist;
162     applist.updateList();
163   PREFAPPS = getPreferredApplications();
164   qDebug() << "Preferred Apps:" << PREFAPPS;
165   ui->combo_rec->clear();
166   //Now get the application mimetype for the file extension (if available)
167   QStringList mimetypes = LXDG::findAppMimeForFile(filePath, true).split("::::"); //use all mimetypes
168     mimetypes.removeDuplicates();
169   QString defapp = getDefaultApp(mimetypes.first()); //default application
170   if(!defapp.isEmpty() && !PREFAPPS.contains(defapp) ){ PREFAPPS << defapp; } //ensure this is listed in the preferred apps list
171   //Now add all the detected applications
172   QHash< QString, QList<XDGDesktop*> > hash = LXDG::sortDesktopCats( applist.apps(false,true) );
173   QStringList cat = hash.keys();
174   cat.sort(); //sort alphabetically
175   ui->combo_apps->clear();
176   for(int c=0; c<cat.length(); c++){
177     QList<XDGDesktop*> app = hash[cat[c]];
178     if(app.length()<1){ continue; }
179     if(ui->combo_apps->count() >1){ ui->combo_apps->insertSeparator(ui->combo_apps->count()); }
180     ui->combo_apps->addItem(translateCat(cat[c]));
181     ui->combo_apps->insertSeparator(ui->combo_apps->count());
182     for(int a=0; a<app.length(); a++){
183       if(shownetwork && (cat[c].toLower()=="network" || cat[c].toLower()=="utility") ){
184 	//Need to show preferred internet applications - look for ones that handle URL's
185 	if(app[a]->exec.contains("%u") || app[a]->exec.contains("%U")){
186           //qDebug() << "Add to Preferred Apps:" << app[a]->filePath;
187           PREFAPPS << app[a]->filePath;
188 	}
189       }
190       ui->combo_apps->addItem(LXDG::findIcon(app[a]->icon, "application-x-desktop"), app[a]->name, app[a]->filePath);
191       //Check to see if this app matches the mime type
192       if(!mimetypes.isEmpty()){
193         QStringList tmp = mimetypes; tmp << app[a]->mimeList;
194         if(tmp.removeDuplicates() > 0 ){
195           // also put this app in the preferred list
196           //qDebug() << "Mimetype match:" << mimetypes << app[a]->mimeList;
197 	  PREFAPPS.append(app[a]->filePath);
198 	  //If this is the first preferred app found - select this app initially
199 	  if(ui->combo_apps->currentIndex()<=0){ ui->combo_apps->setCurrentIndex(ui->combo_apps->count()-1); }
200         }
201       }
202     }
203   }
204   if(ui->combo_apps->currentIndex()<=0){ ui->combo_apps->setCurrentIndex(2); } //Start on the first "real" app - not the first category header
205   //Now add all the preferred applications
206   PREFAPPS.removeDuplicates();
207   for(int i=0; i<PREFAPPS.length(); i++){
208     XDGDesktop dFile(PREFAPPS[i]);
209     if( dFile.isValid() ){
210       QString txt = dFile.name;
211       if(PREFAPPS[i] == defapp){ txt.prepend( tr("[default] ") ); }
212       ui->combo_rec->addItem( LXDG::findIcon(dFile.icon, "application-x-desktop"), txt);
213       if(i==0){ ui->combo_rec->setCurrentIndex(0); } //make sure the first item is selected
214     }else{
215       PREFAPPS.removeAt(i); //invalid app
216       i--;
217     }
218   }
219   //Update the UI
220   if(PREFAPPS.isEmpty()){
221     ui->radio_rec->setEnabled(false); //no preferred apps
222     ui->radio_avail->setChecked(true);
223   }else{
224     ui->radio_rec->setChecked(true);
225   }
226 }
227 
radioChanged()228 void LFileDialog::radioChanged(){
229   if(ui->radio_rec->isChecked()){
230     ui->stackedWidget->setCurrentWidget(ui->page_rec);
231   }else if(ui->radio_avail->isChecked()){
232     ui->stackedWidget->setCurrentWidget(ui->page_avail);
233   }else{
234     ui->stackedWidget->setCurrentWidget(ui->page_custom);
235   }
236   //ui->check_default->setEnabled( !ui->radio_custom->isChecked() );
237   updateUI();
238 }
239 
240 /*void LFileDialog::on_group_binary_toggled(bool checked){
241   ui->label_goodbin->setVisible(checked);
242   ui->line_bin->setVisible(checked);
243   ui->tool_findBin->setVisible(checked);
244   updateUI();
245 }*/
246 
on_tool_ok_clicked()247 void LFileDialog::on_tool_ok_clicked(){
248   appSelected = true;
249   setDefault = ui->check_default->isChecked();
250   if(ui->radio_custom->isChecked()){
251     appExec = ui->line_bin->text();
252   }else if(ui->radio_rec->isChecked()){
253     //application selected
254     XDGDesktop app(PREFAPPS[ui->combo_rec->currentIndex()]);
255     //Set the output variables
256     appExec =  app.getDesktopExec();
257     appPath = app.path;
258     appFile = app.filePath;
259     setPreferredApplication(app.filePath); //bump this to the top of the preferred list for next time
260   }else{
261     //application selected
262     XDGDesktop app(ui->combo_apps->currentData().toString());
263     //Set the output variables
264     appExec = app.getDesktopExec();
265     appPath = app.path;
266     appFile = app.filePath;
267     setPreferredApplication(app.filePath); //save this app to this extension as a recommendation
268   }
269   this->close();
270 }
271 
on_tool_cancel_clicked()272 void LFileDialog::on_tool_cancel_clicked(){
273   appSelected = false;
274   this->close();
275 }
276 
on_tool_findBin_clicked()277 void LFileDialog::on_tool_findBin_clicked(){
278   QString filepath = QFileDialog::getOpenFileName(this, tr("Find Application Binary"), QDir::homePath() );
279   if(filepath.isEmpty()){ return; }
280   ui->line_bin->setText(filepath);
281 }
282 
on_line_bin_textChanged()283 void LFileDialog::on_line_bin_textChanged(){
284   updateUI();
285 }
286