File indexing completed on 2024-04-21 05:54:05

0001 /*
0002     SPDX-FileCopyrightText: 2005-2006, 2010 Tom Albers <toma@kde.org>
0003     SPDX-FileCopyrightText: 2006 Bram Schoenmakers <bramschoenmakers@kde.nl>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "slideshoweffect.h"
0009 #include "breakbase.h"
0010 
0011 #include <QApplication>
0012 #include <QDebug>
0013 #include <QDir>
0014 #include <QLabel>
0015 #include <QRandomGenerator>
0016 #include <QScreen>
0017 #include <QTimer>
0018 #include <QVBoxLayout>
0019 
0020 #include <KWindowSystem>
0021 
0022 SlideEffect::SlideEffect(QObject *parent)
0023     : BreakBase(parent)
0024     , m_searchRecursive(false)
0025     , m_showSmallImages(false)
0026 {
0027     // Make all other screens gray...
0028     slotGray();
0029     connect(qApp, &QGuiApplication::screenAdded, this, &SlideEffect::slotGray);
0030     connect(qApp, &QGuiApplication::screenRemoved, this, &SlideEffect::slotGray);
0031 
0032     m_slidewidget = new SlideWidget(nullptr);
0033     KWindowSystem::forceActiveWindow(m_slidewidget->winId());
0034     KWindowSystem::setOnAllDesktops(m_slidewidget->winId(), true);
0035     KWindowSystem::setState(m_slidewidget->winId(), NET::KeepAbove);
0036     KWindowSystem::setState(m_slidewidget->winId(), NET::FullScreen);
0037 
0038     setReadOnly(true);
0039 
0040     m_timer_slide = new QTimer(this);
0041     connect(m_timer_slide, &QTimer::timeout, this, &SlideEffect::slotNewSlide);
0042 }
0043 
0044 SlideEffect::~SlideEffect()
0045 {
0046     delete m_slidewidget;
0047 }
0048 
0049 void SlideEffect::slotGray()
0050 {
0051     // Make all other screens gray...
0052     setGrayEffectOnAllScreens(true);
0053     excludeGrayEffectOnScreen(QGuiApplication::primaryScreen());
0054 }
0055 
0056 bool SlideEffect::hasImages()
0057 {
0058     return m_files.count() > 0;
0059 }
0060 
0061 void SlideEffect::activate()
0062 {
0063     m_slidewidget->show();
0064     m_timer_slide->start(m_slideInterval * 1000);
0065     BreakBase::activate();
0066 }
0067 
0068 void SlideEffect::deactivate()
0069 {
0070     m_timer_slide->stop();
0071     m_slidewidget->hide();
0072     BreakBase::deactivate();
0073 }
0074 
0075 void SlideEffect::loadImage()
0076 {
0077     if (m_files.count() == 0)
0078         return;
0079 
0080     // Base the size on the size of the screen, for xinerama.
0081     const QSize size = QGuiApplication::primaryScreen()->geometry().size();
0082 
0083     // Do not accept images whose surface is more than 3 times smaller than
0084     // screen
0085     int min_image_surface = size.width() * size.height() / 3;
0086     QImage image;
0087 
0088     while (true) {
0089         // reset if all images are shown
0090         if (m_files_done.count() == m_files.count())
0091             m_files_done.clear();
0092 
0093         // get a not yet used image
0094         int j;
0095         QString name;
0096         do {
0097             j = QRandomGenerator::global()->bounded(m_files.count());
0098             name = m_files[j];
0099         } while (m_files_done.indexOf(name) != -1);
0100 
0101         // load image
0102         qDebug() << "Loading:" << name << "(" << j << "/" << m_files.count() << ") ";
0103         image.load(name);
0104 
0105         // Check size
0106         if (image.width() * image.height() >= min_image_surface || m_showSmallImages) {
0107             // Image is big enough, leave while loop
0108             m_files_done.append(name);
0109             break;
0110         } else {
0111             // Too small, remove from list
0112             m_files.removeAll(name);
0113             if (m_files.count() == 0) {
0114                 // Couldn't find any image big enough, leave function
0115                 return;
0116             }
0117         }
0118     }
0119 
0120     const Qt::AspectRatioMode mode = (m_expandImageToFullScreen) ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio;
0121     const QImage m(image.scaled(size.width(), size.height(), mode));
0122 
0123     if (m.isNull())
0124         return;
0125 
0126     m_slidewidget->setImage(m);
0127 }
0128 
0129 void SlideEffect::findImagesInFolder(const QString &folder)
0130 {
0131     if (folder.isNull())
0132         return;
0133 
0134     QDir dir(folder);
0135 
0136     if (!dir.exists() || !dir.isReadable()) {
0137         qWarning() << "Folder does not exist or is not readable: " << folder;
0138         return;
0139     }
0140 
0141     // TODO: make an automated filter, maybe with QImageIO.
0142     QStringList filters;
0143     filters << "*.png"
0144             << "*.jpg"
0145             << "*.jpeg"
0146             << "*.tif"
0147             << "*.tiff"
0148             << "*.gif"
0149             << "*.bmp"
0150             << "*.xpm"
0151             << "*.ppm"
0152             << "*.pnm"
0153             << "*.xcf"
0154             << "*.pcx";
0155     QStringList filtersUp;
0156     for (int i = 0; i < filters.size(); ++i)
0157         filtersUp << filters.at(i).toUpper();
0158     dir.setNameFilters(filters << filtersUp);
0159     dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::AllDirs);
0160 
0161     const QFileInfoList list = dir.entryInfoList();
0162     for (int i = 0; i < list.count(); ++i) {
0163         QFileInfo fi = list.at(i);
0164         if (fi.isFile())
0165             m_files.append(fi.filePath());
0166         else if (fi.isDir() && m_searchRecursive && fi.fileName() != "." && fi.fileName() != "..")
0167             findImagesInFolder(fi.absoluteFilePath());
0168     }
0169 }
0170 
0171 void SlideEffect::slotNewSlide()
0172 {
0173     if (m_files.count() == 1)
0174         return;
0175 
0176     loadImage();
0177 }
0178 
0179 void SlideEffect::reset(const QString &path, bool recursive, bool showSmallImages, bool expandImageToFullScreen, int slideInterval)
0180 {
0181     m_files.clear();
0182     m_files_done.clear();
0183     m_basePath = path;
0184     m_searchRecursive = recursive;
0185     m_showSmallImages = showSmallImages;
0186     m_slideInterval = slideInterval;
0187     m_expandImageToFullScreen = expandImageToFullScreen;
0188 
0189     findImagesInFolder(path);
0190     qDebug() << "Amount of Files:" << m_files.count();
0191     QTimer::singleShot(2000, this, &SlideEffect::slotNewSlide);
0192 }
0193 
0194 // ------------------ Show widget
0195 
0196 SlideWidget::SlideWidget(QWidget *parent)
0197     : QWidget(parent, Qt::Popup)
0198 {
0199     slotDimension();
0200     connect(qApp, &QGuiApplication::screenAdded, this, &SlideWidget::slotDimension);
0201     connect(qApp, &QGuiApplication::screenRemoved, this, &SlideWidget::slotDimension);
0202 
0203     QVBoxLayout *boxLayout = new QVBoxLayout(this);
0204     boxLayout->setSpacing(0);
0205     boxLayout->setContentsMargins(0, 0, 0, 0);
0206     setLayout(boxLayout);
0207     m_imageLabel = new QLabel();
0208     m_imageLabel->setMaximumSize(width(), height());
0209     m_imageLabel->setAlignment(Qt::AlignCenter);
0210     layout()->addWidget(m_imageLabel);
0211 }
0212 
0213 SlideWidget::~SlideWidget()
0214 {
0215 }
0216 
0217 void SlideWidget::slotDimension()
0218 {
0219     const QRect rect = QGuiApplication::primaryScreen()->geometry();
0220     setGeometry(rect);
0221 }
0222 
0223 void SlideWidget::setImage(const QImage &image)
0224 {
0225     m_imageLabel->setPixmap(QPixmap::fromImage(image));
0226 }