1 /*
2     SPDX-FileCopyrightText: 2019 Jean-Baptiste Mardelle
3     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
4 */
5 
6 #include "buttonparamwidget.hpp"
7 #include "assets/model/assetparametermodel.hpp"
8 #include "jobs/filtertask.h"
9 #include "assets/model/assetcommand.hpp"
10 #include "core.h"
11 #include <mlt++/Mlt.h>
12 
13 #include <KMessageWidget>
14 #include <QPushButton>
15 #include <QVBoxLayout>
16 #include <QProgressBar>
17 
ButtonParamWidget(std::shared_ptr<AssetParameterModel> model,QModelIndex index,QWidget * parent)18 ButtonParamWidget::ButtonParamWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, QWidget *parent)
19     : AbstractParamWidget(std::move(model), index, parent)
20     , m_label(nullptr)
21 {
22     // setup the comment
23     m_buttonName = m_model->data(m_index, Qt::DisplayRole).toString();
24     m_alternatebuttonName = m_model->data(m_index, AssetParameterModel::AlternateNameRole).toString();
25     //QString name = m_model->data(m_index, AssetParameterModel::NameRole).toString();
26     QString comment = m_model->data(m_index, AssetParameterModel::CommentRole).toString();
27     setToolTip(comment);
28     //setEnabled(m_model->getOwnerId().first != ObjectType::TimelineTrack);
29     auto *layout = new QVBoxLayout(this);
30     QVariantList filterData = m_model->data(m_index, AssetParameterModel::FilterJobParamsRole).toList();
31 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
32     QStringList filterAddedParams = m_model->data(m_index, AssetParameterModel::FilterParamsRole).toString().split(QLatin1Char(' '), QString::SkipEmptyParts);
33 #else
34     QStringList filterAddedParams = m_model->data(m_index, AssetParameterModel::FilterParamsRole).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
35 #endif
36 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
37     QStringList consumerParams = m_model->data(m_index, AssetParameterModel::FilterConsumerParamsRole).toString().split(QLatin1Char(' '), QString::SkipEmptyParts);
38 #else
39     QStringList consumerParams = m_model->data(m_index, AssetParameterModel::FilterConsumerParamsRole).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
40 #endif
41 
42     QString conditionalInfo;
43     QString defaultValue;
44     for (const QVariant &jobElement : qAsConst(filterData)) {
45         QStringList d = jobElement.toStringList();
46         if (d.size() == 2) {
47             if (d.at(0) == QLatin1String("conditionalinfo")) {
48                 conditionalInfo = d.at(1);
49             } else if (d.at(0) == QLatin1String("key")) {
50                 m_keyParam = d.at(1);
51             } else if (d.at(0) == QLatin1String("keydefault")) {
52                 defaultValue = d.at(1);
53             }
54         }
55     }
56     QVector<QPair<QString, QVariant>> filterParams = m_model->getAllParameters();
57     m_displayConditional = true;
58     for (const auto &param : qAsConst(filterParams)) {
59         if (param.first == m_keyParam) {
60             if (!param.second.toString().isEmpty() && param.second.toString().contains(QLatin1Char(';'))) {
61                 m_displayConditional = false;
62             }
63             break;
64         }
65     }
66     if (!conditionalInfo.isEmpty()) {
67         m_label = new KMessageWidget(conditionalInfo, this);
68         m_label->setWordWrap(true);
69         layout->addWidget(m_label);
70         m_label->setVisible(m_displayConditional);
71     }
72     layout->setContentsMargins(0, 0, 0, 0);
73     layout->setSpacing(0);
74     m_button = new QPushButton(m_displayConditional ? m_buttonName : m_alternatebuttonName, this);
75     layout->addWidget(m_button);
76     m_progress = new QProgressBar(this);
77     m_progress->setMaximumHeight(m_button->height() / 5);
78     m_progress->setTextVisible(false);
79     layout->addWidget(m_progress);
80     m_progress->setVisible(false);
81     setMinimumHeight(m_button->sizeHint().height() + (m_label != nullptr ? m_label->sizeHint().height() : 0));
82 
83     // emit the signal of the base class when appropriate
84     connect(this->m_button, &QPushButton::clicked, this, [&, filterData, filterAddedParams, consumerParams, defaultValue]() {
85         // Trigger job
86         bool isTracker = m_model->getAssetId() == QLatin1String("opencv.tracker");
87         if (!m_displayConditional) {
88             QVector<QPair<QString, QVariant>> values;
89             if (isTracker) {
90                 // Tracker needs some special config on reset
91                 QString current = m_model->getAsset()->get(m_keyParam.toUtf8().constData());
92                 if (!current.isEmpty()) {
93                     // Extract first keyframe
94                     current = current.section(QLatin1Char('='), 1);
95                     current = current.section(QLatin1Char(';'), 0, 0);
96                 }
97                 if (current.isEmpty()) {
98                     if (defaultValue.contains(QLatin1Char('%'))) {
99                         QSize pSize = pCore->getCurrentFrameDisplaySize();
100                         QStringList numbers = defaultValue.split(QLatin1Char(' '));
101                         int ix = 0;
102                         for ( QString &val : numbers) {
103                             if (val.endsWith(QLatin1Char('%'))) {
104                                 val.chop(1);
105                                 double n = val.toDouble()/100.;
106                                 if (ix %2 == 0) {
107                                     n *= pSize.width();
108                                 } else {
109                                     n *= pSize.height();
110                                 }
111                                 ix++;
112                                 current.append(QString("%1 ").arg(qRound(n)));
113                             } else {
114                                 current.append(QString("%1 ").arg(val));
115                             }
116                         }
117                     } else {
118                         current = defaultValue;
119                     }
120                 }
121                 //values << QPair<QString, QVariant>(QString("rect"),current);
122                 //values << QPair<QString, QVariant>(QString("_reset"),1);
123                 values << QPair<QString, QVariant>(m_keyParam,current);
124             } else {
125                 values << QPair<QString, QVariant>(m_keyParam,defaultValue);
126             }
127             auto *command = new AssetUpdateCommand(m_model, values);
128             pCore->pushUndo(command);
129             return;
130         }
131         QVector<QPair<QString, QVariant>> filterLastParams = m_model->getAllParameters();
132         ObjectId owner = m_model->getOwnerId();
133         const QString assetId = m_model->getAssetId();
134         QString binId;
135         int cid = -1;
136         int in = -1;
137         int out = -1;
138         if (owner.first == ObjectType::BinClip) {
139             binId = QString::number(owner.second);
140         } else if (owner.first == ObjectType::TimelineClip) {
141             cid = owner.second;
142             binId = pCore->getTimelineClipBinId(cid);
143             in = pCore->getItemIn(owner);
144             out = in + pCore->getItemDuration(owner);
145         } else if (owner.first == ObjectType::TimelineTrack || owner.first == ObjectType::Master) {
146             in = 0;
147             out = pCore->getItemDuration(owner);
148             binId = QStringLiteral("-1");
149         }
150         std::unordered_map<QString, QVariant> fParams;
151         std::unordered_map<QString, QString> fData;
152         for (const QVariant &jobElement : filterData) {
153             QStringList d = jobElement.toStringList();
154             if (d.size() == 2)
155             fData.insert({d.at(0), d.at(1)});
156         }
157         for (const auto &param : qAsConst(filterLastParams)) {
158             if (param.first != m_keyParam) {
159                 if (!isTracker || param.first != QLatin1String("rect")) {
160                     fParams.insert({param.first, param.second});
161                 }
162             } else if (isTracker) {
163                 QString initialRect = param.second.toString();
164                 if (initialRect.contains(QLatin1Char('='))) {
165                     initialRect = initialRect.section(QLatin1Char('='), 1);
166                 }
167                 if (initialRect.contains(QLatin1Char(';'))) {
168                     initialRect = initialRect.section(QLatin1Char(';'), 0, 0);
169                 }
170                 fParams.insert({QStringLiteral("rect"), initialRect});
171             }
172         }
173         for (const QString &fparam : filterAddedParams) {
174             if (fparam.contains(QLatin1Char('='))) {
175                 fParams.insert({fparam.section(QLatin1Char('='), 0, 0), fparam.section(QLatin1Char('='), 1)});
176             }
177         }
178         if (m_progress->value() > 0 && m_progress->value() < 100) {
179             // The task is in progress, abort it
180             pCore->taskManager.discardJobs(owner, AbstractTask::FILTERCLIPJOB);
181         } else {
182             FilterTask::start(owner, binId, m_model, assetId, in, out, assetId, fParams, fData, consumerParams, this);
183             if (m_label) {
184                 m_label->setVisible(false);
185             }
186             m_button->setEnabled(false);
187         }
188     });
189 }
190 
slotShowComment(bool show)191 void ButtonParamWidget::slotShowComment(bool show)
192 {
193     Q_UNUSED(show);
194     //if (!m_labelComment->text().isEmpty()) {
195     //    m_widgetComment->setVisible(show);
196     //}
197 }
198 
slotRefresh()199 void ButtonParamWidget::slotRefresh()
200 {
201     QVector<QPair<QString, QVariant>> filterParams = m_model->getAllParameters();
202     m_displayConditional = true;
203     for (const auto &param : qAsConst(filterParams)) {
204         if (param.first == m_keyParam && !param.second.isNull() && param.second.toString().contains(QLatin1Char(';'))) {
205             m_displayConditional = false;
206             break;
207         }
208     }
209     if (m_label) {
210         m_label->setVisible(m_displayConditional);
211     }
212     m_button->setEnabled(true);
213     // Check running job percentage
214     int progress = m_model->data(m_index, AssetParameterModel::FilterProgressRole).toInt();
215     if (progress > 0 && progress < 100) {
216         m_progress->setValue(progress);
217         if (!m_progress->isVisible()) {
218             m_button->setText(i18n("Abort processing"));
219             m_progress->setVisible(true);
220         }
221 
222     } else {
223         m_button->setText(m_displayConditional ? m_buttonName : m_alternatebuttonName);
224         m_progress->setValue(0);
225         m_progress->setVisible(false);
226     }
227     updateGeometry();
228 }
229 
getValue()230 bool ButtonParamWidget::getValue()
231 {
232     return true;
233 }
234 
235