File indexing completed on 2024-05-05 04:47:19

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Urs Wolfer <uwolfer at kde.org>                                   *
0003  * Copyright (c) 2008 Friedrich W. H. Kossebau <kossebau@kde.org>                       *
0004  * Copyright (c) 2009 Téo Mrnjavac <teo@kde.org>                                        *
0005  *                                                                                      *
0006  * Parts of this class have been take from the KAboutApplication class, which was       *
0007  * Copyright (c) 2000 Waldo Bastian (bastian@kde.org) and Espen Sand (espen@kde.org)    *
0008  *                                                                                      *
0009  * This program is free software; you can redistribute it and/or modify it under        *
0010  * the terms of the GNU General Public License as published by the Free Software        *
0011  * Foundation; either version 2 of the License, or (at your option) any later           *
0012  * version.                                                                             *
0013  *                                                                                      *
0014  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0016  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0017  *                                                                                      *
0018  * You should have received a copy of the GNU General Public License along with         *
0019  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0020  ****************************************************************************************/
0021 
0022 #include "ExtendedAboutDialog.h"
0023 
0024 #include "core/support/Amarok.h"
0025 #include "core/support/Debug.h"
0026 #include "OcsPersonItem.h"
0027 
0028 #include <QApplication>
0029 #include <QDialogButtonBox>
0030 #include <QFontDatabase>
0031 #include <QLabel>
0032 #include <QLayout>
0033 #include <QNetworkConfigurationManager>
0034 #include <QPushButton>
0035 #include <QScrollBar>
0036 #include <QStandardPaths>
0037 #include <QStyle>
0038 #include <QTabWidget>
0039 #include <QTextBrowser>
0040 #include <QVBoxLayout>
0041 
0042 #include <KConfigGroup>
0043 #include <KCoreAddons>
0044 #include <KIconLoader>
0045 #include <KMessageBox>
0046 #include <KTitleWidget>
0047 #include <Attica/Provider>
0048 
0049 void ExtendedAboutDialog::Private::_k_showLicense( const QString &number )
0050 {
0051     QDialog *dialog = new QDialog(q);
0052     QWidget *mainWidget = new QWidget;
0053 
0054     dialog->setWindowTitle(i18n("License Agreement"));
0055     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, q);
0056     dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
0057     dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
0058     buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
0059 
0060     const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
0061     QFontMetrics metrics(font);
0062 
0063     const QString licenseText = aboutData->licenses().at(number.toInt()).text();
0064     QTextBrowser *licenseBrowser = new QTextBrowser;
0065     licenseBrowser->setFont(font);
0066     licenseBrowser->setLineWrapMode(QTextEdit::NoWrap);
0067     licenseBrowser->setText(licenseText);
0068 
0069     QVBoxLayout *mainLayout = new QVBoxLayout;
0070     dialog->setLayout(mainLayout);
0071     mainLayout->addWidget(licenseBrowser);
0072     mainLayout->addWidget(mainWidget);
0073     mainLayout->addWidget(buttonBox);
0074 
0075     // try to set up the dialog such that the full width of the
0076     // document is visible without horizontal scroll-bars being required
0077     const qreal idealWidth = licenseBrowser->document()->idealWidth()
0078         + (2 * QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin))
0079         + licenseBrowser->verticalScrollBar()->width() * 2;
0080 //TODO KF5:PM_DefaultChildMargin is obsolete. Look in QStyle docs for correctly replacing it.
0081 
0082     // try to allow enough height for a reasonable number of lines to be shown
0083     const int idealHeight = metrics.height() * 30;
0084 
0085     dialog->resize(dialog->sizeHint().expandedTo(QSize((int)idealWidth,idealHeight)));
0086     dialog->show();
0087 }
0088 
0089 ExtendedAboutDialog::ExtendedAboutDialog(const KAboutData &about, const OcsData *ocsData, QWidget *parent)
0090   : QDialog(parent)
0091   , d(new Private(this))
0092 {
0093     DEBUG_BLOCK
0094     const KAboutData *aboutData = &about;
0095 
0096     d->aboutData = aboutData;
0097 
0098     if (!aboutData) {
0099         QLabel *errorLabel = new QLabel(i18n("<qt>No information available.<br />"
0100                                              "The supplied KAboutData object does not exist.</qt>"), this);
0101 
0102         errorLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0103         QVBoxLayout *mainLayout = new QVBoxLayout;
0104         setLayout(mainLayout);
0105         mainLayout->addWidget(errorLabel);
0106         return;
0107     }
0108     if( !ocsData )
0109     {
0110         QLabel *errorLabel = new QLabel(i18n("<qt>No information available.<br />"
0111                                              "The supplied OcsData object does not exist.</qt>"), this);
0112 
0113         errorLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0114         QVBoxLayout *mainLayout = new QVBoxLayout;
0115         setLayout(mainLayout);
0116         mainLayout->addWidget(errorLabel);
0117         return;
0118     }
0119     m_ocsData = *ocsData;
0120 
0121     setWindowTitle(i18n("About %1", aboutData->displayName()));
0122 
0123     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0124     QWidget *mainWidget = new QWidget(this);
0125     QVBoxLayout *mainLayout = new QVBoxLayout;
0126     setLayout(mainLayout);
0127     mainLayout->addWidget(mainWidget);
0128     connect(buttonBox, &QDialogButtonBox::accepted, this, &ExtendedAboutDialog::accept);
0129     connect(buttonBox, &QDialogButtonBox::rejected, this, &ExtendedAboutDialog::reject);
0130     buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
0131 
0132     setModal(false);
0133 
0134 
0135     //Set up the title widget...
0136     KTitleWidget *titleWidget = new KTitleWidget(this);
0137 
0138     QIcon windowIcon = qApp->windowIcon();
0139     titleWidget->setIcon(windowIcon, KTitleWidget::ImageLeft);
0140     if (aboutData->programLogo().canConvert<QIcon>())
0141         titleWidget->setIcon(aboutData->programLogo().value<QIcon>(), KTitleWidget::ImageLeft);
0142     else if (aboutData->programLogo().canConvert<QPixmap>())
0143         titleWidget->setIcon(QIcon(aboutData->programLogo().value<QPixmap>()), KTitleWidget::ImageLeft);
0144     else if (aboutData->programLogo().canConvert<QImage>())
0145         titleWidget->setIcon(QIcon(QPixmap::fromImage(aboutData->programLogo().value<QImage>())), KTitleWidget::ImageLeft);
0146 
0147     titleWidget->setText(i18n("<html><font size=\"5\">%1</font><br /><b>Version %2</b><br />Using KDE Frameworks %3</html>",
0148                          aboutData->displayName(), aboutData->version(), KCoreAddons::versionString()));
0149 
0150     //Now let's add the tab bar...
0151     QTabWidget *tabWidget = new QTabWidget;
0152     tabWidget->setUsesScrollButtons(false);
0153 
0154 
0155     //Set up the first page...
0156     QString aboutPageText = aboutData->shortDescription() + '\n';
0157 
0158     if (!aboutData->otherText().isEmpty())
0159         aboutPageText += QLatin1Char('\n') + aboutData->otherText() + '\n';
0160 
0161     if (!aboutData->copyrightStatement().isEmpty())
0162         aboutPageText += QLatin1Char('\n') + aboutData->copyrightStatement() + '\n';
0163 
0164     if (!aboutData->homepage().isEmpty())
0165         aboutPageText += QLatin1Char('\n') + QStringLiteral("<a href=\"%1\">%1</a>").arg(aboutData->homepage()) + '\n';
0166     aboutPageText = aboutPageText.trimmed();
0167 
0168     QLabel *aboutLabel = new QLabel;
0169     aboutLabel->setWordWrap(true);
0170     aboutLabel->setOpenExternalLinks(true);
0171     aboutLabel->setText(aboutPageText.replace('\n', "<br />"));
0172     aboutLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0173 
0174     QVBoxLayout *aboutLayout = new QVBoxLayout;
0175     aboutLayout->addStretch();
0176     aboutLayout->addWidget(aboutLabel);
0177 
0178     const int licenseCount = aboutData->licenses().count();
0179     debug()<< "About to show license stuff";
0180     debug()<< "License count is"<<licenseCount;
0181     for (int i = 0; i < licenseCount; ++i) {
0182         const KAboutLicense &license = aboutData->licenses().at(i);
0183 
0184         QLabel *showLicenseLabel = new QLabel;
0185         showLicenseLabel->setText(QStringLiteral("<a href=\"%1\">%2</a>").arg(QString::number(i),
0186                                                                        i18n("License: %1",
0187                                                                             license.name(KAboutLicense::FullName))));
0188         showLicenseLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0189         connect(showLicenseLabel, &QLabel::linkActivated, this, &ExtendedAboutDialog::showLicense);
0190 
0191         aboutLayout->addWidget(showLicenseLabel);
0192     }
0193     debug()<<"License widget added";
0194 
0195     aboutLayout->addStretch();
0196 
0197     QWidget *aboutWidget = new QWidget(this);
0198     aboutWidget->setLayout(aboutLayout);
0199 
0200     tabWidget->addTab(aboutWidget, i18n("&About"));
0201 
0202 
0203     //Stuff needed by both Authors and Credits pages:
0204     QPixmap openDesktopPixmap = QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/opendesktop-22.png" ) );
0205     QIcon openDesktopIcon = QIcon( openDesktopPixmap );
0206 
0207 
0208     //And now, the Authors page:
0209     const int authorCount = d->aboutData->authors().count();
0210 
0211     if (authorCount)
0212     {
0213         m_authorWidget = new QWidget( this );
0214         QVBoxLayout *authorLayout = new QVBoxLayout( m_authorWidget.data() );
0215 
0216         m_showOcsAuthorButton = new AnimatedBarWidget( openDesktopIcon,
0217                                      i18n( "Get data from openDesktop.org to learn more about the team" ),
0218                                      "process-working", m_authorWidget.data() );
0219         connect( m_showOcsAuthorButton.data(), &AnimatedBarWidget::clicked, this, &ExtendedAboutDialog::switchToOcsWidgets );
0220         authorLayout->addWidget( m_showOcsAuthorButton.data() );
0221 
0222         if (!aboutData->customAuthorTextEnabled() || !aboutData->customAuthorRichText().isEmpty())
0223         {
0224             QLabel *bugsLabel = new QLabel( m_authorWidget.data() );
0225             bugsLabel->setContentsMargins( 4, 2, 0, 4 );
0226             if (!aboutData->customAuthorTextEnabled())
0227             {
0228                 if (aboutData->bugAddress().isEmpty() || aboutData->bugAddress() == "submit@bugs.kde.org")
0229                     bugsLabel->setText( i18n("Please use <a href=\"https://bugs.kde.org\">https://bugs.kde.org</a> to report bugs.\n") );
0230                 else
0231                 {
0232                     if(aboutData->authors().count() == 1 && (aboutData->authors().first().emailAddress() == aboutData->bugAddress()))
0233                     {
0234                         bugsLabel->setText( i18n("Please report bugs to <a href=\"mailto:%1\">%2</a>.\n",
0235                                               aboutData->authors().first().emailAddress(),
0236                                               aboutData->authors().first().emailAddress()));
0237                     }
0238                     else
0239                     {
0240                         bugsLabel->setText( i18n("Please report bugs to <a href=\"mailto:%1\">%2</a>.\n",
0241                                               aboutData->bugAddress(), aboutData->bugAddress()));
0242                     }
0243                 }
0244             }
0245             else
0246                 bugsLabel->setText( aboutData->customAuthorRichText() );
0247             authorLayout->addWidget( bugsLabel );
0248         }
0249 
0250         m_authorListWidget = new OcsPersonListWidget( d->aboutData->authors(), m_ocsData.authors(), OcsPersonItem::Author, m_authorWidget.data() );
0251         connect( m_authorListWidget.data(), &OcsPersonListWidget::switchedToOcs,
0252                  m_showOcsAuthorButton.data(), &AnimatedBarWidget::stop );
0253         connect( m_authorListWidget.data(), &OcsPersonListWidget::switchedToOcs,
0254                  m_showOcsAuthorButton.data(), &AnimatedBarWidget::fold );
0255 
0256         authorLayout->addWidget( m_authorListWidget.data() );
0257         authorLayout->setMargin( 0 );
0258         authorLayout->setSpacing( 2 );
0259         m_authorWidget->setLayout( authorLayout );
0260 
0261         m_authorPageTitle = ( authorCount == 1 ) ? i18n("A&uthor") : i18n("A&uthors");
0262         tabWidget->addTab(m_authorWidget.data(), m_authorPageTitle);
0263         m_isOfflineAuthorWidget = true; //is this still used?
0264     }
0265 
0266     //Then the Credits page:
0267     const int creditCount = aboutData->credits().count();
0268 
0269     if (creditCount)
0270     {
0271         m_creditWidget = new QWidget( this );
0272         QVBoxLayout *creditLayout = new QVBoxLayout( m_creditWidget.data() );
0273 
0274         m_showOcsCreditButton = new AnimatedBarWidget( openDesktopIcon,
0275                                      i18n( "Get data from openDesktop.org to learn more about contributors" ),
0276                                      "process-working", m_creditWidget.data() );
0277         connect( m_showOcsCreditButton.data(), &AnimatedBarWidget::clicked, this, &ExtendedAboutDialog::switchToOcsWidgets );
0278         creditLayout->addWidget( m_showOcsCreditButton.data() );
0279 
0280         m_creditListWidget = new OcsPersonListWidget( d->aboutData->credits(), m_ocsData.credits(), OcsPersonItem::Contributor, m_creditWidget.data() );
0281         connect( m_creditListWidget.data(), &OcsPersonListWidget::switchedToOcs,
0282                  m_showOcsCreditButton.data(), &AnimatedBarWidget::stop );
0283         connect( m_creditListWidget.data(), &OcsPersonListWidget::switchedToOcs,
0284                  m_showOcsCreditButton.data(), &AnimatedBarWidget::fold );
0285 
0286         creditLayout->addWidget( m_creditListWidget.data() );
0287         creditLayout->setMargin( 0 );
0288         creditLayout->setSpacing( 2 );
0289         m_creditWidget->setLayout( creditLayout );
0290 
0291         tabWidget->addTab( m_creditWidget.data(), i18n("&Contributors"));
0292         m_isOfflineCreditWidget = true; //is this still used?
0293     }
0294 
0295     //Finally, the Donors page:
0296     const int donorCount = ocsData->donors()->count();
0297 
0298     if (donorCount)
0299     {
0300         m_donorWidget = new QWidget( this );
0301         QVBoxLayout *donorLayout = new QVBoxLayout( m_donorWidget.data() );
0302 
0303         m_showOcsDonorButton = new AnimatedBarWidget( openDesktopIcon,
0304                                      i18n( "Get data from openDesktop.org to learn more about our generous donors" ),
0305                                      "process-working", m_donorWidget.data() );
0306         connect( m_showOcsDonorButton.data(), &AnimatedBarWidget::clicked, this, &ExtendedAboutDialog::switchToOcsWidgets );
0307         donorLayout->addWidget( m_showOcsDonorButton.data() );
0308 
0309         QList< KAboutPerson > donors;
0310         for( QList< QPair< QString, KAboutPerson > >::const_iterator it = m_ocsData.donors()->constBegin();
0311              it != m_ocsData.donors()->constEnd(); ++it )
0312         {
0313             donors << ( *it ).second;
0314         }
0315         m_donorListWidget = new OcsPersonListWidget( donors , m_ocsData.donors(), OcsPersonItem::Contributor, m_donorWidget.data() );
0316         connect( m_donorListWidget.data(), &OcsPersonListWidget::switchedToOcs, m_showOcsDonorButton.data(), &AnimatedBarWidget::stop );
0317         connect( m_donorListWidget.data(), &OcsPersonListWidget::switchedToOcs, m_showOcsDonorButton.data(), &AnimatedBarWidget::fold );
0318 
0319         donorLayout->addWidget( m_donorListWidget.data() );
0320         donorLayout->setMargin( 0 );
0321         donorLayout->setSpacing( 2 );
0322         QLabel *roktoberLabel =
0323             new QLabel(i18n("<p>Each year in October the Amarok team organizes a funding "
0324                             "drive called <b>Roktober</b>.</p>"
0325                             "<p>If you want your name mentioned on this list "
0326                             "<a href=\"http://amarok.kde.org/donations\"> donate "
0327                             "during Roktober</a> and opt-in.</p>"));
0328         roktoberLabel->setOpenExternalLinks(true);
0329         donorLayout->addWidget(roktoberLabel);
0330         m_donorWidget->setLayout( donorLayout );
0331 
0332         tabWidget->addTab( m_donorWidget.data(), i18n("&Donors"));
0333         m_isOfflineDonorWidget = true;
0334     }
0335 
0336 
0337     //And the translators:
0338     QPalette transparentBackgroundPalette;
0339     transparentBackgroundPalette.setColor( QPalette::Base, Qt::transparent );
0340     transparentBackgroundPalette.setColor( QPalette::Text, transparentBackgroundPalette.color( QPalette::WindowText ) );
0341 
0342 
0343     const QList<KAboutPerson> translatorList = aboutData->translators();
0344 
0345     if(!translatorList.isEmpty()) {
0346         QString translatorPageText;
0347 
0348         QList<KAboutPerson>::ConstIterator it;
0349         for(it = translatorList.begin(); it != translatorList.end(); ++it) {
0350             translatorPageText += QStringLiteral("<p style=\"margin: 0px;\">%1</p>").arg((*it).name());
0351             if (!(*it).emailAddress().isEmpty())
0352                 translatorPageText += QStringLiteral("<p style=\"margin: 0px; margin-left: 15px;\"><a href=\"mailto:%1\">%1</a></p>").arg((*it).emailAddress());
0353             translatorPageText += QStringLiteral("<p style=\"margin: 0px;\">&nbsp;</p>");
0354         }
0355 
0356         translatorPageText += KAboutData::aboutTranslationTeam();
0357 
0358         QTextBrowser *translatorTextBrowser = new QTextBrowser;
0359         translatorTextBrowser->setFrameStyle(QFrame::NoFrame);
0360         translatorTextBrowser->setPalette(transparentBackgroundPalette);
0361         translatorTextBrowser->setHtml(translatorPageText);
0362         tabWidget->addTab(translatorTextBrowser, i18n("T&ranslation"));
0363     }
0364 
0365     //Jam everything together in a layout:
0366     mainLayout->addWidget(titleWidget);
0367     mainLayout->addWidget(tabWidget);
0368     mainLayout->setMargin(0);
0369 
0370     mainLayout->addWidget(buttonBox);
0371 
0372     connect( &m_providerManager, &Attica::ProviderManager::defaultProvidersLoaded, this, &ExtendedAboutDialog::onProvidersFetched );
0373 
0374     resize( QSize( 480, 460 ) );
0375 }
0376 
0377 ExtendedAboutDialog::~ExtendedAboutDialog()
0378 {
0379     delete d;
0380 }
0381 
0382 void
0383 ExtendedAboutDialog::switchToOcsWidgets()
0384 {    
0385     if( !QNetworkConfigurationManager().isOnline() )
0386     {
0387         KMessageBox::error( this, i18n( "Internet connection not available" ), i18n( "Network error" ) );
0388         return;
0389     }
0390 
0391     if( m_showOcsAuthorButton )
0392         m_showOcsAuthorButton->animate();
0393     if( m_showOcsCreditButton )
0394         m_showOcsCreditButton->animate();
0395     if( m_showOcsDonorButton )
0396         m_showOcsDonorButton->animate();
0397     m_providerManager.loadDefaultProviders();
0398 }
0399 
0400 void
0401 ExtendedAboutDialog::onProvidersFetched()
0402 {
0403     foreach( const Attica::Provider &provider, m_providerManager.providers() )
0404     {
0405         if( !provider.isValid() || !provider.isEnabled() )
0406             continue;
0407 
0408         if( provider.baseUrl().host() != m_ocsData.providerId() )
0409             continue;
0410 
0411         Attica::Provider copy = provider;
0412         debug()<<"Successfully fetched OCS provider"<< copy.name();
0413         debug()<<"About to request OCS data";
0414         if( m_authorListWidget )
0415             m_authorListWidget->switchToOcs( copy );
0416         if( m_creditListWidget )
0417             m_creditListWidget->switchToOcs( copy );
0418         if( m_donorListWidget )
0419             m_donorListWidget->switchToOcs( copy );
0420         break;
0421     }
0422 }
0423 
0424 void
0425 ExtendedAboutDialog::showLicense(const QString& number)
0426 {
0427     d->_k_showLicense(number);
0428 }
0429