#include "mimeutils.h" #include #include #include #include #include #include #include #include #define MIME_APPS1 "/.local/share/applications/mimeapps.list" #define MIME_APPS2 "/usr/share/applications/mimeapps.list" /** * @brief Creates mime utils * @param parent */ MimeUtils::MimeUtils(QObject *parent) : QObject(parent) { QString path(QDir::homePath() + MIME_APPS1); QFileInfo fi(path); if(fi.exists()){ defaultsFileName = path; } else { QFileInfo ff(MIME_APPS2); if(ff.exists()) defaultsFileName = MIME_APPS2; } getProperties(); load(defaultsFileName, "Default Applications"); defaultsChanged = false; } MimeUtils::~MimeUtils() { } //--------------------------------------------------------------------------- /** * @brief Loads property file * @param fileName * @param group * @return true if load was successful */ bool MimeUtils::load(const QString &fileName, const QString &group) { // NOTE: This class is used for reading of property files instead of QSettings // class, which considers separator ';' as comment // Try open file QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } // Clear old data data.clear(); // Indicator whether group was found or not, if name of group was not // specified, groupFound is always true bool groupFound = group.isEmpty(); // Read propeties QTextStream in(&file); while (!in.atEnd()) { // Read new line QString line = in.readLine(); // Skip empty line or line with invalid format if (line.trimmed().isEmpty()) { continue; } // Read group // NOTE: symbols '[' and ']' can be found not only in group names, but // only group can start with '[' if (!group.isEmpty() && line.trimmed().startsWith("[")) { QString tmp = line.trimmed().replace("[", "").replace("]", ""); groupFound = group.trimmed().compare(tmp) == 0; } // If we are in correct group and line contains assignment then read data if (groupFound && line.contains("=")) { QStringList tmp = line.split("="); data.insert(tmp.at(0), tmp.at(1)); } } file.close(); return true; } QVariant MimeUtils::value(const QString &key, const QVariant &defaultValue) { return data.value(key, defaultValue); } void MimeUtils::getProperties(const QString &fileName, const QString &group) { if (!fileName.isEmpty()) { load(fileName, group); } } /** * @brief Returns mime type of given file * @note This operation is slow, prevent its mass application * @param path path to file * @return mime type */ QString MimeUtils::getMimeType(const QString &path) { QMimeDatabase db; QMimeType type = db.mimeTypeForFile(path); //qDebug() << "mime type" << type.name() << path; return type.name(); } void MimeUtils::getDesktopFile(const QString &fileName) { // Store file name this->fileName = fileName; // File validity if (!QFile::exists(fileName)) { return; } // Loads .desktop file (read from 'Desktop Entry' group) getProperties(fileName, "Desktop Entry"); name = value("Name", "").toString(); genericName = value("GenericName", "").toString(); exec = value("Exec", "").toString(); icon = value("Icon", "").toString(); type = value("Type", "Application").toString(); no_display = value("NoDisplay", false).toBool(); terminal = value("Terminal", false).toBool(); categories = value("Categories").toString().remove(" ").split(";"); mimeType = value("MimeType").toString().remove(" ").split(";"); // Fix categories if (categories.first().compare("") == 0) { categories.removeFirst(); } } //--------------------------------------------------------------------------- QStringList MimeUtils::applicationLocations(QString appPath) { QStringList result; result << QString("%1/.local/share/applications").arg(QDir::homePath()); result << QString("%1/../share/applications").arg(appPath); result << "/usr/share/applications" << "/usr/local/share/applications"; return result; } QString MimeUtils::findApplication(QString appPath, QString desktopFile) { QString result; if (desktopFile.isEmpty()) { return result; } QStringList apps = applicationLocations(appPath); for (int i=0;iapplicationFilePath(), app); qDebug() << "openInApp" << file.absoluteFilePath() << termCmd << mime << app << desktop; if (!desktop.isEmpty()) { getDesktopFile(desktop); if (!terminal) { termCmd.clear(); } else { if (termCmd.isEmpty()) { termCmd = "xterm"; } } openInApp(exec, file, termCmd); } else { QString title = tr("No default application"); QString msg = tr("No default application for mime: %1!").arg(mime); QMessageBox::warning(Q_NULLPTR, title, msg); } } //--------------------------------------------------------------------------- /** * @brief Opens file in a given application * @param exe name of application to be executed * @param file to be opened in executed application * @param processOwner process owner (default NULL) */ void MimeUtils::openInApp(QString exe, const QFileInfo &file, QString termCmd) { qDebug() << "openInApp" << exe << file.absoluteFilePath() << termCmd; // This is not the right the solution, but qpdfview won't start otherwise // TODO: Repair it correctly if (exe.contains("qpdfview")) { exe = "qpdfview"; } // Separate application name from its arguments QStringList split = exe.split(" "); QString name = split.takeAt(0); QString args = split.join(" "); // Get relative path //args = args.split(QDir::separator()).last(); // Replace parameters with file name. If there are no parameters simply append // file name to the end of argument list if (args.toLower().contains("%f")) { args.replace("%f", "\"" + file.filePath() + "\"", Qt::CaseInsensitive); } else if (args.toLower().contains("%u")) { args.replace("%u", "\"" + file.filePath() + "\"", Qt::CaseInsensitive); } else { args.append(args.isEmpty() ? "" : " "); args.append("\"" + file.filePath() + "\""); } qDebug() << "qprocess start detached" << name << args; checkAndKillRunningApp(name); // Start application /* QProcess *myProcess = new QProcess(processOwner); myProcess->startDetached(name, QStringList() << args); myProcess->waitForFinished(1000); //myProcess->terminate();*/ //Q_UNUSED(processOwner) QString cmd = name; if (termCmd.isEmpty()) { cmd.append(" "); cmd.append(args); } else { cmd = QString("%1 -e \"%2 %3\"").arg(termCmd).arg(name).arg(args); } qDebug() << "running:" << cmd; QProcess::startDetached(cmd); } void MimeUtils::openFiles(const QStringList &files) { qDebug() << "openInApp without app"; QString mime = getMimeType(files[0]); load(defaultsFileName, "Default Applications"); QString app = value(mime).toString().split(";").first(); QString desktop = findApplication(qApp->applicationFilePath(), app); QString file; for(int i = 0; i < files.size(); i++){ file.append(files[i]).append(" "); } qDebug() << "openInApp" << file << mime << app << desktop; if (!desktop.isEmpty()) { getDesktopFile(desktop); // openInApp(exec, file, termCmd); qDebug() << "openInApp" << exec << file; // Separate application name from its arguments QStringList split = exec.split(" "); QString name = split.takeAt(0); QString args = split.join(" "); if (args.toLower().contains("%f")) { args.replace("%f", file, Qt::CaseInsensitive); } else if (args.toLower().contains("%u")) { args.replace("%u", file, Qt::CaseInsensitive); } else { args.append(args.isEmpty() ? "" : " "); args.append(file); } qDebug() << "qprocess start detached" << name << args; checkAndKillRunningApp(name); QString cmd = name; cmd.append(" "); cmd.append(args); qDebug() << "running:" << cmd; QProcess::startDetached(cmd); } else { QString title = tr("No default application"); QString msg = tr("No default application for mime: %1!").arg(mime); QMessageBox::warning(Q_NULLPTR, title, msg); } }