File indexing completed on 2024-03-03 05:04:11

0001 /*
0002     SPDX-FileCopyrightText: 2008 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 
0004 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "slideshowclip.h"
0008 #include "bin/projectclip.h"
0009 #include "core.h"
0010 #include "kdenlivesettings.h"
0011 #include "mainwindow.h"
0012 
0013 #include <KFileItem>
0014 #include <KLocalizedString>
0015 #include <KRecentDirs>
0016 
0017 #include "kdenlive_debug.h"
0018 #include <QDir>
0019 #include <QFontDatabase>
0020 #include <QStandardPaths>
0021 #include <QtMath>
0022 
0023 SlideshowClip::SlideshowClip(const Timecode &tc, QString clipFolder, ProjectClip *clip, QWidget *parent)
0024     : QDialog(parent)
0025     , m_count(0)
0026     , m_timecode(tc)
0027     , m_thumbJob(nullptr)
0028 {
0029     setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0030     m_view.setupUi(this);
0031     setWindowTitle(i18nc("@title:window", "Add Image Sequence"));
0032     if (clip) {
0033         m_view.clip_name->setText(clip->name());
0034         m_view.groupBox->setHidden(true);
0035     } else {
0036         m_view.clip_name->setText(i18n("Image Sequence"));
0037     }
0038     m_view.folder_url->setMode(KFile::Directory);
0039     m_view.folder_url->setUrl(QUrl::fromLocalFile(KRecentDirs::dir(QStringLiteral(":KdenliveSlideShowFolder"))));
0040     m_view.icon_list->setIconSize(QSize(50, 50));
0041     m_view.show_thumbs->setChecked(KdenliveSettings::showslideshowthumbs());
0042 
0043     connect(m_view.show_thumbs, &QCheckBox::stateChanged, this, &SlideshowClip::slotEnableThumbs);
0044     connect(m_view.slide_fade, &QCheckBox::stateChanged, this, &SlideshowClip::slotEnableLuma);
0045     connect(m_view.luma_fade, &QCheckBox::stateChanged, this, &SlideshowClip::slotEnableLumaFile);
0046 
0047     // WARNING: keep in sync with project/clipproperties.cpp
0048     m_view.image_type->addItem(QStringLiteral("JPG (*.jpg)"), QStringLiteral("jpg"));
0049     m_view.image_type->addItem(QStringLiteral("JPEG (*.jpeg)"), QStringLiteral("jpeg"));
0050     m_view.image_type->addItem(QStringLiteral("PNG (*.png)"), QStringLiteral("png"));
0051     m_view.image_type->addItem(QStringLiteral("SVG (*.svg)"), QStringLiteral("svg"));
0052     m_view.image_type->addItem(QStringLiteral("BMP (*.bmp)"), QStringLiteral("bmp"));
0053     m_view.image_type->addItem(QStringLiteral("GIF (*.gif)"), QStringLiteral("gif"));
0054     m_view.image_type->addItem(QStringLiteral("TGA (*.tga)"), QStringLiteral("tga"));
0055     m_view.image_type->addItem(QStringLiteral("TIF (*.tif)"), QStringLiteral("tif"));
0056     m_view.image_type->addItem(QStringLiteral("TIFF (*.tiff)"), QStringLiteral("tiff"));
0057     m_view.image_type->addItem(QStringLiteral("Open EXR (*.exr)"), QStringLiteral("exr"));
0058     m_view.image_type->addItem(i18n("Preview from CR2 (*.cr2)"), QStringLiteral("cr2"));
0059     m_view.image_type->addItem(i18n("Preview from ARW (*.arw)"), QStringLiteral("arw"));
0060     m_view.animation->addItem(i18n("None"), QString());
0061 
0062     KConfig conf(QStringLiteral("slideanimations.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation);
0063     KConfigGroup group(&conf, "slides");
0064     QMap<QString, QString> slideTranslations;
0065     slideTranslations.insert(QStringLiteral("Pan"), i18nc("Image Pan", "Pan"));
0066     slideTranslations.insert(QStringLiteral("Pan and zoom"), i18n("Pan and zoom"));
0067     slideTranslations.insert(QStringLiteral("Zoom"), i18n("Zoom"));
0068     QStringList animValues = group.keyList();
0069     for (const auto &val : animValues) {
0070         if (slideTranslations.contains(val)) {
0071             m_view.animation->addItem(slideTranslations.value(val), val);
0072         } else {
0073             m_view.animation->addItem(val, val);
0074         }
0075     }
0076 
0077     m_view.clip_duration->setInputMask(m_timecode.mask());
0078     m_view.luma_duration->setInputMask(m_timecode.mask());
0079     m_view.luma_duration->setText(m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))));
0080 
0081     if (clipFolder.isEmpty()) {
0082         clipFolder = QDir::homePath();
0083     }
0084     m_view.folder_url->setUrl(QUrl::fromLocalFile(QFileInfo(clipFolder).dir().absolutePath()));
0085 
0086     m_view.clip_duration_format->addItem(i18n("hh:mm:ss:ff"));
0087     m_view.clip_duration_format->addItem(i18n("Frames"));
0088     connect(m_view.clip_duration_format, SIGNAL(activated(int)), this, SLOT(slotUpdateDurationFormat(int)));
0089     m_view.clip_duration_frames->setHidden(true);
0090     m_view.luma_duration_frames->setHidden(true);
0091     if (clip) {
0092         QString url = clip->url();
0093         if (QFileInfo(url).fileName().startsWith(QLatin1String(".all."))) {
0094             // the image sequence is defined by MIME type
0095             m_view.method_mime->setChecked(true);
0096             m_view.folder_url->setText(QFileInfo(url).absolutePath());
0097             QString filter = QFileInfo(url).fileName();
0098             QString ext = filter.section(QLatin1Char('.'), -1);
0099             int ix = m_view.image_type->findData(ext);
0100             if (ix > -1) {
0101                 m_view.image_type->setCurrentIndex(ix);
0102             }
0103         } else {
0104             // the image sequence is defined by pattern
0105             m_view.method_pattern->setChecked(true);
0106             m_view.pattern_url->setText(url);
0107         }
0108     } else {
0109         // Using clipfolder file path
0110         QFileInfo file(clipFolder);
0111         QString extension = KdenliveSettings::slideshowmimeextension();
0112         if (file.isFile()) {
0113             extension = file.suffix();
0114             m_view.folder_url->setText(file.dir().absolutePath());
0115         }
0116         if (!extension.isEmpty()) {
0117             int ix = m_view.image_type->findData(extension);
0118             if (ix > -1) {
0119                 m_view.image_type->setCurrentIndex(ix);
0120             }
0121         }
0122         m_view.pattern_url->setUrl(QUrl::fromLocalFile(clipFolder));
0123         m_view.method_mime->setChecked(KdenliveSettings::slideshowbymime());
0124         slotMethodChanged(m_view.method_mime->isChecked());
0125         parseFolder();
0126     }
0127     connect(m_view.method_mime, &QAbstractButton::toggled, this, &SlideshowClip::slotMethodChanged);
0128     connect(m_view.image_type, SIGNAL(currentIndexChanged(int)), this, SLOT(parseFolder()));
0129     connect(m_view.folder_url, &KUrlRequester::textChanged, this, &SlideshowClip::parseFolder);
0130     connect(m_view.pattern_url, &KUrlRequester::textChanged, this, &SlideshowClip::parseFolder);
0131 
0132     // Fill luma list
0133     m_view.luma_file->setIconSize(QSize(50, 30));
0134     QStringList values;
0135     if (pCore->getCurrentFrameSize().width() > 1000) {
0136         // HD project
0137         values = MainWindow::m_lumaFiles.value(QStringLiteral("16_9"));
0138     } else if (pCore->getCurrentFrameSize().height() > 1000) {
0139         values = MainWindow::m_lumaFiles.value(QStringLiteral("9_16"));
0140     } else if (pCore->getCurrentFrameSize().height() == pCore->getCurrentFrameSize().width()) {
0141         values = MainWindow::m_lumaFiles.value(QStringLiteral("square"));
0142     } else if (pCore->getCurrentFrameSize().height() == 480) {
0143         values = MainWindow::m_lumaFiles.value(QStringLiteral("NTSC"));
0144     } else {
0145         values = MainWindow::m_lumaFiles.value(QStringLiteral("PAL"));
0146     }
0147     values.removeDuplicates();
0148 
0149     QStringList names;
0150     for (const QString &value : qAsConst(values)) {
0151         names.append(QUrl(value).fileName());
0152     }
0153     for (int i = 0; i < values.count(); i++) {
0154         const QString &entry = values.at(i);
0155         // Create thumbnails
0156         if (!entry.isEmpty() && (entry.endsWith(QLatin1String(".png")) || entry.endsWith(QLatin1String(".pgm")))) {
0157             if (MainWindow::m_lumacache.contains(entry)) {
0158                 m_view.luma_file->addItem(QPixmap::fromImage(MainWindow::m_lumacache.value(entry)), names.at(i), entry);
0159             } else {
0160                 QImage pix(entry);
0161                 if (!pix.isNull()) {
0162                     MainWindow::m_lumacache.insert(entry, pix.scaled(50, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation));
0163                     m_view.luma_file->addItem(QPixmap::fromImage(MainWindow::m_lumacache.value(entry)), names.at(i), entry);
0164                 }
0165             }
0166         }
0167     }
0168 
0169     if (clip) {
0170         m_view.slide_loop->setChecked(clip->getProducerIntProperty(QStringLiteral("loop")) != 0);
0171         m_view.slide_crop->setChecked(clip->getProducerIntProperty(QStringLiteral("crop")) != 0);
0172         m_view.slide_fade->setChecked(clip->getProducerIntProperty(QStringLiteral("fade")) != 0);
0173         m_view.luma_softness->setValue(clip->getProducerIntProperty(QStringLiteral("softness")));
0174         QString anim = clip->getProducerProperty(QStringLiteral("animation"));
0175         if (!anim.isEmpty()) {
0176             int ix = m_view.animation->findData(anim);
0177             m_view.animation->setCurrentIndex(qMax(0, ix));
0178         } else {
0179             m_view.animation->setCurrentIndex(0);
0180         }
0181         m_view.low_pass->setChecked(clip->getProducerProperty(QStringLiteral("low-pass")) == QLatin1String("1"));
0182         int ttl = clip->getProducerIntProperty(QStringLiteral("ttl"));
0183         m_view.clip_duration->setText(tc.getTimecodeFromFrames(ttl));
0184         m_view.clip_duration_frames->setValue(ttl);
0185         m_view.luma_duration->setText(tc.getTimecodeFromFrames(clip->getProducerIntProperty(QStringLiteral("luma_duration"))));
0186         QString lumaFile = clip->getProducerProperty(QStringLiteral("luma_file"));
0187         if (!lumaFile.isEmpty()) {
0188             m_view.luma_fade->setChecked(true);
0189             m_view.luma_file->setCurrentIndex(m_view.luma_file->findData(lumaFile));
0190         } else {
0191             m_view.luma_file->setEnabled(false);
0192         }
0193         slotEnableLuma(m_view.slide_fade->checkState());
0194         slotEnableLumaFile(m_view.luma_fade->checkState());
0195         parseFolder();
0196     }
0197     m_view.low_pass->setEnabled(!m_view.animation->currentData().isNull());
0198     connect(m_view.animation, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this,
0199             [&]() { m_view.low_pass->setEnabled(!m_view.animation->currentData().isNull()); });
0200     // adjustSize();
0201 }
0202 
0203 SlideshowClip::~SlideshowClip()
0204 {
0205     delete m_thumbJob;
0206 }
0207 
0208 void SlideshowClip::slotEnableLuma(int state)
0209 {
0210     bool enable = false;
0211     if (state == Qt::Checked) {
0212         enable = true;
0213     }
0214     m_view.luma_duration->setEnabled(enable);
0215     m_view.luma_duration_frames->setEnabled(enable);
0216     m_view.luma_fade->setEnabled(enable);
0217     if (enable) {
0218         m_view.luma_file->setEnabled(m_view.luma_fade->isChecked());
0219     } else {
0220         m_view.luma_file->setEnabled(false);
0221     }
0222     m_view.label_softness->setEnabled(m_view.luma_fade->isChecked() && enable);
0223     m_view.luma_softness->setEnabled(m_view.label_softness->isEnabled());
0224 }
0225 
0226 void SlideshowClip::slotEnableThumbs(int state)
0227 {
0228     if (state == Qt::Checked) {
0229         KdenliveSettings::setShowslideshowthumbs(true);
0230         slotGenerateThumbs();
0231     } else {
0232         KdenliveSettings::setShowslideshowthumbs(false);
0233         if (m_thumbJob) {
0234             disconnect(m_thumbJob, &KIO::PreviewJob::gotPreview, this, &SlideshowClip::slotSetPixmap);
0235             m_thumbJob->kill();
0236             m_thumbJob->deleteLater();
0237             m_thumbJob = nullptr;
0238         }
0239     }
0240 }
0241 
0242 void SlideshowClip::slotEnableLumaFile(int state)
0243 {
0244     bool enable = false;
0245     if (state == Qt::Checked) {
0246         enable = true;
0247     }
0248     m_view.luma_file->setEnabled(enable);
0249     m_view.luma_softness->setEnabled(enable);
0250     m_view.label_softness->setEnabled(enable);
0251 }
0252 
0253 void SlideshowClip::parseFolder()
0254 {
0255     m_view.icon_list->clear();
0256     bool isMime = m_view.method_mime->isChecked();
0257     QString path = isMime ? m_view.folder_url->url().toLocalFile() : m_view.pattern_url->url().adjusted(QUrl::RemoveFilename).toLocalFile();
0258     QDir dir(path);
0259     if (path.isEmpty() || !dir.exists()) {
0260         m_count = 0;
0261         m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
0262         m_view.label_info->setText(QString());
0263         return;
0264     }
0265 
0266     QIcon unknownicon(QStringLiteral("unknown"));
0267     QStringList result;
0268     QStringList filters;
0269     QString filter;
0270     if (isMime) {
0271         // TODO: improve jpeg image detection with extension like jpeg, requires change in MLT image producers
0272         filter = m_view.image_type->currentData().toString();
0273         filters << QStringLiteral("*.") + filter;
0274         dir.setNameFilters(filters);
0275         result = dir.entryList(QDir::Files);
0276     } else {
0277         int offset = 0;
0278         QString path_pattern = m_view.pattern_url->text();
0279         QDir abs_dir = QFileInfo(m_view.pattern_url->text()).absoluteDir();
0280         result = abs_dir.entryList(QDir::Files);
0281         // find pattern
0282         if (path_pattern.contains(QLatin1Char('?'))) {
0283             // New MLT syntax
0284             if (path_pattern.section(QLatin1Char('?'), 1).contains(QLatin1Char(':'))) {
0285                 // Old deprecated format
0286                 offset = path_pattern.section(QLatin1Char(':'), -1).toInt();
0287             } else {
0288                 offset = path_pattern.section(QLatin1Char('='), -1).toInt();
0289             }
0290             path_pattern = path_pattern.section(QLatin1Char('?'), 0, 0);
0291         }
0292         filter = QFileInfo(path_pattern).fileName();
0293         QString ext = filter.section(QLatin1Char('.'), -1);
0294         if (filter.contains(QLatin1Char('%'))) {
0295             filter = filter.section(QLatin1Char('%'), 0, -2);
0296         } else {
0297             filter = filter.section(QLatin1Char('.'), 0, -2);
0298             while (!filter.isEmpty() && filter.at(filter.count() - 1).isDigit()) {
0299                 filter.remove(filter.count() - 1, 1);
0300             }
0301         }
0302         qDebug() << " / /" << path_pattern << " / " << ext << " / " << filter;
0303         QString regexp = QLatin1Char('^') + filter + QStringLiteral("\\d+\\.") + ext + QLatin1Char('$');
0304         static const QRegularExpression rx(QRegularExpression::anchoredPattern(regexp));
0305         QStringList entries;
0306         for (const QString &p : qAsConst(result)) {
0307             if (rx.match(p).hasMatch()) {
0308                 if (offset > 0) {
0309                     // make sure our image is in the range we want (> begin)
0310                     int ix = p.section(filter, 1).section('.', 0, 0).toInt();
0311                     if (ix < offset) {
0312                         continue;
0313                     }
0314                 }
0315                 entries << p;
0316             }
0317         }
0318         result = entries;
0319     }
0320     for (const QString &p : qAsConst(result)) {
0321         auto *item = new QListWidgetItem(unknownicon, p);
0322         item->setData(Qt::UserRole, dir.filePath(p));
0323         m_view.icon_list->addItem(item);
0324     }
0325     m_count = m_view.icon_list->count();
0326     m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_count > 0);
0327     if (m_count == 0) {
0328         m_view.label_info->setText(i18n("No image found"));
0329     } else {
0330         m_view.label_info->setText(i18np("1 image found", "%1 images found", m_count));
0331     }
0332     if (m_view.show_thumbs->isChecked()) {
0333         slotGenerateThumbs();
0334     }
0335     m_view.icon_list->setCurrentRow(0);
0336 }
0337 
0338 void SlideshowClip::slotGenerateThumbs()
0339 {
0340     delete m_thumbJob;
0341     KFileItemList fileList;
0342     for (int i = 0; i < m_view.icon_list->count(); ++i) {
0343         QListWidgetItem *item = m_view.icon_list->item(i);
0344         if (item) {
0345             QString path = item->data(Qt::UserRole).toString();
0346             if (!path.isEmpty()) {
0347                 KFileItem f(QUrl::fromLocalFile(path));
0348                 f.setDelayedMimeTypes(true);
0349                 fileList.append(f);
0350             }
0351         }
0352     }
0353     m_thumbJob = new KIO::PreviewJob(fileList, QSize(50, 50));
0354     m_thumbJob->setScaleType(KIO::PreviewJob::Scaled);
0355     m_thumbJob->setAutoDelete(false);
0356     connect(m_thumbJob, &KIO::PreviewJob::gotPreview, this, &SlideshowClip::slotSetPixmap);
0357     m_thumbJob->start();
0358 }
0359 
0360 void SlideshowClip::slotSetPixmap(const KFileItem &fileItem, const QPixmap &pix)
0361 {
0362     for (int i = 0; i < m_view.icon_list->count(); ++i) {
0363         QListWidgetItem *item = m_view.icon_list->item(i);
0364         if (item) {
0365             QString path = item->data(Qt::UserRole).toString();
0366             if (path == fileItem.url().toLocalFile()) {
0367                 item->setIcon(QIcon(pix));
0368                 item->setData(Qt::UserRole, QString());
0369                 break;
0370             }
0371         }
0372     }
0373 }
0374 
0375 QString SlideshowClip::selectedPath()
0376 {
0377     QStringList list;
0378     QUrl url;
0379     if (m_view.method_mime->isChecked()) {
0380         url = m_view.folder_url->url();
0381     } else {
0382         url = m_view.pattern_url->url();
0383     }
0384     QString path = selectedPath(url, m_view.method_mime->isChecked(), QStringLiteral(".all.") + m_view.image_type->currentData().toString(), &list);
0385     m_count = list.count();
0386     // qCDebug(KDENLIVE_LOG)<<"// SELECTED PATH: "<<path;
0387     return path;
0388 }
0389 
0390 // static
0391 int SlideshowClip::getFrameNumberFromPath(const QUrl &path)
0392 {
0393     QString filter = path.fileName();
0394     filter = filter.section(QLatin1Char('.'), 0, -2);
0395     int ix = filter.size() - 1;
0396     while (ix >= 0 && filter.at(ix).isDigit()) {
0397         ix--;
0398     }
0399     return filter.remove(0, ix + 1).toInt();
0400 }
0401 
0402 // static
0403 QString SlideshowClip::selectedPath(const QUrl &url, bool isMime, QString extension, QStringList *list)
0404 {
0405     QString folder;
0406     if (isMime) {
0407         folder = url.toLocalFile();
0408         if (!folder.endsWith(QLatin1Char('/'))) {
0409             folder.append(QLatin1Char('/'));
0410         }
0411         // Check how many files we have
0412         QDir dir(folder);
0413         QStringList filters;
0414         filters << QStringLiteral("*.") + extension.section(QLatin1Char('.'), -1);
0415         dir.setNameFilters(filters);
0416         *list = dir.entryList(QDir::Files);
0417     } else {
0418         folder = url.adjusted(QUrl::RemoveFilename).toLocalFile();
0419         QString filter = url.fileName();
0420         QString ext = QLatin1Char('.') + filter.section(QLatin1Char('.'), -1);
0421         filter = filter.section(QLatin1Char('.'), 0, -2);
0422         int fullSize = filter.size();
0423         QString firstFrameData = filter;
0424 
0425         while (filter.size() > 0 && filter.at(filter.size() - 1).isDigit()) {
0426             filter.chop(1);
0427         }
0428 
0429         // Find number of digits in sequence
0430         int precision = fullSize - filter.size();
0431 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0432         int firstFrame = firstFrameData.rightRef(precision).toInt();
0433 #else
0434         int firstFrame = QStringView(firstFrameData).right(precision).toInt();
0435 #endif
0436         // Check how many files we have
0437         QDir dir(folder);
0438         QString path;
0439         int gap = 0;
0440         for (int i = firstFrame; gap < 100; ++i) {
0441             path = filter + QString::number(i).rightJustified(precision, QLatin1Char('0'), false) + ext;
0442             if (dir.exists(path)) {
0443                 (*list).append(folder + path);
0444                 gap = 0;
0445             } else {
0446                 gap++;
0447             }
0448         }
0449         extension = filter + QStringLiteral("%0") + QString::number(precision) + QLatin1Char('d') + ext;
0450         if (firstFrame > 0) {
0451             extension.append(QStringLiteral("?begin=%1").arg(firstFrame));
0452         }
0453     }
0454     // qCDebug(KDENLIVE_LOG) << "// FOUND " << (*list).count() << " items for " << url.toLocalFile();
0455     return folder + extension;
0456 }
0457 
0458 QString SlideshowClip::clipName() const
0459 {
0460     return m_view.clip_name->text();
0461 }
0462 
0463 QString SlideshowClip::clipDuration() const
0464 {
0465     if (m_view.clip_duration_format->currentIndex() == 1) {
0466         // we are in frames mode
0467         return m_timecode.getTimecodeFromFrames(m_view.clip_duration_frames->value());
0468     }
0469     return m_view.clip_duration->text();
0470 }
0471 
0472 int SlideshowClip::imageCount() const
0473 {
0474     return m_count;
0475 }
0476 
0477 int SlideshowClip::softness() const
0478 {
0479     return m_view.luma_softness->value();
0480 }
0481 
0482 bool SlideshowClip::loop() const
0483 {
0484     return m_view.slide_loop->isChecked();
0485 }
0486 
0487 bool SlideshowClip::crop() const
0488 {
0489     return m_view.slide_crop->isChecked();
0490 }
0491 
0492 bool SlideshowClip::fade() const
0493 {
0494     return m_view.slide_fade->isChecked();
0495 }
0496 
0497 QString SlideshowClip::lumaDuration() const
0498 {
0499     if (m_view.clip_duration_format->currentIndex() == 1) {
0500         // we are in frames mode
0501         return m_timecode.getTimecodeFromFrames(m_view.luma_duration_frames->value());
0502     }
0503     return m_view.luma_duration->text();
0504 }
0505 
0506 QString SlideshowClip::lumaFile() const
0507 {
0508     if (!m_view.luma_fade->isChecked() || !m_view.luma_file->isEnabled()) {
0509         return QString();
0510     }
0511     return m_view.luma_file->itemData(m_view.luma_file->currentIndex()).toString();
0512 }
0513 
0514 QString SlideshowClip::animation() const
0515 {
0516     if (m_view.animation->currentData().isNull()) {
0517         return QString();
0518     }
0519     return m_view.animation->currentData().toString();
0520 }
0521 
0522 void SlideshowClip::slotUpdateDurationFormat(int ix)
0523 {
0524     bool framesFormat = ix == 1;
0525     if (framesFormat) {
0526         // switching to frames count, update widget
0527         m_view.clip_duration_frames->setValue(m_timecode.getFrameCount(m_view.clip_duration->text()));
0528         m_view.luma_duration_frames->setValue(m_timecode.getFrameCount(m_view.luma_duration->text()));
0529     } else {
0530         // switching to timecode format
0531         m_view.clip_duration->setText(m_timecode.getTimecodeFromFrames(m_view.clip_duration_frames->value()));
0532         m_view.luma_duration->setText(m_timecode.getTimecodeFromFrames(m_view.luma_duration_frames->value()));
0533     }
0534     m_view.clip_duration_frames->setHidden(!framesFormat);
0535     m_view.clip_duration->setHidden(framesFormat);
0536     m_view.luma_duration_frames->setHidden(!framesFormat);
0537     m_view.luma_duration->setHidden(framesFormat);
0538 }
0539 
0540 void SlideshowClip::slotMethodChanged(bool active)
0541 {
0542     if (active) {
0543         // User wants MIME type image sequence
0544         m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::image_duration()));
0545         m_view.stackedWidget->setCurrentIndex(0);
0546         KdenliveSettings::setSlideshowbymime(true);
0547     } else {
0548         // User wants pattern image sequence
0549         m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()));
0550         m_view.stackedWidget->setCurrentIndex(1);
0551         KdenliveSettings::setSlideshowbymime(false);
0552     }
0553     parseFolder();
0554 }
0555 
0556 int SlideshowClip::lowPass() const
0557 {
0558     return m_view.low_pass->isEnabled() && m_view.low_pass->isChecked() ? 1 : 0;
0559 }
0560 
0561 // static
0562 QString SlideshowClip::animationToGeometry(const QString &animation, int &ttl)
0563 {
0564     // load animation profiles
0565     KConfig conf(QStringLiteral("slideanimations.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation);
0566     KConfigGroup group(&conf, "slides");
0567     QString geometry;
0568     if (group.hasKey(animation)) {
0569         geometry = group.readEntry(animation);
0570     }
0571     int frames = geometry.count(QLatin1String("%d="));
0572     int frameNumber = ttl - 1;
0573     QString str = QStringLiteral("%d");
0574     for (int i = 0; i < frames; i++) {
0575         geometry.replace(geometry.indexOf(str), 2, QString::number(frameNumber));
0576         frameNumber = qFloor((i + 3) / 2) * ttl;
0577         frameNumber -= (i % 2);
0578     }
0579     return geometry;
0580 }
0581 
0582 const QString SlideshowClip::extension() const
0583 {
0584     return m_view.image_type->currentData().toString();
0585 }