2019-03-23 17:49:09 +02:00
/*
* Copyright 2019 Michail Vourlakos < mvourlakos @ gmail . com >
*
* This file is part of Latte - Dock
*
* Latte - Dock is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
*
* Latte - Dock is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "factory.h"
// local
2019-05-09 17:57:12 +03:00
# include "../layouts/importer.h"
2019-03-23 17:49:09 +02:00
// Qt
# include <QDebug>
# include <QDir>
2019-03-29 19:59:15 +02:00
# include <QDirIterator>
2019-03-31 14:53:12 +03:00
# include <QMessageBox>
2019-03-29 19:59:15 +02:00
# include <QProcess>
2019-03-28 21:51:24 +02:00
# include <QTemporaryDir>
2019-12-31 15:49:53 +02:00
# include <QTimer>
2019-03-23 17:49:09 +02:00
// KDE
2019-03-29 21:09:28 +02:00
# include <KDirWatch>
2019-03-28 21:51:24 +02:00
# include <KLocalizedString>
# include <KNotification>
2019-03-23 17:49:09 +02:00
# include <KPluginMetaData>
2019-03-28 21:51:24 +02:00
# include <KArchive/KTar>
# include <KArchive/KZip>
# include <KArchive/KArchiveEntry>
# include <KArchive/KArchiveDirectory>
2019-03-28 23:18:15 +02:00
# include <KNewStuff3/KNS3/DownloadDialog>
2019-03-23 17:49:09 +02:00
namespace Latte {
namespace Indicator {
Factory : : Factory ( QObject * parent )
: QObject ( parent )
{
2019-03-28 23:18:15 +02:00
m_parentWidget = new QWidget ( ) ;
2019-03-29 21:09:28 +02:00
2019-12-31 15:49:53 +02:00
m_mainPaths = Latte : : Layouts : : Importer : : standardPaths ( ) ;
2019-03-29 21:09:28 +02:00
2019-12-31 15:49:53 +02:00
for ( int i = 0 ; i < m_mainPaths . count ( ) ; + + i ) {
m_mainPaths [ i ] = m_mainPaths [ i ] + " /latte/indicators " ;
discoverNewIndicators ( m_mainPaths [ i ] ) ;
2019-03-29 21:09:28 +02:00
}
//! track paths for changes
2019-12-31 15:49:53 +02:00
for ( const auto & dir : m_mainPaths ) {
2019-03-29 21:09:28 +02:00
KDirWatch : : self ( ) - > addDir ( dir ) ;
}
connect ( KDirWatch : : self ( ) , & KDirWatch : : dirty , this , [ & ] ( const QString & path ) {
2019-12-31 15:49:53 +02:00
if ( m_indicatorsPaths . contains ( path ) ) {
//! indicator updated
reload ( path ) ;
} else if ( m_mainPaths . contains ( path ) ) {
//! consider indicator addition
discoverNewIndicators ( path ) ;
}
} ) ;
connect ( KDirWatch : : self ( ) , & KDirWatch : : deleted , this , [ & ] ( const QString & path ) {
if ( m_indicatorsPaths . contains ( path ) ) {
//! indicator removed
removeIndicatorRecords ( path ) ;
2019-03-29 21:09:28 +02:00
}
} ) ;
2019-03-24 18:44:27 +02:00
qDebug ( ) < < m_plugins [ " org.kde.latte.default " ] . name ( ) ;
2019-03-23 17:49:09 +02:00
}
Factory : : ~ Factory ( )
{
2019-03-28 23:18:15 +02:00
m_parentWidget - > deleteLater ( ) ;
2019-03-23 17:49:09 +02:00
}
2019-03-31 14:53:12 +03:00
bool Factory : : pluginExists ( QString id ) const
{
return m_plugins . contains ( id ) ;
}
2019-03-26 19:31:52 +02:00
int Factory : : customPluginsCount ( )
{
return m_customPluginIds . count ( ) ;
}
QStringList Factory : : customPluginIds ( )
{
return m_customPluginIds ;
}
QStringList Factory : : customPluginNames ( )
{
return m_customPluginNames ;
}
2019-03-31 14:53:12 +03:00
QStringList Factory : : customLocalPluginIds ( )
{
return m_customLocalPluginIds ;
}
2019-03-26 19:31:52 +02:00
2019-03-23 17:49:09 +02:00
KPluginMetaData Factory : : metadata ( QString pluginId )
{
if ( m_plugins . contains ( pluginId ) ) {
return m_plugins [ pluginId ] ;
}
return KPluginMetaData ( ) ;
}
2019-12-31 15:49:53 +02:00
void Factory : : reload ( const QString & indicatorPath )
2019-03-23 17:49:09 +02:00
{
2019-12-31 15:49:53 +02:00
QString pluginChangedId ;
2019-03-23 17:49:09 +02:00
2019-12-31 15:49:53 +02:00
if ( ! indicatorPath . isEmpty ( ) & & indicatorPath ! = " . " & & indicatorPath ! = " .. " ) {
QString metadataFile = indicatorPath + " /metadata.desktop " ;
2019-03-23 17:49:09 +02:00
2019-12-31 15:49:53 +02:00
if ( QFileInfo ( metadataFile ) . exists ( ) ) {
KPluginMetaData metadata = KPluginMetaData : : fromDesktopFile ( metadataFile ) ;
2019-03-23 17:49:09 +02:00
2019-12-31 15:49:53 +02:00
if ( metadataAreValid ( metadata ) ) {
pluginChangedId = metadata . pluginId ( ) ;
QString uiFile = indicatorPath + " /package/ " + metadata . value ( " X-Latte-MainScript " ) ;
2019-03-23 17:49:09 +02:00
2019-12-31 15:49:53 +02:00
if ( ! m_plugins . contains ( metadata . pluginId ( ) ) ) {
m_plugins [ metadata . pluginId ( ) ] = metadata ;
}
2019-03-23 17:49:09 +02:00
2019-12-31 15:49:53 +02:00
if ( QFileInfo ( uiFile ) . exists ( ) ) {
m_pluginUiPaths [ metadata . pluginId ( ) ] = QFileInfo ( uiFile ) . absolutePath ( ) ;
}
2019-03-26 19:31:52 +02:00
2019-12-31 15:49:53 +02:00
if ( ( metadata . pluginId ( ) ! = " org.kde.latte.default " )
2020-01-12 16:43:52 +02:00
& & ( metadata . pluginId ( ) ! = " org.kde.latte.plasma " )
& & ( metadata . pluginId ( ) ! = " org.kde.latte.plasmatabstyle " ) ) {
2019-03-26 19:31:52 +02:00
2021-01-23 15:04:05 +02:00
//! find correct alphabetical position
int newPos = - 1 ;
if ( ! m_customPluginIds . contains ( metadata . pluginId ( ) ) ) {
for ( int i = 0 ; i < m_customPluginNames . count ( ) ; + + i ) {
if ( QString : : compare ( metadata . name ( ) , m_customPluginNames [ i ] , Qt : : CaseInsensitive ) < = 0 ) {
newPos = i ;
break ;
}
}
}
2019-12-31 15:49:53 +02:00
if ( ! m_customPluginIds . contains ( metadata . pluginId ( ) ) ) {
2021-01-23 15:04:05 +02:00
if ( newPos = = - 1 ) {
m_customPluginIds < < metadata . pluginId ( ) ;
} else {
m_customPluginIds . insert ( newPos , metadata . pluginId ( ) ) ;
}
2019-12-31 15:49:53 +02:00
}
2019-03-31 14:53:12 +03:00
2019-12-31 15:49:53 +02:00
if ( ! m_customPluginNames . contains ( metadata . name ( ) ) ) {
2021-01-23 15:04:05 +02:00
if ( newPos = = - 1 ) {
m_customPluginNames < < metadata . name ( ) ;
} else {
m_customPluginNames . insert ( newPos , metadata . name ( ) ) ;
}
2019-12-31 15:49:53 +02:00
}
}
2019-06-03 19:09:08 +03:00
2019-12-31 15:49:53 +02:00
if ( indicatorPath . startsWith ( QDir : : homePath ( ) ) ) {
m_customLocalPluginIds < < metadata . pluginId ( ) ;
}
}
2019-06-03 19:09:08 +03:00
2019-12-31 15:49:53 +02:00
qDebug ( ) < < " Indicator Package Loaded ::: " < < metadata . name ( ) < < " [ " < < metadata . pluginId ( ) < < " ] " < < " - [ " < < indicatorPath < < " ] " ;
2019-06-20 17:42:49 +03:00
2019-12-31 15:49:53 +02:00
/*qDebug() << " Indicator value ::: " << metadata.pluginId();
2019-03-23 17:49:09 +02:00
qDebug ( ) < < " Indicator value ::: " < < metadata . fileName ( ) ;
qDebug ( ) < < " Indicator value ::: " < < metadata . value ( " X-Latte-MainScript " ) ;
qDebug ( ) < < " Indicator value ::: " < < metadata . value ( " X-Latte-ConfigUi " ) ;
qDebug ( ) < < " Indicator value ::: " < < metadata . value ( " X-Latte-ConfigXml " ) ; */
}
}
2019-03-26 19:31:52 +02:00
2019-12-31 15:49:53 +02:00
if ( ! pluginChangedId . isEmpty ( ) ) {
emit indicatorChanged ( pluginChangedId ) ;
}
}
void Factory : : discoverNewIndicators ( const QString & main )
{
if ( ! m_mainPaths . contains ( main ) ) {
return ;
}
QDirIterator indicatorsDirs ( main , QDir : : Dirs | QDir : : NoSymLinks | QDir : : NoDotAndDotDot , QDirIterator : : NoIteratorFlags ) ;
while ( indicatorsDirs . hasNext ( ) ) {
indicatorsDirs . next ( ) ;
QString iPath = indicatorsDirs . filePath ( ) ;
if ( ! m_indicatorsPaths . contains ( iPath ) ) {
m_indicatorsPaths < < iPath ;
KDirWatch : : self ( ) - > addDir ( iPath ) ;
reload ( iPath ) ;
}
}
}
void Factory : : removeIndicatorRecords ( const QString & path )
{
if ( m_indicatorsPaths . contains ( path ) ) {
QString pluginId = path . section ( ' / ' , - 1 ) ;
m_plugins . remove ( pluginId ) ;
m_pluginUiPaths . remove ( pluginId ) ;
int pos = m_customPluginIds . indexOf ( pluginId ) ;
m_customPluginIds . removeAt ( pos ) ;
m_customPluginNames . removeAt ( pos ) ;
m_customLocalPluginIds . removeAll ( pluginId ) ;
m_indicatorsPaths . removeAll ( path ) ;
KDirWatch : : self ( ) - > removeDir ( path ) ;
//! delay informing the removal in case it is just an update
QTimer : : singleShot ( 1000 , [ this , pluginId ] ( ) {
emit indicatorRemoved ( pluginId ) ;
} ) ;
}
}
bool Factory : : isCustomType ( const QString & id ) const
{
2020-01-12 16:43:52 +02:00
return ( ( id ! = " org.kde.latte.default " ) & & ( id ! = " org.kde.latte.plasma " ) & & ( id ! = " org.kde.latte.plasmatabstyle " ) ) ;
2019-03-23 17:49:09 +02:00
}
2019-03-28 21:51:24 +02:00
bool Factory : : metadataAreValid ( KPluginMetaData & metadata )
{
return metadata . isValid ( )
& & metadata . category ( ) = = " Latte Indicator "
& & ! metadata . value ( " X-Latte-MainScript " ) . isEmpty ( ) ;
}
bool Factory : : metadataAreValid ( QString & file )
{
if ( QFileInfo ( file ) . exists ( ) ) {
KPluginMetaData metadata = KPluginMetaData : : fromDesktopFile ( file ) ;
2019-05-28 19:02:04 +03:00
return metadata . isValid ( ) ;
2019-03-28 21:51:24 +02:00
}
return false ;
}
2019-06-03 19:09:08 +03:00
QString Factory : : uiPath ( QString pluginName ) const
{
if ( ! m_pluginUiPaths . contains ( pluginName ) ) {
return " " ;
}
return m_pluginUiPaths [ pluginName ] ;
}
2019-03-28 21:51:24 +02:00
2020-04-23 19:52:51 +03:00
Latte : : ImportExport : : State Factory : : importIndicatorFile ( QString compressedFile )
2019-03-28 21:51:24 +02:00
{
auto showNotificationError = [ ] ( ) {
auto notification = new KNotification ( " import-fail " , KNotification : : CloseOnTimeout ) ;
notification - > setText ( i18n ( " Failed to import indicator " ) ) ;
notification - > sendEvent ( ) ;
} ;
auto showNotificationSucceed = [ ] ( QString name , bool updated ) {
auto notification = new KNotification ( " import-done " , KNotification : : CloseOnTimeout ) ;
notification - > setText ( updated ? i18nc ( " indicator_name, imported updated " , " %0 indicator updated successfully " ) . arg ( name ) :
i18nc ( " indicator_name, imported success " , " %0 indicator installed successfully " ) . arg ( name ) ) ;
notification - > sendEvent ( ) ;
} ;
KArchive * archive ;
KZip * zipArchive = new KZip ( compressedFile ) ;
zipArchive - > open ( QIODevice : : ReadOnly ) ;
//! if the file isnt a zip archive
if ( ! zipArchive - > isOpen ( ) ) {
delete zipArchive ;
KTar * tarArchive = new KTar ( compressedFile , QStringLiteral ( " application/x-tar " ) ) ;
tarArchive - > open ( QIODevice : : ReadOnly ) ;
if ( ! tarArchive - > isOpen ( ) ) {
delete tarArchive ;
showNotificationError ( ) ;
2020-04-23 19:52:51 +03:00
return Latte : : ImportExport : : FailedState ;
2019-03-28 21:51:24 +02:00
} else {
archive = tarArchive ;
}
} else {
archive = zipArchive ;
}
QTemporaryDir archiveTempDir ;
archive - > directory ( ) - > copyTo ( archiveTempDir . path ( ) ) ;
//metadata file
2019-03-29 19:59:15 +02:00
QString packagePath = archiveTempDir . path ( ) ;
2019-03-28 21:51:24 +02:00
QString metadataFile = archiveTempDir . path ( ) + " /metadata.desktop " ;
2019-03-29 19:59:15 +02:00
if ( ! QFileInfo ( metadataFile ) . exists ( ) ) {
QDirIterator iter ( archiveTempDir . path ( ) , QDir : : Dirs | QDir : : NoDotAndDotDot ) ;
while ( iter . hasNext ( ) ) {
QString currentPath = iter . next ( ) ;
QString tempMetadata = currentPath + " /metadata.desktop " ;
if ( QFileInfo ( tempMetadata ) . exists ( ) ) {
metadataFile = tempMetadata ;
packagePath = currentPath ;
}
}
}
2019-03-28 21:51:24 +02:00
KPluginMetaData metadata = KPluginMetaData : : fromDesktopFile ( metadataFile ) ;
if ( metadataAreValid ( metadata ) ) {
2019-05-09 17:57:12 +03:00
QStringList standardPaths = Latte : : Layouts : : Importer : : standardPaths ( ) ;
2019-03-28 21:51:24 +02:00
QString installPath = standardPaths [ 0 ] + " /latte/indicators/ " + metadata . pluginId ( ) ;
bool updated { QDir ( installPath ) . exists ( ) } ;
2019-03-29 19:59:15 +02:00
if ( QDir ( installPath ) . exists ( ) ) {
QDir ( installPath ) . removeRecursively ( ) ;
}
QProcess process ;
process . start ( QString ( " mv " + packagePath + " " + installPath ) ) ;
process . waitForFinished ( ) ;
QString output ( process . readAllStandardOutput ( ) ) ;
2019-03-28 21:51:24 +02:00
2019-03-29 19:59:15 +02:00
showNotificationSucceed ( metadata . name ( ) , updated ) ;
2020-04-23 19:52:51 +03:00
return Latte : : ImportExport : : InstalledState ;
2019-03-28 21:51:24 +02:00
}
showNotificationError ( ) ;
2020-04-23 19:52:51 +03:00
return Latte : : ImportExport : : FailedState ;
2019-03-28 21:51:24 +02:00
}
2019-03-31 14:53:12 +03:00
void Factory : : removeIndicator ( QString id )
{
if ( m_plugins . contains ( id ) ) {
QString pluginName = m_plugins [ id ] . name ( ) ;
auto msg = new QMessageBox ( m_parentWidget ) ;
msg - > setIcon ( QMessageBox : : Warning ) ;
msg - > setWindowTitle ( i18n ( " Remove Indicator " ) ) ;
msg - > setText (
i18n ( " Do you want to remove <b>%0</b> indicator from your system? " ) . arg ( pluginName ) ) ;
msg - > setStandardButtons ( QMessageBox : : Yes | QMessageBox : : No ) ;
msg - > setDefaultButton ( QMessageBox : : No ) ;
connect ( msg , & QMessageBox : : finished , this , [ & , msg , id , pluginName ] ( int result ) {
auto showRemovedSucceed = [ ] ( QString name ) {
auto notification = new KNotification ( " remove-done " , KNotification : : CloseOnTimeout ) ;
notification - > setText ( i18nc ( " indicator_name, removed success " , " <b>%0</b> indicator removed successfully " ) . arg ( name ) ) ;
notification - > sendEvent ( ) ;
} ;
if ( result = = QMessageBox : : Yes ) {
qDebug ( ) < < " Trying to remove indicator :: " < < id ;
QProcess process ;
process . start ( QString ( " kpackagetool5 -r " + id + " -t Latte/Indicator " ) ) ;
process . waitForFinished ( ) ;
showRemovedSucceed ( pluginName ) ;
}
} ) ;
msg - > open ( ) ;
}
}
2019-03-28 23:18:15 +02:00
void Factory : : downloadIndicator ( )
{
KNS3 : : DownloadDialog dialog ( QStringLiteral ( " latte-indicators.knsrc " ) , m_parentWidget ) ;
dialog . exec ( ) ;
}
2019-03-23 17:49:09 +02:00
}
}