xref: /OK3568_Linux_fs/app/qfm/mimeutils.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun #include "mimeutils.h"
2*4882a593Smuzhiyun #include <QApplication>
3*4882a593Smuzhiyun #include <QDir>
4*4882a593Smuzhiyun #include <QDirIterator>
5*4882a593Smuzhiyun #include <QProcess>
6*4882a593Smuzhiyun #include <QDebug>
7*4882a593Smuzhiyun #include <QMessageBox>
8*4882a593Smuzhiyun #include <QMimeDatabase>
9*4882a593Smuzhiyun #include <QMimeType>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #define MIME_APPS1 "/.local/share/applications/mimeapps.list"
12*4882a593Smuzhiyun #define MIME_APPS2 "/usr/share/applications/mimeapps.list"
13*4882a593Smuzhiyun /**
14*4882a593Smuzhiyun  * @brief Creates mime utils
15*4882a593Smuzhiyun  * @param parent
16*4882a593Smuzhiyun  */
MimeUtils(QObject * parent)17*4882a593Smuzhiyun MimeUtils::MimeUtils(QObject *parent) : QObject(parent) {
18*4882a593Smuzhiyun     QString path(QDir::homePath() + MIME_APPS1);
19*4882a593Smuzhiyun     QFileInfo fi(path);
20*4882a593Smuzhiyun     if(fi.exists()){
21*4882a593Smuzhiyun         defaultsFileName = path;
22*4882a593Smuzhiyun     } else {
23*4882a593Smuzhiyun         QFileInfo ff(MIME_APPS2);
24*4882a593Smuzhiyun         if(ff.exists())
25*4882a593Smuzhiyun             defaultsFileName = MIME_APPS2;
26*4882a593Smuzhiyun     }
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun     getProperties();
29*4882a593Smuzhiyun     load(defaultsFileName, "Default Applications");
30*4882a593Smuzhiyun     defaultsChanged = false;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
~MimeUtils()33*4882a593Smuzhiyun MimeUtils::~MimeUtils() {
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun //---------------------------------------------------------------------------
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /**
38*4882a593Smuzhiyun  * @brief Loads property file
39*4882a593Smuzhiyun  * @param fileName
40*4882a593Smuzhiyun  * @param group
41*4882a593Smuzhiyun  * @return true if load was successful
42*4882a593Smuzhiyun  */
load(const QString & fileName,const QString & group)43*4882a593Smuzhiyun bool MimeUtils::load(const QString &fileName, const QString &group) {
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun   // NOTE: This class is used for reading of property files instead of QSettings
46*4882a593Smuzhiyun   // class, which considers separator ';' as comment
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun   // Try open file
49*4882a593Smuzhiyun   QFile file(fileName);
50*4882a593Smuzhiyun   if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
51*4882a593Smuzhiyun     return false;
52*4882a593Smuzhiyun   }
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun   // Clear old data
55*4882a593Smuzhiyun   data.clear();
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun   // Indicator whether group was found or not, if name of group was not
58*4882a593Smuzhiyun   // specified, groupFound is always true
59*4882a593Smuzhiyun   bool groupFound = group.isEmpty();
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun   // Read propeties
62*4882a593Smuzhiyun   QTextStream in(&file);
63*4882a593Smuzhiyun   while (!in.atEnd()) {
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun     // Read new line
66*4882a593Smuzhiyun     QString line = in.readLine();
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun     // Skip empty line or line with invalid format
69*4882a593Smuzhiyun     if (line.trimmed().isEmpty()) {
70*4882a593Smuzhiyun       continue;
71*4882a593Smuzhiyun     }
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun     // Read group
74*4882a593Smuzhiyun     // NOTE: symbols '[' and ']' can be found not only in group names, but
75*4882a593Smuzhiyun     // only group can start with '['
76*4882a593Smuzhiyun     if (!group.isEmpty() && line.trimmed().startsWith("[")) {
77*4882a593Smuzhiyun       QString tmp = line.trimmed().replace("[", "").replace("]", "");
78*4882a593Smuzhiyun       groupFound = group.trimmed().compare(tmp) == 0;
79*4882a593Smuzhiyun     }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun     // If we are in correct group and line contains assignment then read data
82*4882a593Smuzhiyun     if (groupFound && line.contains("=")) {
83*4882a593Smuzhiyun       QStringList tmp = line.split("=");
84*4882a593Smuzhiyun       data.insert(tmp.at(0), tmp.at(1));
85*4882a593Smuzhiyun     }
86*4882a593Smuzhiyun   }
87*4882a593Smuzhiyun   file.close();
88*4882a593Smuzhiyun   return true;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
value(const QString & key,const QVariant & defaultValue)91*4882a593Smuzhiyun QVariant MimeUtils::value(const QString &key, const QVariant &defaultValue) {
92*4882a593Smuzhiyun   return data.value(key, defaultValue);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
getProperties(const QString & fileName,const QString & group)95*4882a593Smuzhiyun void MimeUtils::getProperties(const QString &fileName, const QString &group) {
96*4882a593Smuzhiyun   if (!fileName.isEmpty()) {
97*4882a593Smuzhiyun     load(fileName, group);
98*4882a593Smuzhiyun   }
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /**
102*4882a593Smuzhiyun  * @brief Returns mime type of given file
103*4882a593Smuzhiyun  * @note This operation is slow, prevent its mass application
104*4882a593Smuzhiyun  * @param path path to file
105*4882a593Smuzhiyun  * @return mime type
106*4882a593Smuzhiyun  */
getMimeType(const QString & path)107*4882a593Smuzhiyun QString MimeUtils::getMimeType(const QString &path) {
108*4882a593Smuzhiyun     QMimeDatabase db;
109*4882a593Smuzhiyun     QMimeType type = db.mimeTypeForFile(path);
110*4882a593Smuzhiyun     //qDebug() << "mime type" << type.name() << path;
111*4882a593Smuzhiyun     return type.name();
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 
getDesktopFile(const QString & fileName)115*4882a593Smuzhiyun void MimeUtils::getDesktopFile(const QString &fileName) {
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun   // Store file name
118*4882a593Smuzhiyun   this->fileName = fileName;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun   // File validity
121*4882a593Smuzhiyun   if (!QFile::exists(fileName)) {
122*4882a593Smuzhiyun     return;
123*4882a593Smuzhiyun   }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun   // Loads .desktop file (read from 'Desktop Entry' group)
126*4882a593Smuzhiyun   getProperties(fileName, "Desktop Entry");
127*4882a593Smuzhiyun   name = value("Name", "").toString();
128*4882a593Smuzhiyun   genericName = value("GenericName", "").toString();
129*4882a593Smuzhiyun   exec = value("Exec", "").toString();
130*4882a593Smuzhiyun   icon = value("Icon", "").toString();
131*4882a593Smuzhiyun   type = value("Type", "Application").toString();
132*4882a593Smuzhiyun   no_display = value("NoDisplay", false).toBool();
133*4882a593Smuzhiyun   terminal = value("Terminal", false).toBool();
134*4882a593Smuzhiyun   categories = value("Categories").toString().remove(" ").split(";");
135*4882a593Smuzhiyun   mimeType = value("MimeType").toString().remove(" ").split(";");
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun   // Fix categories
138*4882a593Smuzhiyun   if (categories.first().compare("") == 0) {
139*4882a593Smuzhiyun     categories.removeFirst();
140*4882a593Smuzhiyun   }
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun //---------------------------------------------------------------------------
143*4882a593Smuzhiyun 
applicationLocations(QString appPath)144*4882a593Smuzhiyun QStringList MimeUtils::applicationLocations(QString appPath)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun     QStringList result;
147*4882a593Smuzhiyun     result << QString("%1/.local/share/applications").arg(QDir::homePath());
148*4882a593Smuzhiyun     result << QString("%1/../share/applications").arg(appPath);
149*4882a593Smuzhiyun     result << "/usr/share/applications" << "/usr/local/share/applications";
150*4882a593Smuzhiyun     return result;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
findApplication(QString appPath,QString desktopFile)153*4882a593Smuzhiyun QString MimeUtils::findApplication(QString appPath, QString desktopFile)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun     QString result;
156*4882a593Smuzhiyun     if (desktopFile.isEmpty()) { return result; }
157*4882a593Smuzhiyun     QStringList apps = applicationLocations(appPath);
158*4882a593Smuzhiyun     for (int i=0;i<apps.size();++i) {
159*4882a593Smuzhiyun         QDirIterator it(apps.at(i), QStringList("*.desktop"), QDir::Files|QDir::NoDotAndDotDot);
160*4882a593Smuzhiyun         while (it.hasNext()) {
161*4882a593Smuzhiyun             QString found = it.next();
162*4882a593Smuzhiyun             if (found.split("/").takeLast()==desktopFile) {
163*4882a593Smuzhiyun                 //qDebug() << "found app" << found;
164*4882a593Smuzhiyun                 return found;
165*4882a593Smuzhiyun             }
166*4882a593Smuzhiyun         }
167*4882a593Smuzhiyun     }
168*4882a593Smuzhiyun     return result;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
checkAndKillRunningApp(QString & appName)171*4882a593Smuzhiyun void MimeUtils::checkAndKillRunningApp(QString &appName)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun     QProcess p;
174*4882a593Smuzhiyun     QString s;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun     s = "ps -aux";
177*4882a593Smuzhiyun     p.start(s);
178*4882a593Smuzhiyun     p.waitForStarted();
179*4882a593Smuzhiyun     p.waitForFinished();
180*4882a593Smuzhiyun     QByteArray b = p.readAll();
181*4882a593Smuzhiyun     QString out = QString::fromLocal8Bit(b);
182*4882a593Smuzhiyun     if(out.contains(appName)){
183*4882a593Smuzhiyun         QString str = appName.mid(appName.lastIndexOf('/') + 1, s.size());
184*4882a593Smuzhiyun         s = "killall " + str;
185*4882a593Smuzhiyun         qDebug() << "killing existing app: " + str;
186*4882a593Smuzhiyun         p.start(s);
187*4882a593Smuzhiyun         p.waitForFinished();
188*4882a593Smuzhiyun     }
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun /**
192*4882a593Smuzhiyun  * @brief Opens file in a default application
193*4882a593Smuzhiyun  * @param file
194*4882a593Smuzhiyun  * @param processOwner
195*4882a593Smuzhiyun  */
openInApp(const QFileInfo & file,QString termCmd)196*4882a593Smuzhiyun void MimeUtils::openInApp(const QFileInfo &file, QString termCmd) {
197*4882a593Smuzhiyun   qDebug() << "openInApp without app";
198*4882a593Smuzhiyun   QString mime = getMimeType(file.absoluteFilePath());
199*4882a593Smuzhiyun   load(defaultsFileName, "Default Applications");
200*4882a593Smuzhiyun   QString app = value(mime).toString().split(";").first();
201*4882a593Smuzhiyun   if (app.isEmpty() && mime.startsWith("text/") && mime != "text/plain") {
202*4882a593Smuzhiyun       // fallback for text
203*4882a593Smuzhiyun       app = value("text/plain").toString().split(";").first();
204*4882a593Smuzhiyun   }
205*4882a593Smuzhiyun   QString desktop = findApplication(qApp->applicationFilePath(), app);
206*4882a593Smuzhiyun   qDebug() << "openInApp" << file.absoluteFilePath() << termCmd << mime << app << desktop;
207*4882a593Smuzhiyun   if (!desktop.isEmpty()) {
208*4882a593Smuzhiyun     getDesktopFile(desktop);
209*4882a593Smuzhiyun     if (!terminal) { termCmd.clear(); }
210*4882a593Smuzhiyun     else {
211*4882a593Smuzhiyun         if (termCmd.isEmpty()) { termCmd = "xterm"; }
212*4882a593Smuzhiyun     }
213*4882a593Smuzhiyun     openInApp(exec, file, termCmd);
214*4882a593Smuzhiyun   } else {
215*4882a593Smuzhiyun      QString title = tr("No default application");
216*4882a593Smuzhiyun      QString msg = tr("No default application for mime: %1!").arg(mime);
217*4882a593Smuzhiyun      QMessageBox::warning(Q_NULLPTR, title, msg);
218*4882a593Smuzhiyun   }
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun //---------------------------------------------------------------------------
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /**
223*4882a593Smuzhiyun  * @brief Opens file in a given application
224*4882a593Smuzhiyun  * @param exe name of application to be executed
225*4882a593Smuzhiyun  * @param file to be opened in executed application
226*4882a593Smuzhiyun  * @param processOwner process owner (default NULL)
227*4882a593Smuzhiyun  */
openInApp(QString exe,const QFileInfo & file,QString termCmd)228*4882a593Smuzhiyun void MimeUtils::openInApp(QString exe, const QFileInfo &file,
229*4882a593Smuzhiyun                           QString termCmd) {
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun   qDebug() << "openInApp" << exe << file.absoluteFilePath() << termCmd;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun   // This is not the right the solution, but qpdfview won't start otherwise
234*4882a593Smuzhiyun   // TODO: Repair it correctly
235*4882a593Smuzhiyun   if (exe.contains("qpdfview")) {
236*4882a593Smuzhiyun     exe = "qpdfview";
237*4882a593Smuzhiyun   }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun   // Separate application name from its arguments
240*4882a593Smuzhiyun   QStringList split = exe.split(" ");
241*4882a593Smuzhiyun   QString name = split.takeAt(0);
242*4882a593Smuzhiyun   QString args = split.join(" ");
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun   // Get relative path
245*4882a593Smuzhiyun   //args = args.split(QDir::separator()).last();
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun   // Replace parameters with file name. If there are no parameters simply append
248*4882a593Smuzhiyun   // file name to the end of argument list
249*4882a593Smuzhiyun   if (args.toLower().contains("%f")) {
250*4882a593Smuzhiyun     args.replace("%f", "\"" + file.filePath() + "\"", Qt::CaseInsensitive);
251*4882a593Smuzhiyun   } else if (args.toLower().contains("%u")) {
252*4882a593Smuzhiyun     args.replace("%u", "\"" + file.filePath() + "\"", Qt::CaseInsensitive);
253*4882a593Smuzhiyun   } else {
254*4882a593Smuzhiyun     args.append(args.isEmpty() ? "" : " ");
255*4882a593Smuzhiyun     args.append("\"" + file.filePath() + "\"");
256*4882a593Smuzhiyun   }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun   qDebug() << "qprocess start detached" << name << args;
259*4882a593Smuzhiyun   checkAndKillRunningApp(name);
260*4882a593Smuzhiyun   // Start application
261*4882a593Smuzhiyun  /* QProcess *myProcess = new QProcess(processOwner);
262*4882a593Smuzhiyun   myProcess->startDetached(name, QStringList() << args);
263*4882a593Smuzhiyun   myProcess->waitForFinished(1000);
264*4882a593Smuzhiyun   //myProcess->terminate();*/
265*4882a593Smuzhiyun   //Q_UNUSED(processOwner)
266*4882a593Smuzhiyun   QString cmd = name;
267*4882a593Smuzhiyun   if (termCmd.isEmpty()) {
268*4882a593Smuzhiyun     cmd.append(" ");
269*4882a593Smuzhiyun     cmd.append(args);
270*4882a593Smuzhiyun   } else {
271*4882a593Smuzhiyun     cmd = QString("%1 -e \"%2 %3\"").arg(termCmd).arg(name).arg(args);
272*4882a593Smuzhiyun   }
273*4882a593Smuzhiyun   qDebug() << "running:" << cmd;
274*4882a593Smuzhiyun   QProcess::startDetached(cmd);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
openFiles(const QStringList & files)277*4882a593Smuzhiyun void MimeUtils::openFiles(const QStringList &files) {
278*4882a593Smuzhiyun   qDebug() << "openInApp without app";
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun   QString mime = getMimeType(files[0]);
281*4882a593Smuzhiyun   load(defaultsFileName, "Default Applications");
282*4882a593Smuzhiyun   QString app = value(mime).toString().split(";").first();
283*4882a593Smuzhiyun   QString desktop = findApplication(qApp->applicationFilePath(), app);
284*4882a593Smuzhiyun   QString file;
285*4882a593Smuzhiyun   for(int i = 0; i < files.size(); i++){
286*4882a593Smuzhiyun       file.append(files[i]).append(" ");
287*4882a593Smuzhiyun   }
288*4882a593Smuzhiyun   qDebug() << "openInApp" << file << mime << app << desktop;
289*4882a593Smuzhiyun   if (!desktop.isEmpty()) {
290*4882a593Smuzhiyun     getDesktopFile(desktop);
291*4882a593Smuzhiyun //    openInApp(exec, file, termCmd);
292*4882a593Smuzhiyun     qDebug() << "openInApp" << exec << file;
293*4882a593Smuzhiyun     // Separate application name from its arguments
294*4882a593Smuzhiyun     QStringList split = exec.split(" ");
295*4882a593Smuzhiyun     QString name = split.takeAt(0);
296*4882a593Smuzhiyun     QString args = split.join(" ");
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun     if (args.toLower().contains("%f")) {
299*4882a593Smuzhiyun       args.replace("%f", file, Qt::CaseInsensitive);
300*4882a593Smuzhiyun     } else if (args.toLower().contains("%u")) {
301*4882a593Smuzhiyun       args.replace("%u", file, Qt::CaseInsensitive);
302*4882a593Smuzhiyun     } else {
303*4882a593Smuzhiyun       args.append(args.isEmpty() ? "" : " ");
304*4882a593Smuzhiyun       args.append(file);
305*4882a593Smuzhiyun     }
306*4882a593Smuzhiyun     qDebug() << "qprocess start detached" << name << args;
307*4882a593Smuzhiyun     checkAndKillRunningApp(name);
308*4882a593Smuzhiyun     QString cmd = name;
309*4882a593Smuzhiyun     cmd.append(" ");
310*4882a593Smuzhiyun     cmd.append(args);
311*4882a593Smuzhiyun     qDebug() << "running:" << cmd;
312*4882a593Smuzhiyun     QProcess::startDetached(cmd);
313*4882a593Smuzhiyun   } else {
314*4882a593Smuzhiyun      QString title = tr("No default application");
315*4882a593Smuzhiyun      QString msg = tr("No default application for mime: %1!").arg(mime);
316*4882a593Smuzhiyun      QMessageBox::warning(Q_NULLPTR, title, msg);
317*4882a593Smuzhiyun   }
318*4882a593Smuzhiyun }
319