diff --git a/applets/mediaframe/plugin/mediaframe.cpp b/applets/mediaframe/plugin/mediaframe.cpp index ec521b000..632ef00b4 100644 --- a/applets/mediaframe/plugin/mediaframe.cpp +++ b/applets/mediaframe/plugin/mediaframe.cpp @@ -1,424 +1,423 @@ /* * Copyright 2015 Lars Pontoppidan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. */ #include "mediaframe.h" #include #include #include #include #include #include #include #include #include #include +#include #include #include MediaFrame::MediaFrame(QObject *parent) : QObject(parent) { - qsrand(QTime::currentTime().msec()); - const auto imageMimeTypeNames = QImageReader::supportedMimeTypes(); QMimeDatabase mimeDb; for (const auto& imageMimeTypeName : imageMimeTypeNames) { const auto mimeType = mimeDb.mimeTypeForName(QLatin1String(imageMimeTypeName)); m_filters << mimeType.globPatterns(); } qDebug() << "Added" << m_filters.count() << "filters"; //qDebug() << m_filters; m_next = 0; connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &MediaFrame::slotItemChanged); connect(&m_watcher, &QFileSystemWatcher::fileChanged, this, &MediaFrame::slotItemChanged); } MediaFrame::~MediaFrame() = default; int MediaFrame::count() const { return m_allFiles.count(); } bool MediaFrame::random() const { return m_random; } void MediaFrame::setRandom(bool random) { if (random != m_random) { m_random = random; emit randomChanged(); } } int MediaFrame::random(int min, int max) { if (min > max) { int temp = min; min = max; max = temp; } //qDebug() << "random" << min << "<->" << max << "=" << ((qrand()%(max-min+1))+min); - return ((qrand() % (max - min + 1) ) + min); + return (QRandomGenerator::global()->bounded((max - min + 1) ) + min); } QString MediaFrame::getCacheDirectory() { return QDir::temp().absolutePath(); } QString MediaFrame::hash(const QString &str) { return QString::fromLatin1(QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Md5).toHex()); } bool MediaFrame::isDir(const QString &path) { return QDir(path).exists(); } bool MediaFrame::isDirEmpty(const QString &path) { return (isDir(path) && QDir(path).entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries).isEmpty()); } bool MediaFrame::isFile(const QString &path) { // Check if the file exists and is not a directory return (QFileInfo::exists(path) && QFileInfo(path).isFile()); } void MediaFrame::add(const QString &path) { add(path, AddOption::NON_RECURSIVE); } void MediaFrame::add(const QString &path, AddOption option) { if(isAdded(path)) { qWarning() << "Path" << path << "already added"; return; } QUrl url = QUrl(path); QString localPath = url.toString(QUrl::PreferLocalFile); //qDebug() << "Local path" << localPath << "Path" << path; QStringList paths; QString filePath; if(isDir(localPath)) { if(!isDirEmpty(localPath)) { QDirIterator dirIterator(localPath, m_filters, QDir::Files, (option == AddOption::RECURSIVE ? QDirIterator::Subdirectories | QDirIterator::FollowSymlinks : QDirIterator::NoIteratorFlags)); while (dirIterator.hasNext()) { dirIterator.next(); filePath = dirIterator.filePath(); paths.append(filePath); m_allFiles.append(filePath); //qDebug() << "Appended" << filePath; emit countChanged(); } if(paths.count() > 0) { m_pathMap.insert(path, paths); qDebug() << "Added" << paths.count() << "files from" << path; } else { qWarning() << "No images found in directory" << path; } } else { qWarning() << "Not adding empty directory" << path; } // the pictures have to be sorted before adding them to the list, // because the QDirIterator sorts them in a different way than QDir::entryList //paths.sort(); } else if(isFile(localPath)) { paths.append(path); m_pathMap.insert(path, paths); m_allFiles.append(path); qDebug() << "Added" << paths.count() << "files from" << path; emit countChanged(); } else { if (url.isValid() && !url.isLocalFile()) { qDebug() << "Adding" << url.toString() << "as remote file"; paths.append(path); m_pathMap.insert(path, paths); m_allFiles.append(path); emit countChanged(); } else { qWarning() << "Path" << path << "is not a valid file url or directory"; } } } void MediaFrame::clear() { m_pathMap.clear(); m_allFiles.clear(); emit countChanged(); } void MediaFrame::watch(const QString &path) { QUrl url = QUrl(path); QString localPath = url.toString(QUrl::PreferLocalFile); if(isFile(localPath)) { if(!m_watchFile.isEmpty()) { //qDebug() << "Removing" << m_watchFile << "from watch list"; m_watcher.removePath(m_watchFile); } else { qDebug() << "Nothing in watch list"; } //qDebug() << "watching" << localPath << "for changes"; m_watcher.addPath(localPath); m_watchFile = localPath; } else { qWarning() << "Can't watch remote file" << path << "for changes"; } } bool MediaFrame::isAdded(const QString &path) { return (m_pathMap.contains(path)); } void MediaFrame::get(QJSValue successCallback) { get(successCallback, QJSValue::UndefinedValue); } void MediaFrame::get(QJSValue successCallback, QJSValue errorCallback) { int size = m_allFiles.count() - 1; QString path; QString errorMessage; QJSValueList args; if(size < 1) { if(size == 0) { path = m_allFiles.at(0); if(successCallback.isCallable()) { args << QJSValue(path); successCallback.call(args); } return; } else { errorMessage = QStringLiteral("No files available"); qWarning() << errorMessage; args << QJSValue(errorMessage); errorCallback.call(args); return; } } if(m_random) { path = m_allFiles.at(this->random(0, size)); } else { path = m_allFiles.at(m_next); m_next++; if(m_next > size) { qDebug() << "Resetting next count from" << m_next << "due to queue size" << size; m_next = 0; } } QUrl url = QUrl(path); if(url.isValid()) { QString localPath = url.toString(QUrl::PreferLocalFile); if (!isFile(localPath)) { m_filename = path.section(QLatin1Char('/'), -1); QString cachedFile = getCacheDirectory()+QLatin1Char('/')+hash(path)+QLatin1Char('_')+m_filename; if(isFile(cachedFile)) { // File has been cached qDebug() << path << "is cached as" << cachedFile; if(successCallback.isCallable()) { args << QJSValue(cachedFile); successCallback.call(args); } return; } m_successCallback = successCallback; m_errorCallback = errorCallback; m_filename = cachedFile; qDebug() << path << "doesn't exist locally, trying remote."; KIO::StoredTransferJob * job = KIO::storedGet( url, KIO::NoReload, KIO::HideProgressInfo); connect(job, SIGNAL(finished(KJob*)), this, SLOT(slotFinished(KJob*))); } else { if(successCallback.isCallable()) { args << QJSValue(path); successCallback.call(args); } return; } } else { errorMessage = path + QLatin1String(" is not a valid URL"); qCritical() << errorMessage; if(errorCallback.isCallable()) { args << QJSValue(errorMessage); errorCallback.call(args); } return; } } void MediaFrame::pushHistory(const QString &string) { const int oldCount = m_history.count(); m_history.prepend(string); // Keep a sane history size if (m_history.length() > 50) { m_history.removeLast(); } if (oldCount != m_history.count()) { emit historyLengthChanged(); } } QString MediaFrame::popHistory() { if (m_history.isEmpty()) { return QString(); } const QString item = m_history.takeFirst(); emit historyLengthChanged(); return item; } int MediaFrame::historyLength() const { return m_history.length(); } void MediaFrame::pushFuture(const QString &string) { m_future.prepend(string); emit futureLengthChanged(); } QString MediaFrame::popFuture() { if (m_future.isEmpty()) { return QString(); } const QString item = m_future.takeFirst(); emit futureLengthChanged(); return item; } int MediaFrame::futureLength() const { return m_future.length(); } void MediaFrame::slotItemChanged(const QString &path) { emit itemChanged(path); } void MediaFrame::slotFinished(KJob *job) { QString errorMessage; QJSValueList args; if (job->error()) { errorMessage = QLatin1String("Error loading image: ") + job->errorString(); qCritical() << errorMessage; if(m_errorCallback.isCallable()) { args << QJSValue(errorMessage); m_errorCallback.call(args); } } else if (KIO::StoredTransferJob *transferJob = qobject_cast(job)) { QImage image; // TODO make proper caching calls QString path = m_filename; qDebug() << "Saving download to" << path; image.loadFromData(transferJob->data()); image.save(path); qDebug() << "Saved to" << path; if(m_successCallback.isCallable()) { args << QJSValue(path); m_successCallback.call(args); } } else { errorMessage = QStringLiteral("Unknown error occurred"); qCritical() << errorMessage; if(m_errorCallback.isCallable()) { args << QJSValue(errorMessage); m_errorCallback.call(args); } } } diff --git a/applets/quicklaunch/plugin/quicklaunch_p.cpp b/applets/quicklaunch/plugin/quicklaunch_p.cpp index 79630760a..d285cdf35 100644 --- a/applets/quicklaunch/plugin/quicklaunch_p.cpp +++ b/applets/quicklaunch/plugin/quicklaunch_p.cpp @@ -1,226 +1,227 @@ /* * Copyright 2008-2009 Lukas Appelhans * Copyright 2010-2011 Ingomar Wesp * Copyright 2013 Bhushan Shah * Copyright 2015 David Rosca * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ #include "quicklaunch_p.h" #include #include #include #include #include +#include #include #include #include #include #include #include #include #include QuicklaunchPrivate::QuicklaunchPrivate(QObject *parent) : QObject(parent) { } QVariantMap QuicklaunchPrivate::launcherData(const QUrl &url) { QString name; QString icon; QString genericName; QVariantList jumpListActions; if (url.scheme() == QLatin1String("quicklaunch")) { // Ignore internal scheme } else if (url.isLocalFile()) { const KFileItem fileItem(url); const QFileInfo fi(url.toLocalFile()); if (fileItem.isDesktopFile()) { const KDesktopFile f(url.toLocalFile()); name = f.readName(); icon = f.readIcon(); genericName = f.readGenericName(); if (name.isEmpty()) { name = QFileInfo(url.toLocalFile()).fileName(); } const QStringList &actions = f.readActions(); foreach (const QString &actionName, actions) { const KConfigGroup &actionGroup = f.actionGroup(actionName); if (!actionGroup.isValid() || !actionGroup.exists()) { continue; } const QString &name = actionGroup.readEntry("Name"); const QString &exec = actionGroup.readEntry("Exec"); if (name.isEmpty() || exec.isEmpty()) { continue; } jumpListActions << QVariantMap{ {QStringLiteral("name"), name}, {QStringLiteral("icon"), actionGroup.readEntry("Icon")}, {QStringLiteral("exec"), exec} }; } } else { QMimeDatabase db; name = fi.baseName(); icon = db.mimeTypeForUrl(url).iconName(); genericName = fi.baseName(); } } else { if (url.scheme().contains(QLatin1String("http"))) { name = url.host(); } else if (name.isEmpty()) { name = url.toString(); if (name.endsWith(QLatin1String(":/"))) { name = url.scheme(); } } icon = KIO::iconNameForUrl(url); } return QVariantMap{ {QStringLiteral("applicationName"), name}, {QStringLiteral("iconName"), icon}, {QStringLiteral("genericName"), genericName}, {QStringLiteral("jumpListActions"), jumpListActions} }; } void QuicklaunchPrivate::openUrl(const QUrl &url) { new KRun(url, nullptr); } void QuicklaunchPrivate::openExec(const QString &exec) { KRun::run(exec, {}, nullptr); } void QuicklaunchPrivate::addLauncher(bool isPopup) { KOpenWithDialog *dialog = new KOpenWithDialog(); dialog->setModal(false); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->hideRunInTerminal(); dialog->setSaveNewApplications(true); dialog->show(); connect(dialog, &KOpenWithDialog::accepted, this, [this, dialog, isPopup]() { if (!dialog->service()) { return; } const QUrl &url = QUrl::fromLocalFile(dialog->service()->entryPath()); if (url.isValid()) { Q_EMIT launcherAdded(url.toString(), isPopup); } }); } static QString locateLocal(const QString &file) { const QString &dataPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); const QString appDataPath = QStringLiteral("%1/quicklaunch").arg(dataPath); QDir().mkpath(appDataPath); return QStringLiteral("%1/%2").arg(appDataPath, file); } static QString determineNewDesktopFilePath(const QString &baseName) { QString appendix; QString desktopFilePath = locateLocal(baseName) + QLatin1String(".desktop"); + auto *generator = QRandomGenerator::global(); while (QFile::exists(desktopFilePath)) { if (appendix.isEmpty()) { - qsrand(QTime::currentTime().msec()); appendix += QLatin1Char('-'); } // Limit to [0-9] and [a-z] range. - char newChar = qrand() % 36; + char newChar = generator->bounded(36); newChar += newChar < 10 ? 48 : 97-10; appendix += QLatin1Char(newChar); desktopFilePath = locateLocal(baseName + appendix + QLatin1String(".desktop")); } return desktopFilePath; } void QuicklaunchPrivate::editLauncher(QUrl url, int index, bool isPopup) { // If the launcher does not point to a desktop file, create one, // so that user can change url, icon, text and description. bool desktopFileCreated = false; if (!url.isLocalFile() || !KDesktopFile::isDesktopFile(url.toLocalFile())) { const QString desktopFilePath = determineNewDesktopFilePath(QStringLiteral("launcher")); const QVariantMap data = launcherData(url); KConfig desktopFile(desktopFilePath); KConfigGroup desktopEntry(&desktopFile, "Desktop Entry"); desktopEntry.writeEntry("Name", data.value(QStringLiteral("applicationName")).toString()); desktopEntry.writeEntry("Comment", data.value(QStringLiteral("genericName")).toString()); desktopEntry.writeEntry("Icon", data.value(QStringLiteral("iconName")).toString()); desktopEntry.writeEntry("Type", "Link"); desktopEntry.writeEntry("URL", url); desktopEntry.sync(); url = QUrl::fromLocalFile(desktopFilePath); desktopFileCreated = true; } KPropertiesDialog *dialog = new KPropertiesDialog(url); dialog->setModal(false); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); connect(dialog, &KPropertiesDialog::accepted, this, [this, dialog, index, isPopup]() { QUrl url = dialog->url(); QString path = url.toLocalFile(); // If the user has renamed the file, make sure that the new // file name has the extension ".desktop". if (!path.endsWith(QLatin1String(".desktop"))) { QFile::rename(path, path + QLatin1String(".desktop")); path += QLatin1String(".desktop"); url = QUrl::fromLocalFile(path); } Q_EMIT launcherEdited(url.toString(), index, isPopup); }); connect(dialog, &KPropertiesDialog::rejected, this, [this, url, desktopFileCreated]() { if (desktopFileCreated) { // User didn't save the data, delete the temporary desktop file. QFile::remove(url.toLocalFile()); } }); } diff --git a/dataengines/potd/flickrprovider.cpp b/dataengines/potd/flickrprovider.cpp index b3198a421..438b92a87 100644 --- a/dataengines/potd/flickrprovider.cpp +++ b/dataengines/potd/flickrprovider.cpp @@ -1,167 +1,165 @@ /* * Copyright (C) 2007 Tobias Koenig * Copyright 2008 by Anne-Marie Mahfouf * Copyright 2008 by Georges Toth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "flickrprovider.h" #include #include - +#include #include #include #define FLICKR_API_KEY QStringLiteral("11829a470557ad8e10b02e80afacb3af") static QUrl buildUrl(const QDate &date) { QUrl url(QLatin1String( "https://api.flickr.com/services/rest/")); QUrlQuery urlQuery(url); urlQuery.addQueryItem(QStringLiteral("api_key"), FLICKR_API_KEY); urlQuery.addQueryItem(QStringLiteral("method"), QStringLiteral("flickr.interestingness.getList")); urlQuery.addQueryItem(QStringLiteral("date"), date.toString(Qt::ISODate)); // url_o might be either too small or too large. urlQuery.addQueryItem(QStringLiteral("extras"), QStringLiteral("url_k,url_h,url_o")); url.setQuery(urlQuery); return url; } FlickrProvider::FlickrProvider(QObject *parent, const QVariantList &args) : PotdProvider(parent, args) { - qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); - mActualDate = date(); const QUrl url = buildUrl(mActualDate); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::NoReload, KIO::HideProgressInfo); connect(job, &KIO::StoredTransferJob::finished, this, &FlickrProvider::pageRequestFinished); } FlickrProvider::~FlickrProvider() = default; QImage FlickrProvider::image() const { return mImage; } void FlickrProvider::pageRequestFinished(KJob *_job) { KIO::StoredTransferJob *job = static_cast( _job ); if (job->error()) { emit error(this); qDebug() << "pageRequestFinished error"; return; } const QString data = QString::fromUtf8( job->data() ); // Clear the list m_photoList.clear(); xml.clear(); xml.addData(data); while (!xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { auto attributes = xml.attributes(); if (xml.name() == QLatin1String("rsp")) { const int maxFailure = 5; /* no pictures available for the specified parameters */ if (attributes.value ( QLatin1String( "stat" ) ).toString() != QLatin1String( "ok" )) { if (mFailureNumber < maxFailure) { /* To be sure, decrement the date to two days earlier... @TODO */ mActualDate = mActualDate.addDays(-2); QUrl url = buildUrl(mActualDate); KIO::StoredTransferJob *pageJob = KIO::storedGet(url, KIO::NoReload, KIO::HideProgressInfo); connect(pageJob, &KIO::StoredTransferJob::finished, this, &FlickrProvider::pageRequestFinished); mFailureNumber++; return; } else { emit error(this); qDebug() << "pageRequestFinished error"; return; } } } else if (xml.name() == QLatin1String( "photo" )) { if (attributes.value ( QLatin1String( "ispublic" ) ).toString() != QLatin1String( "1" )) { continue; } const char *fallbackList[] = { "url_k", "url_h" }; bool found = false; for (auto urlAttr : fallbackList) { // Get the best url. QLatin1String urlAttrString(urlAttr); if (attributes.hasAttribute(urlAttrString)) { m_photoList.append(attributes.value(urlAttrString).toString()); found = true; break; } } // The logic here is, if url_h or url_k are present, url_o must // has higher quality, otherwise, url_o is worse than k/h size. // If url_o is better, prefer url_o. if (found) { QLatin1String originAttr("url_o"); if (attributes.hasAttribute(originAttr)) { m_photoList.back() = attributes.value(QLatin1String(originAttr)).toString(); } } } } } if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString(); } if (m_photoList.begin() != m_photoList.end()) { - QUrl url( m_photoList.at(qrand() % m_photoList.size()) ); + QUrl url( m_photoList.at(QRandomGenerator::global()->bounded(m_photoList.size())) ); KIO::StoredTransferJob *imageJob = KIO::storedGet(url, KIO::NoReload, KIO::HideProgressInfo); connect(imageJob, &KIO::StoredTransferJob::finished, this, &FlickrProvider::imageRequestFinished); } else { qDebug() << "empty list"; } } void FlickrProvider::imageRequestFinished(KJob *_job) { KIO::StoredTransferJob *job = static_cast( _job ); if ( job->error() ) { emit error(this); return; } mImage = QImage::fromData( job->data() ); emit finished(this); } K_PLUGIN_CLASS_WITH_JSON(FlickrProvider, "flickrprovider.json") #include "flickrprovider.moc"