File indexing completed on 2024-05-19 04:48:46
0001 /**************************************************************************************** 0002 * Copyright (c) 2010 Rick W. Chen <stuffcorpse@archlinux.us> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #define DEBUG_PREFIX "ScriptsConfig" 0018 0019 #include "ScriptsConfig.h" 0020 0021 #include "amarokconfig.h" 0022 #include "configdialog/ConfigDialog.h" 0023 #include "core/support/Amarok.h" 0024 #include "core/support/Debug.h" 0025 #include "scripting/scriptmanager/ScriptManager.h" 0026 #include "ScriptSelector.h" 0027 #include "ui_ScriptsConfig.h" 0028 0029 #include <KMessageBox> 0030 #include <KNS3/DownloadDialog> 0031 #include <KPluginInfo> 0032 #include <KPluginSelector> 0033 #include <QStandardPaths> 0034 #include <KTar> 0035 #include <KZip> 0036 0037 #include <QFileDialog> 0038 #include <QTemporaryFile> 0039 #include <QTimer> 0040 #include <QVBoxLayout> 0041 #include <QScrollBar> 0042 #include <QMimeDatabase> 0043 #include <QMimeType> 0044 0045 ScriptsConfig::ScriptsConfig( Amarok2ConfigDialog *parent ) 0046 : ConfigDialogBase( parent ) 0047 , m_configChanged( false ) 0048 , m_parent( parent ) 0049 , m_oldSelector( nullptr ) 0050 { 0051 DEBUG_BLOCK 0052 Ui::ScriptsConfig gui; 0053 gui.setupUi( this ); 0054 0055 m_uninstallButton = gui.uninstallButton; 0056 m_timer = new QTimer(this); 0057 connect( m_timer, &QTimer::timeout, this, &ScriptsConfig::slotUpdateScripts ); 0058 m_timer->setInterval( 200 ); 0059 0060 // Load config 0061 gui.kcfg_AutoUpdateScripts->setChecked( AmarokConfig::autoUpdateScripts() ); 0062 gui.manageButton->setIcon( QIcon::fromTheme( QStringLiteral("get-hot-new-stuff-amarok") ) ); 0063 connect( gui.manageButton, &QAbstractButton::clicked, 0064 this, &ScriptsConfig::slotManageScripts ); 0065 connect( gui.installButton, &QAbstractButton::clicked, 0066 this, &ScriptsConfig::installLocalScript ); 0067 0068 m_selector = gui.scriptSelector; 0069 m_verticalLayout = gui.verticalLayout; 0070 slotReloadScriptSelector(); 0071 0072 connect( gui.reloadButton, &QAbstractButton::clicked, m_timer, QOverload<>::of(&QTimer::start) ); 0073 connect( gui.uninstallButton, &QAbstractButton::clicked, this, &ScriptsConfig::slotUninstallScript ); 0074 0075 connect( ScriptManager::instance(), &ScriptManager::scriptsChanged, 0076 this, &ScriptsConfig::slotReloadScriptSelector ); 0077 0078 this->setEnabled( AmarokConfig::enableScripts() ); 0079 } 0080 0081 ScriptsConfig::~ScriptsConfig() 0082 {} 0083 0084 void 0085 ScriptsConfig::slotManageScripts() 0086 { 0087 QStringList updateScriptsList; 0088 KNS3::DownloadDialog dialog(QStringLiteral("amarok.knsrc"), this); 0089 dialog.exec(); 0090 0091 if( !dialog.installedEntries().isEmpty() || !dialog.changedEntries().isEmpty() ) 0092 m_timer->start(); 0093 } 0094 0095 void 0096 ScriptsConfig::updateSettings() 0097 { 0098 DEBUG_BLOCK 0099 if( m_configChanged ) 0100 { 0101 m_selector->save(); 0102 ScriptManager::instance()->configChanged( true ); 0103 } 0104 } 0105 0106 bool 0107 ScriptsConfig::hasChanged() 0108 { 0109 return m_configChanged; 0110 } 0111 0112 bool 0113 ScriptsConfig::isDefault() 0114 { 0115 return false; 0116 } 0117 0118 void 0119 ScriptsConfig::slotConfigChanged( bool changed ) 0120 { 0121 m_configChanged = changed; 0122 if( changed ) 0123 debug() << "config changed"; 0124 } 0125 0126 void 0127 ScriptsConfig::installLocalScript() 0128 { 0129 DEBUG_BLOCK 0130 // where's this config stored anyway, use amarokconfig instead? 0131 // the script can actually be updated if you get the folder name right 0132 int response = KMessageBox::warningContinueCancel( this, i18n( "Manually installed scripts " 0133 "cannot be automatically updated, continue?" ), QString(), KStandardGuiItem::cont() 0134 , KStandardGuiItem::cancel(), QStringLiteral("manualScriptInstallWarning") ); 0135 if( response == KMessageBox::Cancel ) 0136 return; 0137 0138 QString filePath = QFileDialog::getOpenFileName( this, i18n( "Select Archived Script" ) ); 0139 if( filePath.isEmpty() ) 0140 return; 0141 0142 QString fileName = QFileInfo( filePath ).fileName(); 0143 QMimeDatabase db; 0144 QMimeType mimeType = db.mimeTypeForFile( filePath ); 0145 QScopedPointer<KArchive> archive; 0146 if( mimeType.inherits( QStringLiteral("application/zip") ) ) 0147 archive.reset( new KZip( filePath ) ); 0148 else 0149 archive.reset( new KTar( filePath ) ); 0150 0151 if( !archive || !archive->open( QIODevice::ReadOnly ) ) 0152 { 0153 KMessageBox::error( this, i18n( "Invalid Archive" ) ); 0154 return; 0155 } 0156 0157 QString destination = QStandardPaths::writableLocation( QStandardPaths::GenericDataLocation ) + QStringLiteral("amarok/scripts/") + fileName + '/'; 0158 const KArchiveDirectory* const archiveDir = archive->directory(); 0159 const QDir dir( destination ); 0160 const KArchiveFile *specFile = findSpecFile( archiveDir ); 0161 if( !specFile ) 0162 { 0163 KMessageBox::error( this, i18n( "Invalid Script File" ) ); 0164 return; 0165 } 0166 0167 QTemporaryFile tempFile; 0168 tempFile.open(); 0169 QIODevice *device = specFile->createDevice(); 0170 tempFile.write( device->readAll() ); 0171 delete device; 0172 tempFile.close(); 0173 0174 KPluginInfo newScriptInfo( tempFile.fileName() ); 0175 if( !newScriptInfo.isValid() ) 0176 { 0177 KMessageBox::error( this, i18n( "Invalid Script File" ) ); 0178 return; 0179 } 0180 0181 if( ScriptManager::instance()->m_scripts.contains( newScriptInfo.pluginName() ) ) 0182 { 0183 QString existingVersion = ScriptManager::instance()->m_scripts[ newScriptInfo.pluginName() ]->info().version(); 0184 QString message = i18n( "Another script with the name %1 already exists\nExisting Script's " 0185 "Version: %2\nSelected Script's Version: %3", newScriptInfo.name() 0186 , existingVersion, newScriptInfo.version() ); 0187 KMessageBox::error( this, message ); 0188 return; 0189 } 0190 0191 for( int i = 1; dir.exists( destination ); ++i ) 0192 destination += i; 0193 dir.mkpath( destination ); 0194 archiveDir->copyTo( destination ); 0195 KMessageBox::information( this, i18n( "The script %1 was successfully installed", newScriptInfo.name() ) ); 0196 m_timer->start(); 0197 } 0198 0199 void 0200 ScriptsConfig::slotReloadScriptSelector() 0201 { 0202 DEBUG_BLOCK 0203 m_oldSelector = m_selector; 0204 m_selector = new ScriptSelector( this ); 0205 QString key = QStringLiteral( "Generic" ); 0206 m_selector->addScripts( ScriptManager::instance()->scripts( key ), 0207 KPluginSelector::ReadConfigFile, i18n("Generic"), key ); 0208 0209 key = QStringLiteral( "Lyrics" ); 0210 m_selector->addScripts( ScriptManager::instance()->scripts( key ), 0211 KPluginSelector::ReadConfigFile, i18n("Lyrics"), key ); 0212 0213 key = QStringLiteral( "Scriptable Service" ); 0214 m_selector->addScripts( ScriptManager::instance()->scripts( key ), 0215 KPluginSelector::ReadConfigFile, i18n("Scriptable Service"), key ); 0216 connect( m_selector, &ScriptSelector::changed, this, &ScriptsConfig::slotConfigChanged ); 0217 connect( m_selector, &ScriptSelector::filtered, m_uninstallButton, &QPushButton::setDisabled ); 0218 connect( m_selector, &ScriptSelector::changed, 0219 qobject_cast<Amarok2ConfigDialog*>(m_parent), &Amarok2ConfigDialog::updateButtons ); 0220 0221 m_verticalLayout->insertWidget( 0, m_selector ); 0222 m_verticalLayout->removeWidget( m_oldSelector ); 0223 0224 m_selector->setFilter( m_oldSelector->filter() ); 0225 QTimer::singleShot( 0, this, &ScriptsConfig::restoreScrollBar ); 0226 } 0227 0228 void 0229 ScriptsConfig::restoreScrollBar() 0230 { 0231 if( !m_oldSelector ) 0232 return; 0233 m_selector->setVerticalPosition( m_oldSelector->verticalPosition() ); 0234 m_oldSelector->deleteLater(); 0235 } 0236 0237 void 0238 ScriptsConfig::slotUpdateScripts() 0239 { 0240 m_timer->stop(); 0241 ScriptManager::instance()->updateAllScripts(); 0242 } 0243 0244 void 0245 ScriptsConfig::slotUninstallScript() 0246 { 0247 DEBUG_BLOCK 0248 if( !ScriptManager::instance()->m_scripts.contains( m_selector->currentItem() ) ) 0249 return; 0250 0251 ScriptItem *item = ScriptManager::instance()->m_scripts.value( m_selector->currentItem() ); 0252 /* 0253 int response = KMessageBox::warningContinueCancel( this, i18n( "You are advised to only uninstall manually " 0254 "installed scripts using this button." ) ); 0255 if( response == KMessageBox::Cancel ) 0256 return; 0257 */ 0258 0259 QFileInfo specFile( item->specPath() ); 0260 qDebug() << "About to remove folder " << specFile.path(); 0261 QDir( specFile.path() ).removeRecursively(); 0262 m_timer->start(); 0263 } 0264 0265 const KArchiveFile* 0266 ScriptsConfig::findSpecFile( const KArchiveDirectory *dir ) const 0267 { 0268 foreach( const QString &entry, dir->entries() ) 0269 { 0270 if( dir->entry( entry )->isFile() ) 0271 { 0272 if( entry == QLatin1String("script.spec") ) 0273 return static_cast<const KArchiveFile*>( dir->entry( entry ) ); 0274 } 0275 else 0276 { 0277 if( entry != QLatin1String(".") && entry != QLatin1String("..") ) 0278 { 0279 const KArchiveDirectory *subDir = static_cast<const KArchiveDirectory*>( dir->entry( entry ) ); 0280 if( subDir ) 0281 { 0282 const KArchiveFile *file = findSpecFile( subDir ); 0283 if( !file ) 0284 continue; 0285 return file; 0286 } 0287 } 0288 } 0289 } 0290 return nullptr; 0291 }