File indexing completed on 2025-02-02 04:18:27

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Jouni Pentikäinen <joupent@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_dlg_import_image_sequence.h"
0008 
0009 #include "KisDocument.h"
0010 #include "KisMainWindow.h"
0011 #include "kis_image.h"
0012 #include "kis_image_animation_interface.h"
0013 #include "KisImportExportManager.h"
0014 #include "KoFileDialog.h"
0015 #include <QStandardPaths>
0016 #include <QRegExp>
0017 
0018 
0019 class KisDlgImportImageSequence::ListItem : QListWidgetItem {
0020 
0021 public:
0022     ListItem(const QString &text, QListWidget *view, QCollator *collator)
0023         : QListWidgetItem(text, view)
0024         , collator(collator)
0025     {}
0026 
0027     bool operator <(const QListWidgetItem &other) const override
0028     {
0029         if (collator->numericMode()) {
0030             const QRegExp rx(QLatin1String("[^0-9]+"));
0031 
0032 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
0033             QStringList ours = text().split(rx, Qt::SkipEmptyParts);
0034             QStringList theirs = other.text().split(rx, Qt::SkipEmptyParts);
0035 #else
0036             QStringList ours = text().split(rx, QString::SkipEmptyParts);
0037             QStringList theirs = other.text().split(rx, QString::SkipEmptyParts);
0038 #endif
0039 
0040             // Let's compare the last numbers -- they are most likely to be the serial numbers
0041             if (ours.size() > 0 && theirs.size() > 0) {
0042                 return (ours.last().toInt() < theirs.last().toInt());
0043             }
0044 
0045         }
0046         return collator->compare(this->text(), other.text()) < 0;
0047     }
0048 
0049 private:
0050     QCollator *collator;
0051 };
0052 
0053 KisDlgImportImageSequence::KisDlgImportImageSequence(KisMainWindow *mainWindow, KisDocument *document) :
0054     KoDialog(mainWindow),
0055     m_mainWindow(mainWindow),
0056     m_document(document)
0057 {
0058     setButtons(Ok | Cancel);
0059     setDefaultButton(Ok);
0060 
0061     QWidget * page = new QWidget(this);
0062     m_ui.setupUi(page);
0063     setMainWidget(page);
0064 
0065     enableButtonOk(false);
0066 
0067     m_ui.cmbOrder->addItem(i18n("Ascending"), Ascending);
0068     m_ui.cmbOrder->addItem(i18n("Descending"), Descending);
0069     m_ui.cmbOrder->setCurrentIndex(0);
0070 
0071     m_ui.cmbSortMode->addItem(i18n("Alphabetical"), Natural);
0072     m_ui.cmbSortMode->addItem(i18n("Numerical"), Numerical);
0073     m_ui.cmbSortMode->setCurrentIndex(1);
0074 
0075     m_ui.lstFiles->setSelectionMode(QAbstractItemView::ExtendedSelection);
0076 
0077     connect(m_ui.btnAddImages, &QAbstractButton::clicked, this, &KisDlgImportImageSequence::slotAddFiles);
0078     connect(m_ui.btnRemove, &QAbstractButton::clicked, this, &KisDlgImportImageSequence::slotRemoveFiles);
0079     connect(m_ui.spinStep, SIGNAL(valueChanged(int)), this, SLOT(slotSkipChanged(int)));
0080     connect(m_ui.cmbOrder, SIGNAL(currentIndexChanged(int)), this, SLOT(slotOrderOptionsChanged(int)));
0081     connect(m_ui.cmbSortMode, SIGNAL(currentIndexChanged(int)), this, SLOT(slotOrderOptionsChanged(int)));
0082     connect(m_ui.autoAddHoldframesBox, &QCheckBox::stateChanged, this, &KisDlgImportImageSequence::autoAddHoldframes);
0083     // cold initialization of the controls
0084     slotSkipChanged(m_ui.spinStep->value());
0085     slotOrderOptionsChanged(m_ui.cmbOrder->currentIndex());
0086     slotOrderOptionsChanged(m_ui.cmbSortMode->currentIndex());
0087     m_ui.beginFromZeroIndexBox->hide();
0088 }
0089 
0090 QStringList KisDlgImportImageSequence::files()
0091 {
0092     QStringList list;
0093 
0094     for (int i=0; i < m_ui.lstFiles->count(); i++) {
0095         list.append(m_ui.lstFiles->item(i)->text());
0096     }
0097 
0098     return list;
0099 }
0100 
0101 int KisDlgImportImageSequence::firstFrame()
0102 {
0103     return m_ui.spinFirstFrame->value();
0104 }
0105 
0106 int KisDlgImportImageSequence::step()
0107 {
0108     return m_ui.spinStep->value();
0109 }
0110 
0111 bool KisDlgImportImageSequence::autoAddHoldframes(){
0112 
0113     bool isChecked = m_ui.autoAddHoldframesBox->isChecked();
0114     if(isChecked && m_ui.cmbOrder->currentIndex() == 0){
0115         m_ui.beginFromZeroIndexBox->show();
0116     }
0117     else {
0118         m_ui.beginFromZeroIndexBox->hide();
0119     }
0120     return isChecked;
0121 }
0122 
0123 void KisDlgImportImageSequence::slotAddFiles()
0124 {
0125     QStringList urls = showOpenFileDialog();
0126 
0127     if (!urls.isEmpty()) {
0128         Q_FOREACH(QString url, urls) {
0129             new ListItem(url, m_ui.lstFiles, &m_collator);
0130         }
0131 
0132         sortFileList();
0133     }
0134 
0135     enableButtonOk(m_ui.lstFiles->count() > 0);
0136 }
0137 
0138 QStringList KisDlgImportImageSequence::showOpenFileDialog()
0139 {
0140     KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument");
0141     dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
0142     dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import));
0143     dialog.setCaption(i18n("Import Images"));
0144 
0145     return dialog.filenames();
0146 }
0147 
0148 
0149 
0150 void KisDlgImportImageSequence::slotRemoveFiles()
0151 {
0152     QList<QListWidgetItem*> selected = m_ui.lstFiles->selectedItems();
0153 
0154     Q_FOREACH(QListWidgetItem *item, selected) {
0155         delete item;
0156     }
0157 
0158     enableButtonOk(m_ui.lstFiles->count() > 0);
0159 }
0160 
0161 void KisDlgImportImageSequence::slotSkipChanged(int)
0162 {
0163     int documentFps = m_document->image()->animationInterface()->framerate();
0164     float sourceFps = 1.0f * documentFps / m_ui.spinStep->value();
0165 
0166     m_ui.lblFramerate->setText(i18n("Source fps: %1", sourceFps));
0167 }
0168 
0169 void KisDlgImportImageSequence::slotOrderOptionsChanged(int)
0170 {
0171 
0172     if(m_ui.cmbSortMode->currentIndex() == 0){ // we shouldn't add hold frames automatically if they are sorted alphabetically
0173         m_ui.autoAddHoldframesBox->setChecked(false);
0174         m_ui.autoAddHoldframesBox->setEnabled(false);
0175     }
0176     else {
0177         m_ui.autoAddHoldframesBox->setEnabled(true);
0178     }
0179 
0180     if(m_ui.cmbOrder->currentIndex() == 1){
0181         m_ui.beginFromZeroIndexBox->setChecked(false);   //redundant
0182         m_ui.beginFromZeroIndexBox->hide();
0183     }
0184     this->sortOrder = m_ui.cmbOrder->currentIndex();
0185     sortFileList();
0186 }
0187 
0188 bool KisDlgImportImageSequence::startFrom1(){
0189     return m_ui.beginFromZeroIndexBox->isChecked();
0190 }
0191 
0192 int KisDlgImportImageSequence::isAscending(){
0193     return this->sortOrder;
0194 }
0195 
0196 void KisDlgImportImageSequence::sortFileList()
0197 {
0198     int order = m_ui.cmbOrder->currentData().toInt();
0199     bool numeric = m_ui.cmbSortMode->currentData().toInt() == Numerical;
0200 
0201     m_collator.setNumericMode(numeric);
0202     m_ui.lstFiles->sortItems((order == Ascending) ? Qt::AscendingOrder : Qt::DescendingOrder);
0203 }