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;\"> </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