File indexing completed on 2024-04-28 04:51:35
0001 /* 0002 SPDX-FileCopyrightText: 2022 Jean-Baptiste Mardelle <jb@kdenlive.org> 0003 0004 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "clipjobmanager.h" 0008 0009 #include "core.h" 0010 #include "effects/effectsrepository.hpp" 0011 #include "kdenlivesettings.h" 0012 0013 #include "kdenlive_debug.h" 0014 #include <KLocalizedString> 0015 #include <KMessageBox> 0016 #include <QButtonGroup> 0017 #include <QFontDatabase> 0018 #include <QUuid> 0019 0020 ClipJobManager::ClipJobManager(AbstractTask::JOBTYPE type, QWidget *parent) 0021 : QDialog(parent) 0022 { 0023 setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0024 setupUi(this); 0025 setWindowTitle(i18n("Manage Bin Clip Jobs")); 0026 connect(job_list, &QListWidget::currentRowChanged, this, &ClipJobManager::displayJob); 0027 loadJobs(); 0028 if (type != AbstractTask::NOJOBTYPE) { 0029 for (int i = 0; i < job_list->count(); i++) { 0030 QListWidgetItem *item = job_list->item(i); 0031 if (item && item->data(Qt::UserRole + 1).toInt() == (int)type) { 0032 job_list->setCurrentRow(i); 0033 break; 0034 } 0035 } 0036 } else { 0037 job_list->setCurrentRow(0); 0038 } 0039 0040 job_list->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); 0041 connect(button_add, &QToolButton::clicked, this, &ClipJobManager::addJob); 0042 connect(button_delete, &QToolButton::clicked, this, &ClipJobManager::deleteJob); 0043 0044 job_params->setToolTip(i18n("Arguments for the command line script")); 0045 job_params->setWhatsThis( 0046 xi18nc("@info:whatsthis", 0047 "<b>{%1}</b> will be replaced by the first parameter, <b>{%2}</b> by the second, , <b>{%3}</b> by the output file path.")); 0048 destination_pattern->setToolTip(i18n("File extension for the output file")); 0049 destination_pattern->setWhatsThis( 0050 xi18nc("@info:whatsthis", 0051 "The output file name will be the same as the source bin clip filename, with the modified extension. It will be appended at the end of the " 0052 "arguments or inserted in place of <b>{%3}</b> if found. If output filename already exists, a -0001 pattern will be appended.")); 0053 0054 param1_isfile->setToolTip(i18n("If selected, a file path will be requested on execution")); 0055 param1_islist->setToolTip(i18n("If selected, a dropdown list of values will be shown on execution")); 0056 param1_isframe->setToolTip( 0057 i18n("If selected, the selected clip's current frame will be extracted to a temporary file and the parameter value will be the image path")); 0058 param1_list->setToolTip(i18n("A newline separated list of possible values that will be offered on execution")); 0059 param1_list->setWhatsThis( 0060 xi18nc("@info:whatsthis", 0061 "When the parameter is set to <b>Request Option in List</b> the user will be asked to choose a value in this list when the job is started.")); 0062 0063 param2_isfile->setToolTip(i18n("If selected, a file path will be requested on execution")); 0064 param1_islist->setToolTip(i18n("If selected, a dropdown list of values will be shown on execution")); 0065 param2_list->setWhatsThis( 0066 xi18nc("@info:whatsthis", 0067 "When the parameter is set to <b>Request Option in List</b> the user will be asked to choose a value in this list when the job is started.")); 0068 0069 connect(job_list, &QListWidget::itemChanged, this, &ClipJobManager::updateName); 0070 0071 QButtonGroup *bg = new QButtonGroup(this); 0072 bg->setExclusive(false); 0073 bg->addButton(enable_video); 0074 bg->addButton(enable_audio); 0075 bg->addButton(enable_image); 0076 0077 QButtonGroup *param1Bg = new QButtonGroup(this); 0078 param1Bg->setExclusive(true); 0079 param1Bg->addButton(param1_isfile); 0080 param1Bg->addButton(param1_islist); 0081 param1Bg->addButton(param1_isframe); 0082 0083 // Mark preset as dirty if anything changes 0084 connect(url_binary, &KUrlRequester::textChanged, this, [this]() { 0085 checkScript(); 0086 setDirty(); 0087 }); 0088 connect(job_params, &QPlainTextEdit::textChanged, this, &ClipJobManager::setDirty); 0089 connect(destination_pattern, &QLineEdit::textChanged, this, &ClipJobManager::setDirty); 0090 connect(radio_replace, &QRadioButton::toggled, this, &ClipJobManager::setDirty); 0091 connect(combo_folder, &QComboBox::currentIndexChanged, this, &ClipJobManager::setDirty); 0092 connect(folder_name, &QLineEdit::textChanged, this, &ClipJobManager::setDirty); 0093 connect(param1_list, &QPlainTextEdit::textChanged, this, &ClipJobManager::setDirty); 0094 connect(param2_list, &QPlainTextEdit::textChanged, this, &ClipJobManager::setDirty); 0095 connect(taskDescription, &QPlainTextEdit::textChanged, this, &ClipJobManager::setDirty); 0096 connect(param1Bg, &QButtonGroup::buttonClicked, this, &ClipJobManager::setDirty); 0097 connect(param2_islist, &QAbstractButton::toggled, this, &ClipJobManager::setDirty); 0098 connect(param1_name, &QLineEdit::textChanged, this, &ClipJobManager::setDirty); 0099 connect(param2_name, &QLineEdit::textChanged, this, &ClipJobManager::setDirty); 0100 connect(bg, &QButtonGroup::idToggled, this, &ClipJobManager::setDirty); 0101 info_message->setVisible(false); 0102 checkScript(); 0103 connect(buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &ClipJobManager::validate); 0104 } 0105 0106 ClipJobManager::~ClipJobManager() {} 0107 0108 void ClipJobManager::setDirty() 0109 { 0110 m_dirty = job_list->currentItem()->data(Qt::UserRole).toString(); 0111 } 0112 0113 void ClipJobManager::validate() 0114 { 0115 // ensure changes to the current preset get saved 0116 displayJob(-1); 0117 writePresetsToConfig(); 0118 accept(); 0119 } 0120 0121 void ClipJobManager::loadJobs() 0122 { 0123 QSignalBlocker bk(job_list); 0124 job_list->clear(); 0125 // Add jobs 0126 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0127 KConfigGroup group(&conf, "Ids"); 0128 m_ids = group.entryMap(); 0129 QListWidgetItem *item; 0130 0131 // Add builtin jobs 0132 item = new QListWidgetItem(i18n("Stabilize"), job_list, QListWidgetItem::Type); 0133 item->setData(Qt::UserRole, QLatin1String("stabilize")); 0134 item->setData(Qt::UserRole + 1, AbstractTask::STABILIZEJOB); 0135 item = new QListWidgetItem(i18n("Duplicate Clip with Speed Change…"), job_list, QListWidgetItem::Type); 0136 item->setData(Qt::UserRole, QLatin1String("timewarp")); 0137 item->setData(Qt::UserRole + 1, AbstractTask::SPEEDJOB); 0138 0139 QMapIterator<QString, QString> k(m_ids); 0140 while (k.hasNext()) { 0141 k.next(); 0142 if (!k.value().isEmpty()) { 0143 item = new QListWidgetItem(k.value(), job_list, QListWidgetItem::UserType); 0144 item->setData(Qt::UserRole, k.key()); 0145 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); 0146 } 0147 } 0148 // Read all data 0149 KConfigGroup groupParams(&conf, "Parameters"); 0150 m_params = groupParams.entryMap(); 0151 KConfigGroup groupFolder(&conf, "FolderName"); 0152 m_folderNames = groupFolder.entryMap(); 0153 KConfigGroup groupUse(&conf, "FolderUse"); 0154 m_folderUse = groupUse.entryMap(); 0155 KConfigGroup groupOutput(&conf, "Output"); 0156 m_output = groupOutput.entryMap(); 0157 KConfigGroup groupBinary(&conf, "Binary"); 0158 m_binaries = groupBinary.entryMap(); 0159 KConfigGroup groupEnabled(&conf, "EnabledTypes"); 0160 m_enableType = groupEnabled.entryMap(); 0161 KConfigGroup param1Type(&conf, "Param1Type"); 0162 m_param1Type = param1Type.entryMap(); 0163 KConfigGroup param1List(&conf, "Param1List"); 0164 m_param1List = param1List.entryMap(); 0165 KConfigGroup param2Type(&conf, "Param2Type"); 0166 m_param2Type = param2Type.entryMap(); 0167 KConfigGroup param2List(&conf, "Param2List"); 0168 m_param2List = param2List.entryMap(); 0169 KConfigGroup param1Name(&conf, "Param1Name"); 0170 m_param1Name = param1Name.entryMap(); 0171 KConfigGroup param2Name(&conf, "Param2Name"); 0172 m_param2Name = param2Name.entryMap(); 0173 KConfigGroup descName(&conf, "Description"); 0174 m_description = descName.entryMap(); 0175 } 0176 0177 void ClipJobManager::displayJob(int row) 0178 { 0179 if (!m_dirty.isEmpty()) { 0180 saveCurrentPreset(); 0181 } 0182 if (row == -1) { 0183 param_box->setEnabled(false); 0184 return; 0185 } 0186 QListWidgetItem *item = job_list->item(row); 0187 QString jobId = item->data(Qt::UserRole).toString(); 0188 bool customJob = item->type() == QListWidgetItem::UserType; 0189 param_box->setEnabled(customJob); 0190 button_delete->setEnabled(customJob); 0191 if (customJob && !m_ids.contains(jobId)) { 0192 // This is a new job, set some default values 0193 url_binary->setUrl(QUrl::fromLocalFile(KdenliveSettings::ffmpegpath())); 0194 job_params->setPlainText(QStringLiteral("-i {source} -codec:a copy -codec:v copy {output}")); 0195 } else { 0196 url_binary->setText(m_binaries.value(jobId)); 0197 job_params->setPlainText(m_params.value(jobId)); 0198 } 0199 destination_pattern->setText(m_output.value(jobId)); 0200 folder_name->setText(m_folderNames.value(jobId)); 0201 folder_name->setText(m_folderNames.value(jobId)); 0202 if (m_folderUse.contains(jobId) || m_dirty == jobId) { 0203 folder_box->setEnabled(true); 0204 if (m_folderUse.value(jobId) == QLatin1String("replace")) { 0205 radio_replace->setChecked(true); 0206 } else if (m_folderUse.value(jobId) == QLatin1String("rootfolder")) { 0207 radio_folder->setChecked(true); 0208 combo_folder->setCurrentIndex(0); 0209 } else if (m_folderUse.value(jobId) == QLatin1String("subfolder")) { 0210 radio_folder->setChecked(true); 0211 combo_folder->setCurrentIndex(1); 0212 } else { 0213 folder_box->setEnabled(false); 0214 } 0215 } else { 0216 folder_box->setEnabled(false); 0217 } 0218 enable_video->setChecked(m_enableType.value(jobId).contains(QLatin1String("v"))); 0219 enable_audio->setChecked(m_enableType.value(jobId).contains(QLatin1String("a"))); 0220 enable_image->setChecked(m_enableType.value(jobId).contains(QLatin1String("i"))); 0221 0222 if (m_param1Type.value(jobId) == QLatin1String("list")) { 0223 param1_islist->setChecked(true); 0224 } else if (m_param1Type.value(jobId) == QLatin1String("frame")) { 0225 param1_isframe->setChecked(true); 0226 } else { 0227 param1_isfile->setChecked(true); 0228 } 0229 if (m_param2Type.value(jobId) == QLatin1String("list")) { 0230 param2_islist->setChecked(true); 0231 } else { 0232 param2_isfile->setChecked(true); 0233 } 0234 param1_name->setText(m_param1Name.value(jobId)); 0235 param2_name->setText(m_param2Name.value(jobId)); 0236 taskDescription->setPlainText(m_description.value(jobId)); 0237 0238 QStringList option1 = m_param1List.value(jobId).split(QLatin1String(" ")); 0239 param1_list->setPlainText(option1.join(QLatin1Char('\n'))); 0240 QStringList option2 = m_param2List.value(jobId).split(QLatin1String(" ")); 0241 param2_list->setPlainText(option2.join(QLatin1Char('\n'))); 0242 } 0243 0244 void ClipJobManager::checkScript() 0245 { 0246 if (url_binary->text().isEmpty() || !url_binary->isEnabled()) { 0247 script_message->setVisible(false); 0248 return; 0249 } 0250 QFileInfo info(url_binary->text()); 0251 if (!info.exists()) { 0252 script_message->setText(i18n("Missing executable")); 0253 script_message->setVisible(true); 0254 } else if (!info.isExecutable()) { 0255 script_message->setText(i18n("Your script or application %1 is not executable, change permissions", info.fileName())); 0256 script_message->setVisible(true); 0257 } else { 0258 script_message->setVisible(false); 0259 } 0260 } 0261 0262 QMap<QString, QString> ClipJobManager::getClipJobNames() 0263 { 0264 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0265 KConfigGroup group(&conf, "Ids"); 0266 QMap<QString, QString> ids = group.entryMap(); 0267 KConfigGroup group2(&conf, "EnabledTypes"); 0268 QMap<QString, QString> id2s = group2.entryMap(); 0269 // Append supported type after job key 0270 QMapIterator<QString, QString> i(ids); 0271 QMap<QString, QString> newIds; 0272 while (i.hasNext()) { 0273 i.next(); 0274 if (!i.value().isEmpty()) { 0275 newIds.insert(QString("%1;%2").arg(i.key(), id2s.value(i.key())), i.value()); 0276 } 0277 } 0278 // Add the 3 internal jobs 0279 if (EffectsRepository::get()->exists(QLatin1String("vidstab"))) { 0280 newIds.insert(QStringLiteral("stabilize;v"), i18n("Stabilize")); 0281 } 0282 newIds.insert(QStringLiteral("scenesplit;v"), i18n("Automatic Scene Split…")); 0283 if (KdenliveSettings::producerslist().contains(QLatin1String("timewarp"))) { 0284 newIds.insert(QStringLiteral("timewarp;av"), i18n("Duplicate Clip with Speed Change…")); 0285 } 0286 return newIds; 0287 } 0288 0289 std::pair<ClipJobManager::JobCompletionAction, QString> ClipJobManager::getJobAction(const QString &jobId) 0290 { 0291 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0292 KConfigGroup group(&conf, "FolderUse"); 0293 KConfigGroup nameGroup(&conf, "FolderName"); 0294 QString useValue = group.readEntry(jobId, QString()); 0295 if (useValue == QLatin1String("replace")) { 0296 return {JobCompletionAction::ReplaceOriginal, QString()}; 0297 } 0298 if (useValue == QLatin1String("rootfolder")) { 0299 return {JobCompletionAction::RootFolder, nameGroup.readEntry(jobId, QString())}; 0300 } 0301 if (useValue == QLatin1String("subfolder")) { 0302 return {JobCompletionAction::SubFolder, nameGroup.readEntry(jobId, QString())}; 0303 } 0304 return {JobCompletionAction::NoAction, nameGroup.readEntry(jobId, QString())}; 0305 } 0306 0307 QMap<QString, QString> ClipJobManager::getJobParameters(const QString &jobId) 0308 { 0309 QMap<QString, QString> result; 0310 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0311 KConfigGroup idGroup(&conf, "Ids"); 0312 result.insert(QLatin1String("description"), idGroup.readEntry(jobId, i18n("Job description"))); 0313 KConfigGroup group(&conf, "Binary"); 0314 result.insert(QLatin1String("binary"), group.readEntry(jobId, QString())); 0315 KConfigGroup paramGroup(&conf, "Parameters"); 0316 result.insert(QLatin1String("parameters"), paramGroup.readEntry(jobId, QString())); 0317 KConfigGroup outGroup(&conf, "Output"); 0318 result.insert(QLatin1String("output"), outGroup.readEntry(jobId, QString())); 0319 KConfigGroup p1Group(&conf, "Param1Type"); 0320 result.insert(QLatin1String("param1type"), p1Group.readEntry(jobId, QString())); 0321 KConfigGroup p2Group(&conf, "Param2Type"); 0322 result.insert(QLatin1String("param2type"), p2Group.readEntry(jobId, QString())); 0323 KConfigGroup p1List(&conf, "Param1List"); 0324 result.insert(QLatin1String("param1list"), p1List.readEntry(jobId, QString())); 0325 KConfigGroup p2List(&conf, "Param2List"); 0326 result.insert(QLatin1String("param2list"), p2List.readEntry(jobId, QString())); 0327 KConfigGroup p1Name(&conf, "Param1Name"); 0328 result.insert(QLatin1String("param1name"), p1Name.readEntry(jobId, QString())); 0329 KConfigGroup p2Name(&conf, "Param2Name"); 0330 result.insert(QLatin1String("param2name"), p2Name.readEntry(jobId, QString())); 0331 KConfigGroup descName(&conf, "Description"); 0332 result.insert(QLatin1String("details"), descName.readEntry(jobId, QString())); 0333 return result; 0334 } 0335 0336 void ClipJobManager::saveCurrentPreset() 0337 { 0338 m_folderNames.insert(m_dirty, folder_name->text().simplified()); 0339 if (radio_replace->isChecked()) { 0340 m_folderUse.insert(m_dirty, QStringLiteral("replace")); 0341 } else if (combo_folder->currentIndex() == 0) { 0342 m_folderUse.insert(m_dirty, QStringLiteral("rootfolder")); 0343 } else { 0344 m_folderUse.insert(m_dirty, QStringLiteral("subfolder")); 0345 } 0346 m_binaries.insert(m_dirty, url_binary->text().simplified()); 0347 m_params.insert(m_dirty, job_params->toPlainText().simplified()); 0348 m_output.insert(m_dirty, destination_pattern->text().simplified()); 0349 m_description.insert(m_dirty, taskDescription->toPlainText().simplified()); 0350 QString enabledTypes; 0351 if (enable_video->isChecked()) { 0352 enabledTypes.append(QLatin1String("v")); 0353 } 0354 if (enable_audio->isChecked()) { 0355 enabledTypes.append(QLatin1String("a")); 0356 } 0357 if (enable_image->isChecked()) { 0358 enabledTypes.append(QLatin1String("i")); 0359 } 0360 m_enableType.insert(m_dirty, enabledTypes); 0361 m_param1Type.insert(m_dirty, 0362 param1_islist->isChecked() ? QLatin1String("list") : (param1_isframe->isChecked() ? QLatin1String("frame") : QLatin1String("file"))); 0363 m_param2Type.insert(m_dirty, param2_islist->isChecked() ? QLatin1String("list") : QLatin1String("file")); 0364 QStringList option1 = param1_list->toPlainText().split(QLatin1Char('\n')); 0365 m_param1List.insert(m_dirty, option1.join(QLatin1String(" "))); 0366 QStringList option2 = param2_list->toPlainText().split(QLatin1Char('\n')); 0367 m_param2List.insert(m_dirty, option2.join(QLatin1String(" "))); 0368 m_param1Name.insert(m_dirty, param1_name->text()); 0369 m_param2Name.insert(m_dirty, param2_name->text()); 0370 m_description.insert(m_dirty, taskDescription->toPlainText()); 0371 m_dirty.clear(); 0372 } 0373 0374 void ClipJobManager::writeGroup(KConfig &conf, const QString &groupName, QMap<QString, QString> values) 0375 { 0376 KConfigGroup idGroup(&conf, groupName); 0377 QMapIterator<QString, QString> i(values); 0378 while (i.hasNext()) { 0379 i.next(); 0380 idGroup.writeEntry(i.key(), i.value()); 0381 } 0382 } 0383 0384 void ClipJobManager::writePresetsToConfig() 0385 { 0386 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0387 writeGroup(conf, QStringLiteral("Ids"), m_ids); 0388 writeGroup(conf, QStringLiteral("Binary"), m_binaries); 0389 writeGroup(conf, QStringLiteral("Parameters"), m_params); 0390 writeGroup(conf, QStringLiteral("Output"), m_output); 0391 writeGroup(conf, QStringLiteral("FolderName"), m_folderNames); 0392 writeGroup(conf, QStringLiteral("FolderUse"), m_folderUse); 0393 writeGroup(conf, QStringLiteral("EnabledTypes"), m_enableType); 0394 writeGroup(conf, QStringLiteral("Param1Type"), m_param1Type); 0395 writeGroup(conf, QStringLiteral("Param2Type"), m_param2Type); 0396 writeGroup(conf, QStringLiteral("Param1List"), m_param1List); 0397 writeGroup(conf, QStringLiteral("Param2List"), m_param2List); 0398 writeGroup(conf, QStringLiteral("Param1Name"), m_param1Name); 0399 writeGroup(conf, QStringLiteral("Param2Name"), m_param2Name); 0400 writeGroup(conf, QStringLiteral("Description"), m_description); 0401 } 0402 0403 void ClipJobManager::addJob() 0404 { 0405 const QString uuid = QUuid::createUuid().toString(); 0406 QString jobName = i18n("My Clip Job"); 0407 bool newName = false; 0408 int j = 1; 0409 while (newName == false) { 0410 int i = 0; 0411 for (; i < job_list->count(); i++) { 0412 QListWidgetItem *it = job_list->item(i); 0413 if (it->text() == jobName) { 0414 jobName = i18n("My Clip Job %1", j); 0415 j++; 0416 break; 0417 } 0418 } 0419 if (i == job_list->count()) { 0420 // All the list was parsed so this is a unique name 0421 newName = true; 0422 } 0423 } 0424 QListWidgetItem *item = new QListWidgetItem(jobName, job_list, QListWidgetItem::UserType); 0425 item->setData(Qt::UserRole, uuid); 0426 m_folderUse.insert(uuid, QStringLiteral("replace")); 0427 m_enableType.insert(uuid, QStringLiteral("v")); 0428 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); 0429 job_list->setCurrentItem(item); 0430 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0431 KConfigGroup idGroup(&conf, "Ids"); 0432 idGroup.writeEntry(uuid, item->text()); 0433 m_dirty = uuid; 0434 } 0435 0436 void ClipJobManager::deleteJob() 0437 { 0438 QListWidgetItem *item = job_list->currentItem(); 0439 if (item && item->type() == QListWidgetItem::UserType) { 0440 if (KMessageBox::warningContinueCancel(this, i18n("Permanently delete this Clip Job:\n%1 ?", item->text())) == KMessageBox::Continue) { 0441 const QString jobId = item->data(Qt::UserRole).toString(); 0442 KConfig conf(QStringLiteral("clipjobsettings.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0443 QStringList groupIds = {QStringLiteral("Ids"), QStringLiteral("Binary"), QStringLiteral("Parameters"), 0444 QStringLiteral("Output"), QStringLiteral("FolderName"), QStringLiteral("FolderUse")}; 0445 for (auto &gName : groupIds) { 0446 KConfigGroup group(&conf, gName); 0447 group.deleteEntry(jobId); 0448 } 0449 delete item; 0450 m_ids.remove(jobId); 0451 m_binaries.remove(jobId); 0452 m_params.remove(jobId); 0453 m_output.remove(jobId); 0454 m_folderNames.remove(jobId); 0455 m_folderUse.remove(jobId); 0456 m_enableType.remove(jobId); 0457 m_param1Type.remove(jobId); 0458 m_param1List.remove(jobId); 0459 m_param2Type.remove(jobId); 0460 m_param2List.remove(jobId); 0461 m_param1Name.remove(jobId); 0462 m_param2Name.remove(jobId); 0463 m_description.remove(jobId); 0464 m_dirty.clear(); 0465 job_list->setCurrentRow(0); 0466 } 0467 } 0468 } 0469 0470 void ClipJobManager::updateName(QListWidgetItem *item) 0471 { 0472 setDirty(); 0473 m_ids.insert(m_dirty, item->text()); 0474 }