File indexing completed on 2024-05-05 16:45:36
0001 /* 0002 SPDX-FileCopyrightText: 2008 Hamish Rodda <rodda@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "licensepage.h" 0008 0009 #include "ui_licensechooser.h" 0010 #include "debug.h" 0011 0012 #include <KSharedConfig> 0013 #include <KLocalizedString> 0014 #include <KEMailSettings> 0015 #include <KMessageBox> 0016 #include <KConfigGroup> 0017 0018 #include <QDirIterator> 0019 #include <QStandardPaths> 0020 0021 namespace KDevelop { 0022 0023 struct LicensePagePrivate 0024 { 0025 struct LicenseInfo 0026 { 0027 QString name; 0028 QString path; 0029 QString contents; 0030 bool operator< (const LicenseInfo& o) const 0031 { 0032 return name.localeAwareCompare(o.name) < 0; 0033 } 0034 }; 0035 using LicenseList = QVector<LicenseInfo>; 0036 0037 0038 explicit LicensePagePrivate(LicensePage* page_) 0039 : license(nullptr) 0040 , page(page_) 0041 { 0042 } 0043 0044 // methods 0045 void initializeLicenses(); 0046 QString readLicense(int licenseIndex); 0047 bool saveLicense(); 0048 // slots 0049 void licenseComboChanged(int license); 0050 0051 Ui::LicenseChooserDialog* license; 0052 LicenseList availableLicenses; 0053 LicensePage* page; 0054 }; 0055 0056 //! Read all the license files in the global and local config dirs 0057 void LicensePagePrivate::initializeLicenses() 0058 { 0059 qCDebug(PLUGIN_FILETEMPLATES) << "Searching for available licenses"; 0060 const QStringList licenseDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kdevcodegen/licenses"), QStandardPaths::LocateDirectory); 0061 0062 //Iterate through the possible directories that contain licenses, and load their names 0063 for (const QString& currentDir : licenseDirs) { 0064 QDirIterator it(currentDir, QDir::Files | QDir::Readable); 0065 while(it.hasNext()) 0066 { 0067 LicenseInfo newLicense; 0068 newLicense.path = it.next(); 0069 newLicense.name = it.fileName(); 0070 0071 qCDebug(PLUGIN_FILETEMPLATES) << "Found License: " << newLicense.name; 0072 0073 availableLicenses.push_back(newLicense); 0074 } 0075 } 0076 0077 std::sort(availableLicenses.begin(), availableLicenses.end()); 0078 0079 for (const LicenseInfo& info : qAsConst(availableLicenses)) { 0080 license->licenseComboBox->addItem(info.name); 0081 } 0082 //Finally add the option other for user specified licenses 0083 LicenseInfo otherLicense; 0084 availableLicenses.push_back(otherLicense); 0085 license->licenseComboBox->addItem(i18nc("@item:inlistbox other license", "Other")); 0086 } 0087 0088 // Read a license index, if it is not loaded, open it from the file 0089 QString LicensePagePrivate::readLicense(int licenseIndex) 0090 { 0091 //If the license is not loaded into memory, read it in 0092 if(availableLicenses[licenseIndex].contents.isEmpty()) 0093 { 0094 QString licenseText; 0095 //If we are dealing with the last option "other" just return a new empty string 0096 if(licenseIndex != (availableLicenses.size() - 1)) 0097 { 0098 qCDebug(PLUGIN_FILETEMPLATES) << "Reading license: " << availableLicenses[licenseIndex].name ; 0099 QFile newLicense(availableLicenses[licenseIndex].path); 0100 0101 if(newLicense.open(QIODevice::ReadOnly | QIODevice::Text)) 0102 { 0103 QTextStream newLicenseText(&newLicense); 0104 newLicenseText.setAutoDetectUnicode(true); 0105 licenseText = newLicenseText.readAll(); 0106 newLicense.close(); 0107 0108 // license text files are stored with a trailing linebreak, 0109 // as otherwise some tools complain about it 0110 // so deal with that and remove any potential trailing linebreak 0111 // which otherwise would result in a trailing empty line 0112 QRegularExpression anyLinebreakAtEnd(QStringLiteral("(\n|\r\n)$")); 0113 licenseText.remove(anyLinebreakAtEnd); 0114 } 0115 else 0116 licenseText = QStringLiteral("Error, could not open license file.\n Was it deleted?"); 0117 } 0118 0119 availableLicenses[licenseIndex].contents = licenseText; 0120 } 0121 0122 return availableLicenses[licenseIndex].contents; 0123 } 0124 0125 // ---Slots--- 0126 0127 void LicensePagePrivate::licenseComboChanged(int selectedLicense) 0128 { 0129 //If the last slot is selected enable the save license combobox 0130 if(selectedLicense == (availableLicenses.size() - 1)) 0131 { 0132 license->licenseTextEdit->clear(); 0133 license->licenseTextEdit->setReadOnly(false); 0134 license->saveLicense->setEnabled(true); 0135 } 0136 else 0137 { 0138 license->saveLicense->setEnabled(false); 0139 license->licenseTextEdit->setReadOnly(true); 0140 } 0141 0142 if(selectedLicense < 0 || selectedLicense >= availableLicenses.size()) 0143 license->licenseTextEdit->setText(i18n("Could not load previous license")); 0144 else 0145 license->licenseTextEdit->setText(readLicense(selectedLicense)); 0146 } 0147 0148 bool LicensePagePrivate::saveLicense() 0149 { 0150 qCDebug(PLUGIN_FILETEMPLATES) << "Attempting to save custom license: " << license->licenseName->text(); 0151 0152 QString localDataDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)+QLatin1String("/kdevcodegen/licenses/"); 0153 QString fullPath = localDataDir + license->licenseName->text(); 0154 QFile newFile(fullPath); 0155 0156 if(newFile.exists()) 0157 { 0158 KMessageBox::error(page, i18n("The specified license already exists. " 0159 "Please provide a different name.")); 0160 return false; 0161 } 0162 0163 QDir().mkpath(localDataDir); 0164 newFile.open(QIODevice::WriteOnly); 0165 qint64 result = newFile.write(license->licenseTextEdit->toPlainText().toUtf8()); 0166 newFile.close(); 0167 0168 if(result == -1) 0169 { 0170 KMessageBox::error(page, i18n("Failed to write custom license template to file %1.", fullPath)); 0171 return false; 0172 } 0173 0174 // also add to our data structures, this esp. needed for proper saving 0175 // of the license index so it can be restored the next time we show up 0176 LicenseInfo info; 0177 info.name = license->licenseName->text(); 0178 info.path = localDataDir; 0179 availableLicenses << info; 0180 // find index of the new the license, omitting the very last item ('Other') 0181 int idx = availableLicenses.count() - 1; 0182 for(int i = 0; i < availableLicenses.size() - 1; ++i) { 0183 if (info < availableLicenses.at(i)) { 0184 idx = i; 0185 break; 0186 } 0187 } 0188 availableLicenses.insert(idx, info); 0189 license->licenseComboBox->insertItem(idx, info.name); 0190 license->licenseComboBox->setCurrentIndex(idx); 0191 0192 0193 return true; 0194 } 0195 0196 LicensePage::LicensePage(QWidget* parent) 0197 : QWidget(parent) 0198 , d(new LicensePagePrivate(this)) 0199 { 0200 d->license = new Ui::LicenseChooserDialog; 0201 d->license->setupUi(this); 0202 0203 connect(d->license->licenseComboBox, QOverload<int>::of(&KComboBox::currentIndexChanged), 0204 this, [&] (int selectedLicense) { d->licenseComboChanged(selectedLicense); }); 0205 connect(d->license->saveLicense, &QCheckBox::clicked, 0206 d->license->licenseName, &QLineEdit::setEnabled); 0207 0208 // Read all the available licenses from the standard dirs 0209 d->initializeLicenses(); 0210 0211 //Set the license selection to the previous one 0212 KConfigGroup config(KSharedConfig::openConfig()->group("CodeGeneration")); 0213 d->license->licenseComboBox->setCurrentIndex(config.readEntry( "LastSelectedLicense", 0 )); 0214 // Needed to avoid a bug where licenseComboChanged doesn't get 0215 // called by QComboBox if the past selection was 0 0216 d->licenseComboChanged(d->license->licenseComboBox->currentIndex()); 0217 } 0218 0219 LicensePage::~LicensePage() 0220 { 0221 if (d->license->saveLicense->isChecked() && !d->license->licenseName->text().isEmpty()) { 0222 d->saveLicense(); 0223 } 0224 KConfigGroup config(KSharedConfig::openConfig()->group("CodeGeneration")); 0225 //Do not save invalid license numbers' 0226 int index = d->license->licenseComboBox->currentIndex(); 0227 if( index >= 0 || index < d->availableLicenses.size() ) 0228 { 0229 config.writeEntry("LastSelectedLicense", index); 0230 config.config()->sync(); 0231 } 0232 else 0233 { 0234 qCWarning(PLUGIN_FILETEMPLATES) << "Attempted to save an invalid license number: " << index 0235 << ". Number of licenses:" << d->availableLicenses.size(); 0236 } 0237 0238 delete d->license; 0239 delete d; 0240 } 0241 0242 QString LicensePage::license() const 0243 { 0244 QString licenseText = d->license->licenseTextEdit->document()->toPlainText(); 0245 /* Add date, name and email to license text */ 0246 licenseText.replace(QLatin1String("<year>"), QDate::currentDate().toString(QStringLiteral("yyyy"))); 0247 licenseText.replace(QLatin1String("<month>"), QDate::currentDate().toString(QStringLiteral("MM"))); 0248 licenseText.replace(QLatin1String("<day>"), QDate::currentDate().toString(QStringLiteral("dd"))); 0249 QString developer(QStringLiteral("%1 <%2>")); 0250 KEMailSettings emailSettings; 0251 QString name = emailSettings.getSetting(KEMailSettings::RealName); 0252 if (name.isEmpty()) 0253 { 0254 name = QStringLiteral("<copyright holder>"); 0255 } 0256 developer = developer.arg(name); 0257 QString email = emailSettings.getSetting(KEMailSettings::EmailAddress); 0258 if (email.isEmpty()) 0259 { 0260 email = QStringLiteral("email"); //no < > as they are already through the email field 0261 } 0262 developer = developer.arg(email); 0263 licenseText.replace(QLatin1String("<copyright holder>"), developer); 0264 0265 return licenseText; 0266 } 0267 0268 void LicensePage::setFocusToFirstEditWidget() 0269 { 0270 d->license->licenseComboBox->setFocus(); 0271 } 0272 0273 } 0274 0275 Q_DECLARE_TYPEINFO(KDevelop::LicensePagePrivate::LicenseInfo, Q_MOVABLE_TYPE); 0276 0277 #include "moc_licensepage.cpp"