File indexing completed on 2024-05-05 04:48:24

0001 /****************************************************************************************
0002  * Copyright (c) 2012 Andrzej J. R. Hunt <andrzej at ahunt.org>                         *
0003  * Copyright (c) Mark Kretschmann <kretschmann@kde.org>                                 *
0004  *                                                                                      *
0005  * This program is free software; you can redistribute it and/or modify it under        *
0006  * the terms of the GNU General Public License as published by the Free Software        *
0007  * Foundation; either version 2 of the License, or (at your option) any later           *
0008  * version.                                                                             *
0009  *                                                                                      *
0010  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0011  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0012  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0013  *                                                                                      *
0014  * You should have received a copy of the GNU General Public License along with         *
0015  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0016  ****************************************************************************************/
0017 
0018 #include "DiagnosticDialog.h"
0019 
0020 #include "context/ContextView.h"
0021 #include "PluginManager.h"
0022 #include "scripting/scriptmanager/ScriptManager.h"
0023 
0024 #include <QApplication>
0025 #include <QClipboard>
0026 #include <QDialogButtonBox>
0027 #include <QDir>
0028 #include <QPlainTextEdit>
0029 #include <QPushButton>
0030 #include <QSettings>
0031 #include <QVBoxLayout>
0032 
0033 #include <KAboutData>
0034 #include <KCoreAddons>
0035 #include <KLocalizedString>
0036 #include <KPluginInfo>
0037 
0038 #include <algorithm>
0039 #include <phonon/pulsesupport.h>
0040 
0041 
0042 
0043 BackendDescriptor::BackendDescriptor(const QString &path)
0044     : isValid(false)
0045 {
0046     QPluginLoader loader(path);
0047 
0048     iid = loader.metaData().value(QStringLiteral("IID")).toString();
0049 
0050     const QJsonObject metaData = loader.metaData().value(QStringLiteral("MetaData")).toObject();
0051     name = metaData.value(QStringLiteral("Name")).toString();
0052     version = metaData.value(QStringLiteral("Version")).toString();
0053     website = metaData.value(QStringLiteral("Website")).toString();
0054     preference = metaData.value(QStringLiteral("InitialPreference")).toDouble();
0055 
0056     pluginPath = path;
0057 
0058     if (name.isEmpty())
0059         name = QFileInfo(path).baseName();
0060 
0061     if (iid.isEmpty())
0062         return; // Not valid.
0063 
0064     isValid = true;
0065 }
0066 
0067 bool BackendDescriptor::operator <(const BackendDescriptor &rhs) const
0068 {
0069     return this->preference < rhs.preference;
0070 }
0071 
0072 
0073 
0074 DiagnosticDialog::DiagnosticDialog( const KAboutData &about, QWidget *parent )
0075     : QDialog( parent )
0076 {
0077     setLayout( new QVBoxLayout );
0078     m_textBox = new QPlainTextEdit( generateReport( &about ), this );
0079     m_textBox->setReadOnly( true );
0080     layout()->addWidget( m_textBox );
0081 
0082     auto buttonBox = new QDialogButtonBox( this );
0083     auto closeButton = buttonBox->addButton( QDialogButtonBox::Close );
0084     auto copyButton = new QPushButton( i18n( "Copy to Clipboard" ) );
0085     buttonBox->addButton( copyButton, QDialogButtonBox::ActionRole );
0086     layout()->addWidget( buttonBox );
0087 
0088     setWindowTitle( i18nc( "%1 is the program name", "%1 Diagnostics", KAboutData::applicationData().displayName() ) );
0089 
0090     resize( QSize( 480, 460 ) );
0091 
0092     connect( closeButton, &QPushButton::clicked, this, &DiagnosticDialog::close );
0093     connect( copyButton, &QPushButton::clicked, this, &DiagnosticDialog::slotCopyToClipboard );
0094 
0095     setAttribute( Qt::WA_DeleteOnClose );
0096 }
0097 
0098 const QString
0099 DiagnosticDialog::generateReport( const KAboutData *aboutData )
0100 {
0101     // Get scripts -- we have to assemble 3 lists into one
0102     KPluginInfo::List aScripts;
0103     const auto aScriptManager = ScriptManager::instance();
0104     aScripts.append( aScriptManager->scripts( QStringLiteral( "Generic" ) ) );
0105     aScripts.append( aScriptManager->scripts( QStringLiteral( "Lyrics" ) ) );
0106     aScripts.append( aScriptManager->scripts( QStringLiteral( "Scriptable Service" ) ) );
0107 
0108     // Format the data to be readable
0109     QString aScriptString;
0110     foreach( KPluginInfo aInfo, aScripts )
0111     {
0112         if( aInfo.isPluginEnabled() )
0113             aScriptString += "   " + aInfo.name() + " (" + aInfo.version() + ")\n";
0114     }
0115 
0116 
0117     // Get plugins -- we have to assemble a list again.
0118     QVector<KPluginMetaData> aPlugins;
0119     const auto aPluginManager = Plugins::PluginManager::instance();
0120     aPlugins.append( aPluginManager->enabledPlugins( Plugins::PluginManager::Collection ) );
0121     aPlugins.append( aPluginManager->enabledPlugins( Plugins::PluginManager::Service ) );
0122     aPlugins.append( aPluginManager->enabledPlugins( Plugins::PluginManager::Importer ) );
0123 
0124     QString aPluginString;
0125     for( const auto &aInfo : qAsConst(aPlugins) )
0126     {
0127         aPluginString += "   " + aInfo.name() + " (" + aInfo.version() + ")\n";
0128     }
0129 
0130     // Get applets
0131     QString appletString;
0132     const QStringList appletList = Context::ContextView::self()->currentAppletNames();
0133 
0134     for ( const QString &applet : appletList )
0135     {
0136         // Currently we cannot extract the applet version number this way
0137         appletString += "   " + applet + '\n';
0138     }
0139 
0140     const BackendDescriptor aPhononBackend = getPreferredBackend();
0141 
0142     const bool hasPulse = Phonon::PulseSupport::getInstance()->isActive();
0143     const QString pulse = hasPulse ? i18nc( "Usage", "Yes" ) : i18nc( "Usage", "No" );
0144 
0145     return i18n(
0146                "%1 Diagnostics\n\nGeneral Information:\n"
0147                "   %1 Version: %2\n"
0148                "   KDE Frameworks Version: %3\n"
0149                "   Qt Version: %4\n"
0150                "   Phonon Version: %5\n"
0151                "   Phonon Backend: %6 (%7, %8)\n"
0152                "   PulseAudio: %9\n\n",
0153 
0154                KAboutData::applicationData().displayName(), aboutData->version(),      // Amarok
0155                KCoreAddons::versionString(),                        // KDE Frameworks
0156                qVersion(),                                          // Qt
0157                Phonon::phononVersion(),                             // Phonon
0158                aPhononBackend.name,
0159                aPhononBackend.version,
0160                aPhononBackend.website,                              // & Backend
0161                pulse                                                // PulseAudio
0162            ) + i18n(
0163                "Enabled Scripts:\n%1\n"
0164                "Enabled Plugins:\n%2\n"
0165                "Enabled Applets:\n%3\n",
0166                aScriptString, aPluginString, appletString
0167            );
0168 }
0169 
0170 const BackendDescriptor
0171 DiagnosticDialog::getPreferredBackend() const
0172 {
0173     QList<QString> iidPreference;
0174     QSettings settings("kde.org", "libphonon");
0175     const int size = settings.beginReadArray("Backends");
0176     for (int i = 0; i < size; ++i) {
0177         settings.setArrayIndex(i);
0178         iidPreference.append(settings.value(QStringLiteral("iid")).toString());
0179     }
0180     settings.endArray();
0181 
0182     const QLatin1String suffix("/" PHONON_LIB_SONAME "_backend/");
0183     const QStringList paths = QCoreApplication::libraryPaths();
0184 
0185     QList<struct BackendDescriptor> backendList;
0186 
0187     foreach (const QString &path, paths) {
0188         const QString libPath = path + suffix;
0189         const QDir dir(libPath);
0190         if (!dir.exists()) {
0191             continue;
0192         }
0193 
0194         const QStringList plugins(dir.entryList(QDir::Files));
0195 
0196         for (const QString &plugin : plugins) {
0197             BackendDescriptor bd = BackendDescriptor(libPath + plugin);
0198             if (bd.isValid) {
0199                 int preference = iidPreference.indexOf(bd.iid);
0200                 if (preference != -1) {
0201                     bd.preference = preference;
0202                 }
0203                 backendList.append(bd);
0204             }
0205         }
0206     }
0207 
0208     std::sort(backendList.begin(), backendList.end());
0209 
0210     return backendList.first();
0211 }
0212 
0213 void
0214 DiagnosticDialog::slotCopyToClipboard() const
0215 {
0216     QClipboard *clipboard = QApplication::clipboard();
0217     clipboard->setText( m_textBox->toPlainText() );
0218 }