File indexing completed on 2025-04-20 13:38:31
0001 /*************************************************************************** 0002 scriptplugin.cpp - description 0003 ------------------- 0004 begin : Fri Nov 9 2007 0005 copyright : (C) 2007 by Dominik Seichter 0006 email : domseichter@web.de 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "scriptplugin.h" 0019 0020 #include <kconfiggroup.h> 0021 #include <kiconloader.h> 0022 #include <kmessagebox.h> 0023 #include <KIO/StoredTransferJob> 0024 #include <KIO/StatJob> 0025 #include <KJobWidgets> 0026 #include <QTemporaryFile> 0027 0028 #include <QFile> 0029 #include <QMenu> 0030 #include <QPointer> 0031 #include <QTextStream> 0032 #include <QVariant> 0033 #include <QFileDialog> 0034 0035 #include <kjs/kjsinterpreter.h> 0036 0037 #include "ui_scriptplugindialog.h" 0038 #include "ui_scriptpluginwidget.h" 0039 #include "batchrenamer.h" 0040 #include "krenamefile.h" 0041 0042 const char *ScriptPlugin::s_pszFileDialogLocation = "kfiledialog://krenamejscript"; 0043 const char *ScriptPlugin::s_pszVarNameIndex = "krename_index"; 0044 const char *ScriptPlugin::s_pszVarNameUrl = "krename_url"; 0045 const char *ScriptPlugin::s_pszVarNameFilename = "krename_filename"; 0046 const char *ScriptPlugin::s_pszVarNameExtension = "krename_extension"; 0047 const char *ScriptPlugin::s_pszVarNameDirectory = "krename_directory"; 0048 0049 enum EVarType { 0050 eVarType_String = 0, 0051 eVarType_Int, 0052 eVarType_Double, 0053 eVarType_Bool 0054 }; 0055 0056 ScriptPlugin::ScriptPlugin(PluginLoader *loader) 0057 : QObject(), 0058 Plugin(loader), m_parent(nullptr) 0059 { 0060 m_name = i18n("JavaScript Plugin"); 0061 m_icon = "applications-development"; 0062 m_interpreter = new KJSInterpreter(); 0063 m_menu = new QMenu(); 0064 m_widget = new Ui::ScriptPluginWidget(); 0065 0066 this->addSupportedToken("js;.*"); 0067 0068 m_help.append("[js;4+5];;" + i18n("Insert a snippet of JavaScript code (4+5 in this case)")); 0069 0070 m_menu->addAction(i18n("Index of the current file"), this, SLOT(slotInsertIndex())); 0071 m_menu->addAction(i18n("URL of the current file"), this, SLOT(slotInsertUrl())); 0072 m_menu->addAction(i18n("Filename of the current file"), this, SLOT(slotInsertFilename())); 0073 m_menu->addAction(i18n("Extension of the current file"), this, SLOT(slotInsertExtension())); 0074 m_menu->addAction(i18n("Directory of the current file"), this, SLOT(slotInsertDirectory())); 0075 } 0076 0077 ScriptPlugin::~ScriptPlugin() 0078 { 0079 delete m_widget; 0080 delete m_menu; 0081 delete m_interpreter; 0082 } 0083 0084 QString ScriptPlugin::processFile(BatchRenamer *b, int index, 0085 const QString &filenameOrToken, EPluginType) 0086 { 0087 QString token(filenameOrToken); 0088 QString script; 0089 QString definitions = m_widget->textCode->toPlainText(); 0090 0091 if (token.contains(";")) { 0092 script = token.section(';', 1); // all sections from 1 to the last 0093 token = token.section(';', 0, 0).toLower(); 0094 } else { 0095 token = token.toLower(); 0096 } 0097 0098 if (token == "js") { 0099 // Setup interpreter 0100 const KRenameFile &file = b->files()->at(index); 0101 initKRenameVars(file, index); 0102 0103 // Make sure definitions are executed first 0104 script = definitions + '\n' + script; 0105 0106 KJSResult result = m_interpreter->evaluate(script, nullptr); 0107 if (result.isException()) { 0108 qDebug("JavaScript Error: %s", result.errorMessage().toUtf8().data()); 0109 return QString(); 0110 } 0111 0112 return result.value().toString(m_interpreter->globalContext()); 0113 } 0114 0115 return QString(); 0116 } 0117 0118 const QPixmap ScriptPlugin::icon() const 0119 { 0120 return KIconLoader::global()->loadIcon(m_icon, KIconLoader::NoGroup, KIconLoader::SizeSmall); 0121 } 0122 0123 void ScriptPlugin::createUI(QWidget *parent) const 0124 { 0125 QStringList labels; 0126 labels << i18n("Variable Name"); 0127 labels << i18n("Initial Value"); 0128 0129 const_cast<ScriptPlugin *>(this)->m_parent = parent; 0130 m_widget->setupUi(parent); 0131 m_widget->listVariables->setColumnCount(2); 0132 m_widget->listVariables->setHeaderLabels(labels); 0133 0134 connect(m_widget->listVariables, &QTreeWidget::itemSelectionChanged, 0135 this, &ScriptPlugin::slotEnableControls); 0136 connect(m_widget->buttonAdd, &QPushButton::clicked, 0137 this, &ScriptPlugin::slotAdd); 0138 connect(m_widget->buttonRemove, &QPushButton::clicked, 0139 this, &ScriptPlugin::slotRemove); 0140 connect(m_widget->buttonLoad, &QPushButton::clicked, 0141 this, &ScriptPlugin::slotLoad); 0142 connect(m_widget->buttonSave, &QPushButton::clicked, 0143 this, &ScriptPlugin::slotSave); 0144 connect(m_widget->textCode, &QTextEdit::textChanged, 0145 this, &ScriptPlugin::slotEnableControls); 0146 0147 const_cast<ScriptPlugin *>(this)->slotEnableControls(); 0148 0149 QPixmap openIcon = KIconLoader::global()->loadIcon("document-open", KIconLoader::NoGroup, KIconLoader::SizeSmall); 0150 QPixmap saveIcon = KIconLoader::global()->loadIcon("document-save-as", KIconLoader::NoGroup, KIconLoader::SizeSmall); 0151 QPixmap removeIcon = KIconLoader::global()->loadIcon("list-remove", KIconLoader::NoGroup, KIconLoader::SizeSmall); 0152 QPixmap addIcon = KIconLoader::global()->loadIcon("list-add", KIconLoader::NoGroup, KIconLoader::SizeSmall); 0153 0154 m_widget->buttonLoad->setIcon(openIcon); 0155 m_widget->buttonSave->setIcon(saveIcon); 0156 m_widget->buttonAdd->setIcon(addIcon); 0157 m_widget->buttonRemove->setIcon(removeIcon); 0158 0159 m_widget->buttonInsert->setMenu(m_menu); 0160 } 0161 0162 void ScriptPlugin::initKRenameVars(const KRenameFile &file, int index) 0163 { 0164 // KRename definitions 0165 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0166 ScriptPlugin::s_pszVarNameIndex, 0167 index); 0168 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0169 ScriptPlugin::s_pszVarNameUrl, 0170 file.srcUrl().url()); 0171 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0172 ScriptPlugin::s_pszVarNameFilename, 0173 file.srcFilename()); 0174 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0175 ScriptPlugin::s_pszVarNameExtension, 0176 file.srcExtension()); 0177 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0178 ScriptPlugin::s_pszVarNameDirectory, 0179 file.srcDirectory()); 0180 0181 // User definitions, set them only on first file 0182 if (index == 0) { 0183 for (int i = 0; i < m_widget->listVariables->topLevelItemCount(); i++) { 0184 // TODO, we have to know the type of the variable! 0185 QTreeWidgetItem *item = m_widget->listVariables->topLevelItem(i); 0186 if (item) { 0187 EVarType eVarType = static_cast<EVarType>(item->data(1, Qt::UserRole).toInt()); 0188 const QString &name = item->text(0); 0189 const QString &value = item->text(1); 0190 switch (eVarType) { 0191 default: 0192 case eVarType_String: 0193 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0194 name, value.toUtf8().data()); 0195 break; 0196 case eVarType_Int: 0197 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0198 name, value.toInt()); 0199 break; 0200 case eVarType_Double: 0201 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0202 name, value.toDouble()); 0203 break; 0204 case eVarType_Bool: 0205 m_interpreter->globalObject().setProperty(m_interpreter->globalContext(), 0206 name, 0207 (value.toLower() == "true" ? true : false)); 0208 break; 0209 0210 } 0211 } 0212 } 0213 } 0214 } 0215 0216 void ScriptPlugin::insertVariable(const char *name) 0217 { 0218 m_widget->textCode->insertPlainText(QString(name)); 0219 } 0220 0221 void ScriptPlugin::slotEnableControls() 0222 { 0223 bool bEnable = (m_widget->listVariables->selectedItems().count() != 0); 0224 m_widget->buttonRemove->setEnabled(bEnable); 0225 0226 bEnable = !m_widget->textCode->toPlainText().isEmpty(); 0227 m_widget->buttonSave->setEnabled(bEnable); 0228 } 0229 0230 void ScriptPlugin::slotAdd() 0231 { 0232 QPointer<QDialog> dialog = new QDialog(); 0233 Ui::ScriptPluginDialog dlg; 0234 0235 QStringList types; 0236 0237 types << i18n("String"); 0238 types << i18n("Int"); 0239 types << i18n("Double"); 0240 types << i18n("Boolean"); 0241 0242 dlg.setupUi(dialog); 0243 dlg.comboType->addItems(types); 0244 0245 if (dialog->exec() == QDialog::Accepted) { 0246 QString name = dlg.lineName->text(); 0247 QString value = dlg.lineValue->text(); 0248 0249 // Build a Java script statement 0250 QString script = name + " = " + value + ';'; 0251 0252 KJSInterpreter interpreter; 0253 KJSResult result = m_interpreter->evaluate(script, nullptr); 0254 if (result.isException()) { 0255 KMessageBox::error(m_parent, 0256 i18n("A JavaScript error has occurred: ") + 0257 result.errorMessage(), this->name()); 0258 } else { 0259 QTreeWidgetItem *item = new QTreeWidgetItem(); 0260 item->setText(0, name); 0261 item->setText(1, value); 0262 item->setData(1, Qt::UserRole, QVariant(dlg.comboType->currentIndex())); 0263 0264 m_widget->listVariables->addTopLevelItem(item); 0265 } 0266 } 0267 delete dialog; 0268 } 0269 0270 void ScriptPlugin::slotRemove() 0271 { 0272 QTreeWidgetItem *item = m_widget->listVariables->currentItem(); 0273 if (item) { 0274 m_widget->listVariables->invisibleRootItem()->removeChild(item); 0275 delete item; 0276 } 0277 } 0278 0279 void ScriptPlugin::slotLoad() 0280 { 0281 if (!m_widget->textCode->toPlainText().isEmpty() && 0282 KMessageBox::questionYesNo(m_parent, 0283 i18n("All currently entered definitions will be lost. Do you want to continue?"), {}, 0284 KStandardGuiItem::cont(), 0285 KStandardGuiItem::cancel()) 0286 == KMessageBox::No) { 0287 return; 0288 } 0289 0290 QUrl url = QFileDialog::getOpenFileUrl(m_parent, i18n("Select file"), 0291 QUrl(ScriptPlugin::s_pszFileDialogLocation)); 0292 0293 if (!url.isEmpty()) { 0294 // Also support remote files 0295 KIO::StoredTransferJob *job = KIO::storedGet(url); 0296 KJobWidgets::setWindow(job, m_parent); 0297 if (job->exec()) { 0298 m_widget->textCode->setPlainText(QString::fromLocal8Bit(job->data())); 0299 } else { 0300 KMessageBox::error(m_parent, job->errorString()); 0301 } 0302 } 0303 0304 slotEnableControls(); 0305 } 0306 0307 void ScriptPlugin::slotSave() 0308 { 0309 QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18n("Select file"), 0310 QUrl(ScriptPlugin::s_pszFileDialogLocation)); 0311 0312 if (!url.isEmpty()) { 0313 KIO::StatJob *statJob = KIO::stat(url, KIO::StatJob::DestinationSide, 0); 0314 statJob->exec(); 0315 if (statJob->error() != KIO::ERR_DOES_NOT_EXIST) { 0316 int m = KMessageBox::warningYesNo(m_parent, i18n("The file %1 already exists. " 0317 "Do you want to overwrite it?", url.toDisplayString(QUrl::PreferLocalFile)), {}, 0318 KStandardGuiItem::overwrite(), 0319 KStandardGuiItem::cancel()); 0320 0321 if (m == KMessageBox::No) { 0322 return; 0323 } 0324 } 0325 0326 if (url.isLocalFile()) { 0327 QFile file(url.path()); 0328 if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0329 QTextStream out(&file); 0330 out << m_widget->textCode->toPlainText(); 0331 out.flush(); 0332 file.close(); 0333 } else { 0334 KMessageBox::error(m_parent, i18n("Unable to open %1 for writing.", url.path())); 0335 } 0336 } else { 0337 KIO::StoredTransferJob *job = KIO::storedPut(m_widget->textCode->toPlainText().toLocal8Bit(), url, -1); 0338 KJobWidgets::setWindow(job, m_parent); 0339 job->exec(); 0340 if (job->error()) { 0341 KMessageBox::error(m_parent, job->errorString()); 0342 } 0343 } 0344 } 0345 0346 slotEnableControls(); 0347 } 0348 0349 void ScriptPlugin::slotTest() 0350 { 0351 } 0352 0353 void ScriptPlugin::slotInsertIndex() 0354 { 0355 this->insertVariable(ScriptPlugin::s_pszVarNameIndex); 0356 } 0357 0358 void ScriptPlugin::slotInsertUrl() 0359 { 0360 this->insertVariable(ScriptPlugin::s_pszVarNameUrl); 0361 } 0362 0363 void ScriptPlugin::slotInsertFilename() 0364 { 0365 this->insertVariable(ScriptPlugin::s_pszVarNameFilename); 0366 } 0367 0368 void ScriptPlugin::slotInsertExtension() 0369 { 0370 this->insertVariable(ScriptPlugin::s_pszVarNameExtension); 0371 } 0372 0373 void ScriptPlugin::slotInsertDirectory() 0374 { 0375 this->insertVariable(ScriptPlugin::s_pszVarNameDirectory); 0376 } 0377 0378 void ScriptPlugin::loadConfig(KConfigGroup &group) 0379 { 0380 QStringList variableNames; 0381 QStringList variableValues; 0382 QVariantList variableTypes; 0383 0384 variableNames = group.readEntry("JavaScriptVariableNames", variableNames); 0385 variableValues = group.readEntry("JavaScriptVariableValues", variableValues); 0386 variableTypes = group.readEntry("JavaScriptVariableTypes", variableTypes); 0387 0388 int min = qMin(variableNames.count(), variableValues.count()); 0389 min = qMin(min, variableTypes.count()); 0390 0391 for (int i = 0; i < min; i++) { 0392 QTreeWidgetItem *item = new QTreeWidgetItem(); 0393 item->setText(0, variableNames[i]); 0394 item->setText(1, variableValues[i]); 0395 item->setData(1, Qt::UserRole, variableTypes[i]); 0396 0397 m_widget->listVariables->addTopLevelItem(item); 0398 } 0399 0400 m_widget->textCode->setPlainText(group.readEntry("JavaScriptDefinitions", QString())); 0401 } 0402 0403 void ScriptPlugin::saveConfig(KConfigGroup &group) const 0404 { 0405 QStringList variableNames; 0406 QStringList variableValues; 0407 QVariantList variableTypes; 0408 0409 for (int i = 0; i < m_widget->listVariables->topLevelItemCount(); i++) { 0410 QTreeWidgetItem *item = m_widget->listVariables->topLevelItem(i); 0411 if (item) { 0412 variableNames << item->text(0); 0413 variableValues << item->text(1); 0414 variableTypes << item->data(1, Qt::UserRole); 0415 } 0416 } 0417 0418 group.writeEntry("JavaScriptVariableNames", variableNames); 0419 group.writeEntry("JavaScriptVariableValues", variableValues); 0420 group.writeEntry("JavaScriptVariableTypes", variableTypes); 0421 group.writeEntry("JavaScriptDefinitions", m_widget->textCode->toPlainText()); 0422 } 0423