//=========================================== // 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 "LuminaUtils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QStringList fav; inline QStringList ProcessRun(QString cmd, QStringList args){ //Assemble outputs QStringList out; out << "1" << ""; //error code, string output QProcess proc; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("LANG", "C"); env.insert("LC_MESSAGES", "C"); proc.setProcessEnvironment(env); proc.setProcessChannelMode(QProcess::MergedChannels); if(args.isEmpty()){ proc.start(cmd, QIODevice::ReadOnly); }else{ proc.start(cmd,args ,QIODevice::ReadOnly); } QString info; while(!proc.waitForFinished(1000)){ if(proc.state() == QProcess::NotRunning){ break; } //somehow missed the finished signal QString tmp = proc.readAllStandardOutput(); if(tmp.isEmpty()){ proc.terminate(); } else{ info.append(tmp); } } out[0] = QString::number(proc.exitCode()); out[1] = info+QString(proc.readAllStandardOutput()); return out; } //============= // LUtils Functions //============= QString LUtils::LuminaDesktopVersion(){ QString ver = "1.0.1"; #ifdef GIT_VERSION ver.append( QString(" (Git Revision: %1)").arg(GIT_VERSION) ); #endif return ver; } QString LUtils::LuminaDesktopBuildDate(){ #ifdef BUILD_DATE return BUILD_DATE; #endif return ""; } int LUtils::runCmd(QString cmd, QStringList args){ /*QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); if(args.isEmpty()){ proc.start(cmd); }else{ proc.start(cmd, args); } //if(!proc.waitForStarted(30000)){ return 1; } //process never started - max wait of 30 seconds while(!proc.waitForFinished(300)){ if(proc.state() == QProcess::NotRunning){ break; } //somehow missed the finished signal QCoreApplication::processEvents(); } int ret = proc.exitCode(); return ret;*/ QFuture future = QtConcurrent::run(ProcessRun, cmd, args); return future.result()[0].toInt(); //turn it back into an integer return code } QStringList LUtils::getCmdOutput(QString cmd, QStringList args){ /*QProcess proc; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("LANG", "C"); env.insert("LC_MESSAGES", "C"); proc.setProcessEnvironment(env); proc.setProcessChannelMode(QProcess::MergedChannels); if(args.isEmpty()){ proc.start(cmd); }else{ proc.start(cmd,args); } //if(!proc.waitForStarted(30000)){ return QStringList(); } //process never started - max wait of 30 seconds while(!proc.waitForFinished(300)){ if(proc.state() == QProcess::NotRunning){ break; } //somehow missed the finished signal QCoreApplication::processEvents(); } QStringList out = QString(proc.readAllStandardOutput()).split("\n"); return out;*/ QFuture future = QtConcurrent::run(ProcessRun, cmd, args); return future.result()[1].split("\n"); //Split the return message into lines } QStringList LUtils::readFile(QString filepath){ QStringList out; QFile file(filepath); if(file.open(QIODevice::Text | QIODevice::ReadOnly)){ QTextStream in(&file); while(!in.atEnd()){ out << in.readLine(); } file.close(); } return out; } bool LUtils::writeFile(QString filepath, QStringList contents, bool overwrite){ QFile file(filepath); if(file.exists() && !overwrite){ return false; } bool ok = false; if(contents.isEmpty()){ contents << "\n"; } if( file.open(QIODevice::WriteOnly | QIODevice::Truncate) ){ QTextStream out(&file); out << contents.join("\n"); if(!contents.last().isEmpty()){ out << "\n"; } //always end with a new line file.close(); ok = true; } return ok; } bool LUtils::isValidBinary(QString& bin){ if(!bin.startsWith("/")){ //Relative path: search for it on the current "PATH" settings QStringList paths = QString(qgetenv("PATH")).split(":"); for(int i=0; i fmt = QImageReader::supportedImageFormats(); for(int i=0; iremoveTranslator(cTrans); } //Setup the translator cTrans = new QTranslator(); //Use the shortened locale code if specific code does not have a corresponding file if(!QFile::exists(LOS::LuminaShare()+"i18n/"+appname+"_" + langCode + ".qm") && langCode!="en_US" ){ langCode.truncate( langCode.indexOf("_") ); } QString filename = appname+"_"+langCode+".qm"; //qDebug() << "FileName:" << filename << "Dir:" << LOS::LuminaShare()+"i18n/"; if( cTrans->load( filename, LOS::LuminaShare()+"i18n/" ) ){ app->installTranslator( cTrans ); }else{ //Translator could not be loaded for some reason cTrans = 0; if(langCode!="en_US"){ qWarning() << " - Could not load Locale:" << langCode; } } }else{ //Only going to set the encoding since no application given qDebug() << "Loading System Encoding:" << langEnc; } //Load current encoding for this locale QTextCodec::setCodecForLocale( QTextCodec::codecForName(langEnc.toUtf8()) ); return cTrans; } QStringList LUtils::knownLocales(){ QDir i18n = QDir(LOS::LuminaShare()+"i18n"); if( !i18n.exists() ){ return QStringList(); } QStringList files = i18n.entryList(QStringList() << "lumina-desktop_*.qm", QDir::Files, QDir::Name); if(files.isEmpty()){ return QStringList(); } //Now strip off the filename and just leave the locale tag for(int i=0; i=1000 && c=100){ //No decimel places num = QString::number(qRound(bytes)); }else if(bytes>=10){ //need 1 decimel place num = QString::number( (qRound(bytes*10)/10.0) ); }else if(bytes>1){ //need 2 decimel places num = QString::number( (qRound(bytes*100)/100.0) ); }else{ //Fully decimel (3 places) num = "0."+QString::number(qRound(bytes*1000)); } return (num+labs[c]); } QString LUtils::SecondsToDisplay(int secs){ if(secs < 0){ return "??"; } QString rem; //remaining if(secs > 3600){ int hours = secs/3600; rem.append( QString::number(hours)+"h "); secs = secs - (hours*3600); } if(secs > 60){ int min = secs/60; rem.append( QString::number(min)+"m "); secs = secs - (min*60); } if(secs > 0){ rem.append( QString::number(secs)+"s"); }else{ rem.append( "0s" ); } return rem; } //Various function for finding valid QtQuick plugins on the system bool LUtils::validQuickPlugin(QString ID){ return ( !LUtils::findQuickPluginFile(ID).isEmpty() ); } QString LUtils::findQuickPluginFile(QString ID){ if(ID.startsWith("quick-")){ ID = ID.section("-",1,50); } //just in case //Give preference to any user-supplied plugins (overwrites for system plugins) QString path = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/quickplugins/quick-"+ID+".qml"; if( QFile::exists(path) ){return path; } path = LOS::LuminaShare()+"quickplugins/quick-"+ID+".qml"; if( QFile::exists(path) ){return path; } return ""; //could not be found } QStringList LUtils::listQuickPlugins(){ QDir dir(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/quickplugins"); QStringList files = dir.entryList(QStringList() << "quick-*.qml", QDir::Files | QDir::NoDotAndDotDot, QDir::Name); dir.cd(LOS::LuminaShare()+"quickplugins"); files << dir.entryList(QStringList() << "quick-*.qml", QDir::Files | QDir::NoDotAndDotDot, QDir::Name); for(int i=0; i, sym-links in the ~/.lumina/favorites dir} //Include 0.8.4-devel versions in this upgrade (need to distinguish b/w devel and release versions later somehow) QDir favdir(QDir::homePath()+"/.lumina/favorites"); QFileInfoList symlinks = favdir.entryInfoList(QDir::Files | QDir::Dirs | QDir::System | QDir::NoDotAndDotDot); QStringList favfile = LUtils::listFavorites(); //just in case some already exist bool newentry = false; for(int i=0; iscreenCount(); i++){ if(desk->screenGeometry(i).x()==0){ screen = QString::number(i); screenGeom = desk->screenGeometry(i); break; } } //Now setup the default "desktopsettings.conf" and "sessionsettings.conf" files QStringList deskset, sesset;//, lopenset; // -- SESSION SETTINGS -- QStringList tmp = sysDefaults.filter("session_"); if(tmp.isEmpty()){ tmp = sysDefaults.filter("session."); }//for backwards compat sesset << "[General]"; //everything is in this section sesset << "DesktopVersion="+LUtils::LuminaDesktopVersion(); for(int i=0; i 1000000], [1.2.3 -> 1002003], [0.6.1 -> 6001] //returns true if something changed int oldversion = LUtils::VersionStringToNumber(lastversion); int nversion = LUtils::VersionStringToNumber(QApplication::applicationVersion()); bool newversion = ( oldversion < nversion ); //increasing version number bool newrelease = ( lastversion.contains("-devel", Qt::CaseInsensitive) && QApplication::applicationVersion().contains("-release", Qt::CaseInsensitive) ); //Moving from devel to release QString confdir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/"; //Check for the desktop settings file QString dset = confdir+"desktopsettings.conf"; bool firstrun = false; if(!QFile::exists(dset) || oldversion < 5000){ if( oldversion < 100000 && nversion>=100000 ){ system("rm -rf ~/.lumina"); qDebug() << "Current desktop settings obsolete: Re-implementing defaults"; } else{ firstrun = true; } LUtils::LoadSystemDefaults(); } //Convert the favorites framework as necessary (change occured with 0.8.4) if(newversion || newrelease){ LUtils::upgradeFavorites(oldversion); } //Convert any "userbutton" and "appmenu" panel plugins to the new "systemstart" plugin (0.8.7) /*if(oldversion <= 8007 && (newversion || newrelease) && nversion < 8008){ QSettings dset(QSettings::UserScope, "LuminaDE","desktopsettings"); QStringList plugKeys = dset.allKeys().filter("panel").filter("/pluginlist"); for(int i=0; i systemstart conversion plugs = plugs.join(";;;;").replace("userbutton","systemstart").replace("appmenu","systemstart").split(";;;;"); //Remove any system dashboard plugins plugs.removeAll("systemdashboard"); //Now save that back to the file dset.setValue(plugKeys[i], plugs); } //Also remove any "desktopview" desktop plugin and enable the automatic desktop icons instead plugKeys = dset.allKeys().filter("desktop-").filter("/pluginlist"); for(int i=0; i..) maj = mid = min = 0; bool ok = true; maj = version.section(".",0,0).toInt(&ok); if(ok){ mid = version.section(".",1,1).toInt(&ok); }else{ maj = 0; } if(ok){ min = version.section(".",2,2).toInt(&ok); }else{ mid = 0; } if(!ok){ min = 0; } //Now assemble the number //NOTE: This format allows numbers to be anywhere from 0->999 without conflict return (maj*1000000 + mid*1000 + min); } // ======================= // RESIZEMENU CLASS // ======================= ResizeMenu::ResizeMenu(QWidget *parent) : QMenu(parent){ this->setContentsMargins(1,1,1,1); this->setMouseTracking(true); resizeSide = NONE; cAct = new QWidgetAction(this); contents = 0; connect(this, SIGNAL(aboutToShow()), this, SLOT(clearFlags()) ); connect(this, SIGNAL(aboutToHide()), this, SLOT(clearFlags()) ); connect(cAct, SIGNAL(hovered()), this, SLOT(clearFlags()) ); } ResizeMenu::~ResizeMenu(){ } void ResizeMenu::setContents(QWidget *con){ this->clear(); cAct->setDefaultWidget(con); this->addAction(cAct); contents = con; //save for later contents->setCursor(Qt::ArrowCursor); } void ResizeMenu::mouseMoveEvent(QMouseEvent *ev){ QRect geom = this->geometry(); //Note: The exact position does not matter as much as the size // since the window will be moved again the next time it is shown // The "-2" in the sizing below accounts for the menu margins QPoint gpos = this->mapToGlobal(ev->pos()); bool handled = false; switch(resizeSide){ case TOP: if(gpos.y() >= geom.bottom()-1){ break; } geom.setTop(gpos.y()); this->setGeometry(geom); if(contents!=0){ contents->setFixedSize(QSize(geom.width()-2, geom.height()-2));} handled = true; break; case BOTTOM: if(gpos.y() <= geom.top()+1){ break; } geom.setBottom( gpos.y()); this->setGeometry(geom); if(contents!=0){ contents->setFixedSize(QSize(geom.width()-2, geom.height()-2));} handled = true; break; case LEFT: if(gpos.x() >= geom.right()-1){ break; } geom.setLeft(gpos.x()); this->setGeometry(geom); if(contents!=0){ contents->setFixedSize(QSize(geom.width()-2, geom.height()-2));} handled = true; break; case RIGHT: if(gpos.x() <= geom.left()+1){ break; } geom.setRight(gpos.x()); this->setGeometry(geom); if(contents!=0){ contents->setFixedSize(QSize(geom.width()-2, geom.height()-2));} handled = true; break; default: //NONE //qDebug() << " - Mouse At:" << ev->pos(); //Just adjust the mouse cursor which is shown if(ev->pos().x()<=1 && ev->pos().x() >= -1){ this->setCursor(Qt::SizeHorCursor); } else if(ev->pos().x() >= this->width()-1 && ev->pos().x() <= this->width()+1){ this->setCursor(Qt::SizeHorCursor); } else if(ev->pos().y()<=1 && ev->pos().y() >= -1){ this->setCursor(Qt::SizeVerCursor); } else if(ev->pos().y() >= this->height()-1 && ev->pos().y() <= this->height()+1){ this->setCursor(Qt::SizeVerCursor); } else{ this->setCursor(Qt::ArrowCursor); } } if(!handled){ QMenu::mouseMoveEvent(ev); } //do normal processing as well } void ResizeMenu::mousePressEvent(QMouseEvent *ev){ bool used = false; if(ev->buttons().testFlag(Qt::LeftButton) && resizeSide==NONE){ //qDebug() << "Mouse Press Event:" << ev->pos() << resizeSide; if(ev->pos().x()<=1 && ev->pos().x() >= -1){resizeSide = LEFT; used = true;} else if(ev->pos().x() >= this->width()-1 && ev->pos().x() <= this->width()+1){ resizeSide = RIGHT; used = true;} else if(ev->pos().y()<=1 && ev->pos().y() >= -1){ resizeSide = TOP; used = true; } else if(ev->pos().y() >= this->height()-1 && ev->pos().y() <= this->height()+1){ resizeSide = BOTTOM; used = true; } } if(used){ ev->accept(); this->grabMouse(); } else{ QMenu::mousePressEvent(ev); } //do normal processing } void ResizeMenu::mouseReleaseEvent(QMouseEvent *ev){ this->releaseMouse(); if(ev->button() == Qt::LeftButton && resizeSide!=NONE ){ //qDebug() << "Mouse Release Event:" << ev->pos() << resizeSide; resizeSide = NONE; emit MenuResized(contents->size()); ev->accept(); }else{ QMenu::mouseReleaseEvent(ev); //do normal processing } }