//=========================================== // Lumina-DE source code // Copyright (c) 2013-2015, Ken Moore // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== #include "LuminaXDG.h" #include "LuminaOS.h" #include "LuminaUtils.h" #include #include #include #include static QStringList mimeglobs; static qint64 mimechecktime; //====XDGDesktopList Functions ==== XDGDesktopList::XDGDesktopList(QObject *parent, bool watchdirs) : QObject(parent){ if(watchdirs){ watcher = new QFileSystemWatcher(this); connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(watcherChanged()) ); connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(watcherChanged()) ); }else{ watcher = 0; } } XDGDesktopList::~XDGDesktopList(){ //nothing special to do here } void XDGDesktopList::watcherChanged(){ QTimer::singleShot(1000, this, SLOT(updateList()) ); //1 second delay before check kicks off } void XDGDesktopList::updateList(){ //run the check routine QStringList appDirs = LXDG::systemApplicationDirs(); //get all system directories QStringList found, newfiles; //for avoiding duplicate apps (might be files with same name in different priority directories) QStringList oldkeys = files.keys(); bool appschanged = false; bool firstrun = lastCheck.isNull() || oldkeys.isEmpty(); lastCheck = QDateTime::currentDateTime(); //Variables for internal loop use only (to prevent re-initializing variable on every iteration) bool ok; QString path; QDir dir; QStringList apps; XDGDesktop dFile; for(int i=0; iQFileInfo(path).lastModified()) ){ //Re-use previous data for this file (nothing changed) dFile = files[path]; ok=true; }else{ ok=false; dFile = LXDG::loadDesktopFile(path,ok); //will change the "ok" variable as needed appschanged = true; //flag that something changed - needed to load a file } if(ok && !found.contains(dFile.name)){ if(!oldkeys.contains(path)){ newfiles << path; } //brand new file (not an update to a previously-read file) files.insert(path, dFile); found << dFile.name; oldkeys.removeAll(path); //make sure this key does not get cleaned up later } } //end loop over apps } //end loop over appDirs //Save the extra info to the internal lists if(!firstrun){ removedApps = oldkeys; }//files which were removed if(!firstrun){ newApps = newfiles; }//files which were added //Now go through and cleanup any old keys where the associated file does not exist anymore for(int i=0; iremovePaths(QStringList() << watcher->files() << watcher->directories()); watcher->addPaths(appDirs); if(appschanged){ emit appsUpdated(); } } } QList XDGDesktopList::apps(bool showAll, bool showHidden){ //showAll: include invalid files, showHidden: include NoShow/Hidden files QStringList keys = files.keys(); QList out; for(int i=0; iisDir()){ mime = "inode/directory"; //Special directory icons QString name = this->fileName().toLower(); if(name=="desktop"){ icon = "user-desktop"; } else if(name=="tmp"){ icon = "folder-temp"; } else if(name=="video" || name=="videos"){ icon = "folder-video"; } else if(name=="music" || name=="audio"){ icon = "folder-sound"; } else if(name=="projects" || name=="devel"){ icon = "folder-development"; } else if(name=="notes"){ icon = "folder-txt"; } else if(name=="downloads"){ icon = "folder-downloads"; } else if(name=="documents"){ icon = "folder-documents"; } else if(name=="images" || name=="pictures"){ icon = "folder-image"; } else if( !this->isReadable() ){ icon = "folder-locked"; } }else if( this->suffix()=="desktop"){ mime = "application/x-desktop"; icon = "application-x-desktop"; //default value bool ok = false; desk = LXDG::loadDesktopFile(this->absoluteFilePath(), ok); if(ok){ //use the specific desktop file info (if possible) if(!desk.icon.isEmpty()){ icon = desk.icon; } } }else{ //Generic file, just determine the mimetype mime = LXDG::findAppMimeForFile(this->fileName()); } } LFileInfo::LFileInfo(QString filepath){ //overloaded contructor this->setFile(filepath); loadExtraInfo(); } LFileInfo::LFileInfo(QFileInfo info){ //overloaded contructor this->swap(info); //use the given QFileInfo without re-loading it loadExtraInfo(); } //Functions for accessing the extra information // -- Return the mimetype for the file QString LFileInfo::mimetype(){ if(mime=="inode/directory"){ return ""; } else{ return mime; } } // -- Return the icon to use for this file QString LFileInfo::iconfile(){ if(!icon.isEmpty()){ return icon; }else{ if(!mime.isEmpty()){ QString tmp = mime; tmp.replace("/","-"); return tmp; }else if(this->isExecutable()){ return "application-x-executable"; } } return ""; //Fall back to nothing } // -- Check if this is an XDG desktop file bool LFileInfo::isDesktopFile(){ return (!desk.filePath.isEmpty()); } // -- Allow access to the XDG desktop data structure XDGDesktop* LFileInfo::XDG(){ return &desk; } // -- Check if this is a readable image file (for thumbnail support) bool LFileInfo::isImage(){ if(!mime.startsWith("image/")){ return false; } //quick return for non-image files //Check the Qt subsystems to see if this image file can be read return ( !LUtils::imageExtensions().filter(this->suffix().toLower()).isEmpty() ); } bool LFileInfo::isAVFile(){ return (mime.startsWith("audio/") || mime.startsWith("video/") ); } //==== LXDG Functions ==== XDGDesktop LXDG::loadDesktopFile(QString filePath, bool& ok){ //Create the outputs ok=false; XDGDesktop DF; DF.isHidden=false; DF.useTerminal=false; DF.startupNotify=false; DF.type = XDGDesktop::APP; DF.filePath = filePath; DF.lastRead = QDateTime::currentDateTime(); DF.exec = DF.tryexec = ""; // just to make sure this is initialized //Get the current localization code QString lang = QLocale::system().name(); //lang code QString slang = lang.section("_",0,0); //short lang code //Read in the File bool insection=false; bool inaction=false; QStringList file = LUtils::readFile(filePath); if(file.isEmpty()){ return DF; } //if(filePath.contains("pcbsd")){ qDebug() << "Check File:" << filePath << lang << slang; } XDGDesktopAction CDA; //current desktop action for(int i=0; i