From 50ece2748a89791879ecf15cffee2faa4655fd66 Mon Sep 17 00:00:00 2001
From: ale rimoldi <ale@graphicslab.org>
Date: Thu, 14 Nov 2024 10:45:20 +0100
Subject: add own scripts in a script submenu


diff --git a/scribus/menumanager.cpp b/scribus/menumanager.cpp
index d5df098a0..35f89d3cf 100644
--- a/scribus/menumanager.cpp
+++ b/scribus/menumanager.cpp
@@ -220,6 +220,28 @@ void MenuManager::addMenuItemStringsToRememberedMenu(const QString &menuName, co
 			addMenuItemStringsToMenu(menuName, rememberedMenus.value(menuName), menuActions);
 }
 
+void MenuManager::hideRemberedMenu(const QString& menuName)
+{
+	if (!rememberedMenus.contains(menuName))
+		return;
+	if (rememberedMenus.value(menuName) == nullptr)
+		return;
+
+	auto menu = rememberedMenus.value(menuName);
+	menu->menuAction()->setVisible(false);
+}
+
+void MenuManager::showRemberedMenu(const QString& menuName)
+{
+	if (!rememberedMenus.contains(menuName))
+		return;
+	if (rememberedMenus.value(menuName) == nullptr)
+		return;
+
+	auto menu = rememberedMenus.value(menuName);
+	menu->menuAction()->setVisible(true);
+}
+
 void MenuManager::clearMenuStrings(const QString &menuName)
 {
 	QMenu* menu = rememberedMenus.value(menuName, nullptr);
diff --git a/scribus/menumanager.h b/scribus/menumanager.h
index eee3a8e37..2bdd08d3f 100644
--- a/scribus/menumanager.h
+++ b/scribus/menumanager.h
@@ -67,6 +67,9 @@ class SCRIBUS_API MenuManager : public QObject
 		void addMenuItemStringAfter(const QString &s, const QString &after, const QString &parent);
 		void addMenuItemStringsToMenu(const QString &menuName, QMenu *menuToAddTo, const QMap<QString, QPointer<ScrAction> > &menuActions);
 		void addMenuItemStringsToRememberedMenu(const QString &menuName, const QMap<QString, QPointer<ScrAction> > &menuActions);
+		void hideRemberedMenu(const QString& menuName);
+		void showRemberedMenu(const QString& menuName);
+
 		void addMenuItemStringsToMenuBar(const QString &menuName, const QMap<QString, QPointer<ScrAction> > &menuActions);
 		void clearMenuStrings(const QString &menuName);
 		void dumpMenuStrings();
diff --git a/scribus/plugins/scriptplugin/CMakeLists.txt b/scribus/plugins/scriptplugin/CMakeLists.txt
index ef2c21758..0276c0b12 100644
--- a/scribus/plugins/scriptplugin/CMakeLists.txt
+++ b/scribus/plugins/scriptplugin/CMakeLists.txt
@@ -37,6 +37,7 @@ set(SCRIPTER_PLUGIN_SOURCES
 	pyesstring.cpp
 	runscriptdialog.cpp
 	scriptercore.cpp
+	scriptpaths.cpp
 	scriptplugin.cpp
 	svgimport.cpp
 )
diff --git a/scribus/plugins/scriptplugin/prefs_scripter.cpp b/scribus/plugins/scriptplugin/prefs_scripter.cpp
index 2d3d9f5d8..5e5ed340e 100644
--- a/scribus/plugins/scriptplugin/prefs_scripter.cpp
+++ b/scribus/plugins/scriptplugin/prefs_scripter.cpp
@@ -36,6 +36,7 @@ Prefs_Scripter::Prefs_Scripter(QWidget* parent)
 	// The startup script box should be disabled  if ext scripts are off
 	startupScriptEdit->setEnabled(extensionScriptsChk->isChecked());
 	startupScriptEdit->setText(scripterCore->startupScript());
+	scriptPathsListWidget->addItems(scripterCore->scriptPaths.get());
 	// signals and slots connections
 	connect(extensionScriptsChk, SIGNAL(toggled(bool)), startupScriptEdit, SLOT(setEnabled(bool)));
 	// colors
@@ -48,6 +49,15 @@ Prefs_Scripter::Prefs_Scripter(QWidget* parent)
 	connect(numberButton, SIGNAL(clicked()), this, SLOT(setColor()));
 	connect(extensionScriptsChk, SIGNAL(toggled(bool)), startupScriptChangeButton, SLOT(setEnabled(bool)));
 	connect(startupScriptChangeButton, SIGNAL(clicked()), this, SLOT(changeStartupScript()));
+
+	changePathButton->setEnabled(false);
+	removePathButton->setEnabled(false);
+	connect(scriptPathsListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPath(QListWidgetItem*)));
+	connect(addPathButton, SIGNAL(clicked()), this, SLOT(addPath()));
+	connect(changePathButton, SIGNAL(clicked()), this, SLOT(changePath()));
+	connect(removePathButton, SIGNAL(clicked()), this, SLOT(removePath()));
+
+
 }
 
 Prefs_Scripter::~Prefs_Scripter() = default;
@@ -81,6 +91,17 @@ void Prefs_Scripter::apply()
 		prefs->set("syntaxstring", stringColor.name());
 		prefs->set("syntaxtext", textColor.name());
 
+		if (pathsChanged)
+		{
+			scripterCore->scriptPaths.clear();
+			for (int i = 0; i < scriptPathsListWidget->count(); i++) {
+				scripterCore->scriptPaths.append(scriptPathsListWidget->item(i)->text());
+			}
+			scripterCore->scriptPaths.buildMenu();
+		}
+
+		scripterCore->scriptPaths.saveToPrefs();
+
 		emit prefsChanged();
 	}
 }
@@ -161,3 +182,74 @@ void Prefs_Scripter::changeStartupScript()
 		startupScriptEdit->setText(s);
 }
 
+void Prefs_Scripter::selectPath(QListWidgetItem *c)
+{
+	changePathButton->setEnabled(true);
+	removePathButton->setEnabled(true);
+}
+
+void Prefs_Scripter::addPath()
+{
+	QString s = QFileDialog::getExistingDirectory(this, tr("Choose a Directory"), latestPath);
+	if (s.isEmpty())
+		return;
+
+	if (s.endsWith("/"))
+	{
+		s.chop(1);
+	}
+	s = QDir::toNativeSeparators(s);
+	if (scriptPathsListWidget->findItems(s, Qt::MatchExactly).count() != 0)
+		return;
+
+	scriptPathsListWidget->addItem(s);
+
+	scriptPathsListWidget->setCurrentRow(scriptPathsListWidget->count() - 1);
+	changePathButton->setEnabled(true);
+	removePathButton->setEnabled(true);
+	latestPath = s;
+	pathsChanged = true;
+}
+
+void Prefs_Scripter::changePath()
+{
+	QString s = QFileDialog::getExistingDirectory(this, tr("Choose a Directory"), latestPath);
+	if (s.isEmpty())
+		return;
+
+	if (s.endsWith("/"))
+	{
+		s.chop(1);
+	}
+	s = QDir::toNativeSeparators(s);
+	// if the new path is already in the list, just remove the old path
+	if (scriptPathsListWidget->findItems(s, Qt::MatchExactly).count() != 0)
+	{
+		removePath();
+		return;
+	}
+
+	scriptPathsListWidget->currentItem()->setText(s);
+
+	latestPath = s;
+	pathsChanged = true;
+}
+
+void Prefs_Scripter::removePath()
+{
+	const int i = scriptPathsListWidget->currentRow();
+	if (scriptPathsListWidget->count() == 1)
+	{
+		scriptPathsListWidget->clear();
+	}
+	else
+	{
+		delete scriptPathsListWidget->takeItem(i);
+	}
+	if (scriptPathsListWidget->count() == 0)
+	{
+		changePathButton->setEnabled(false);
+		removePathButton->setEnabled(false);
+	}
+	pathsChanged = true;
+}
diff --git a/scribus/plugins/scriptplugin/prefs_scripter.h b/scribus/plugins/scriptplugin/prefs_scripter.h
index 46a8dffba..29bfbc76b 100644
--- a/scribus/plugins/scriptplugin/prefs_scripter.h
+++ b/scribus/plugins/scriptplugin/prefs_scripter.h
@@ -28,6 +28,11 @@ class Prefs_Scripter : public Prefs_Pane, Ui::Prefs_Scripter
 		//! \brief Apply changes to prefs. Auto connected.
 		void apply() override;
 
+		void selectPath(QListWidgetItem *c);
+		void addPath();
+		void changePath();
+		void removePath();
+
 	protected:
 		void setupSyntaxColors();
 		QColor textColor;
@@ -38,6 +43,9 @@ class Prefs_Scripter : public Prefs_Pane, Ui::Prefs_Scripter
 		QColor stringColor;
 		QColor numberColor;
 
+		QString latestPath;
+		bool pathsChanged = false;
+
 	protected slots:
 		/*! \brief All requests for color change are handled here.
 		\author Petr Vanek
diff --git a/scribus/plugins/scriptplugin/prefs_scripterbase.ui b/scribus/plugins/scriptplugin/prefs_scripterbase.ui
index d077c0c12..0f07f60b1 100644
--- a/scribus/plugins/scriptplugin/prefs_scripterbase.ui
+++ b/scribus/plugins/scriptplugin/prefs_scripterbase.ui
@@ -40,46 +40,109 @@
    <item>
     <widget class="Line" name="line">
      <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QScrollArea" name="scrollArea">
-     <property name="frameShape">
-      <enum>QFrame::NoFrame</enum>
-     </property>
-     <property name="frameShadow">
-      <enum>QFrame::Plain</enum>
-     </property>
-     <property name="widgetResizable">
-      <bool>true</bool>
-     </property>
-     <widget class="QWidget" name="scrollAreaWidgetContents">
-      <property name="geometry">
-       <rect>
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QScrollArea" name="scrollArea">
+     <property name="frameShape">
+      <enum>QFrame::NoFrame</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="widgetResizable">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="scrollAreaWidgetContents">
+      <property name="geometry">
+       <rect>
         <x>0</x>
-        <y>0</y>
-        <width>742</width>
-        <height>538</height>
-       </rect>
-      </property>
-      <layout class="QVBoxLayout" name="verticalLayout">
-       <property name="leftMargin">
-        <number>0</number>
-       </property>
-       <property name="topMargin">
-        <number>0</number>
-       </property>
-       <property name="rightMargin">
-        <number>0</number>
-       </property>
-       <item>
-        <widget class="QLabel" name="extensionsTitleLabel">
-         <property name="font">
-          <font>
-           <weight>75</weight>
-           <bold>true</bold>
+		<y>0</y>
+        <width>678</width>
+        <height>570</height>
+       </rect>
+      </property>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QLabel" name="ownScripts">
+         <property name="font">
+          <font>
+           <bold>true</bold>
+          </font>
+         </property>
+         <property name="text">
+          <string>Own Scripts</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="Line" name="line_4">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <item>
+          <widget class="QListWidget" name="scriptPathsListWidget"/>
+         </item>
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_2">
+           <item>
+            <widget class="QPushButton" name="changePathButton">
+             <property name="text">
+              <string>C&amp;hange</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="addPathButton">
+             <property name="text">
+              <string>A&amp;dd</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="removePathButton">
+             <property name="text">
+              <string>&amp;Remove</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_3">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QLabel" name="extensionsTitleLabel">
+         <property name="font">
+          <font>
+           <bold>true</bold>
           </font>
          </property>
          <property name="text">
diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp
index 103038c27..96f5c701d 100644
--- a/scribus/plugins/scriptplugin/scriptercore.cpp
+++ b/scribus/plugins/scriptplugin/scriptercore.cpp
@@ -70,6 +70,8 @@ ScripterCore::ScripterCore(QWidget* parent)
 
 	QObject::connect(ScQApp, SIGNAL(appStarted()) , this, SLOT(runStartupScript()) );
 	QObject::connect(ScQApp, SIGNAL(appStarted()) , this, SLOT(slotRunPythonScript()) );
+
+	QObject::connect(&scriptPaths, &ScriptPaths::runScriptFile, this, &ScripterCore::runScriptFile);
 }
 
 ScripterCore::~ScripterCore()
@@ -82,6 +84,7 @@ void ScripterCore::addToMainWindowMenu(ScribusMainWindow *mw)
 {
 	m_menuMgr = mw->scrMenuMgr;
 	m_menuMgr->createMenu("Scripter", QObject::tr("&Script"));
+	scriptPaths.attachToMenu(m_menuMgr);
 	m_menuMgr->createMenu("ScribusScripts", QObject::tr("&Scribus Scripts"), "Scripter");
 	m_menuMgr->addMenuItemString("ScribusScripts", "Scripter");
 	m_menuMgr->addMenuItemString("scripterExecuteScript", "Scripter");
@@ -98,6 +101,7 @@ void ScripterCore::addToMainWindowMenu(ScribusMainWindow *mw)
 	m_menuMgr->addMenuItemStringsToMenuBar("Scripter", m_scripterActions);
 	m_recentScripts = m_savedRecentScripts;
 	rebuildRecentScriptsMenu();
+	scriptPaths.buildMenu();
 }
 
 void ScripterCore::enableMainWindowMenu()
@@ -177,6 +181,15 @@ void ScripterCore::finishScriptRun()
 	mainWin->HaveNewDoc();
 }
 
+/**
+ * setup the environment for running the script, run the script and clean up the environment
+ */
+void ScripterCore::runScriptFile(const QString& path)
+{
+	slotRunScriptFile(path);
+	finishScriptRun();
+}
+
 void ScripterCore::runScriptDialog()
 {
 	RunScriptDialog dia( ScCore->primaryMainWindow(), m_enableExtPython );
diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h
index ceb4e68b2..15475b293 100644
--- a/scribus/plugins/scriptplugin/scriptercore.h
+++ b/scribus/plugins/scriptplugin/scriptercore.h
@@ -11,6 +11,7 @@ for which a new license (GPL+exception) is in place.
 
 #include "qmap.h"
 #include "qpointer.h"
+#include "scriptpaths.h"
 
 class ScrAction;
 class ScribusMainWindow;
@@ -34,10 +35,13 @@ public:
 	/** @brief String representation of line of code to be passed to the Python interactive interpreter */
 	QString inValue;
 
+	ScriptPaths scriptPaths;
+
 public slots:
 	void runScriptDialog();
 	void StdScript(const QString& baseFilename);
 	void RecentScript(const QString& fn);
+	void runScriptFile(const QString& path);
 	void slotRunScriptFile(const QString& fileName, bool inMainInterpreter = false);
 	void slotRunScriptFile(const QString& fileName, QStringList arguments, bool inMainInterpreter = false);
 	void slotRunPythonScript(); // needed for running python script from CLI
@@ -57,6 +61,7 @@ public slots:
 	void runStartupScript();
 	void languageChange();
 
+	// Preferences
 	const QString & startupScript() const;
 	bool extensionsEnabled() const;
 	void setStartupScript(const QString& newScript);
diff --git a/scribus/plugins/scriptplugin/scriptpaths.cpp b/scribus/plugins/scriptplugin/scriptpaths.cpp
new file mode 100644
index 000000000..428c10b8e
--- /dev/null
+++ b/scribus/plugins/scriptplugin/scriptpaths.cpp
@@ -0,0 +1,174 @@
+#include "scriptpaths.h"
+#include "prefsmanager.h"
+#include "prefsfile.h"
+#include "prefscontext.h"
+#include "prefstable.h"
+
+#include <QWidget>
+#include "menumanager.h"
+
+ScriptPaths::ScriptPaths()
+{
+}
+
+void ScriptPaths::saveToPrefs() const
+{
+	paths.saveToPrefs();
+}
+
+/**
+ * Add a Scripts sub menu to the Scripts navigation (if there is any user script).
+ * It will be hidden if buildMenu() detects that no scripts have been found.
+ */
+void ScriptPaths::attachToMenu(MenuManager* menuManager)
+{
+	menuManager->createMenu("OwnScripts", QObject::tr("&Scripts"), "Scripter", false, true);
+	menuManager->addMenuItemString("OwnScripts", "Scripter");
+	this->menuManager = menuManager;
+}
+
+void ScriptPaths::buildMenu()
+{
+	if (menuManager == nullptr)
+		return;
+
+	updateScriptsList();
+
+	if (empty())
+	{
+		menuManager->hideRemberedMenu("OwnScripts");
+		return;
+	}
+
+	menuManager->showRemberedMenu("OwnScripts");
+
+	scriptsActions.clear();
+	menuManager->clearMenuStrings("OwnScripts");
+
+	for (const auto& scriptInfo: scriptsList)
+	{
+		// TODO: strippedName sould be unique for the whole menu (repo index + script name?)... we could use the full path...
+		auto scriptName = scriptInfo.name;
+		scriptName.replace('_', ' ');
+		scriptName = scriptName.first(1).toUpper() + scriptName.mid(1);
+		scriptsActions.insert(scriptName, new ScrAction(ScrAction::OwnScript, scriptName, QKeySequence(), this, scriptInfo.path));
+		connect(
+		    scriptsActions[scriptName], qOverload<QString>(&ScrAction::triggeredData),
+			this, &ScriptPaths::runScript
+		);
+		menuManager->addMenuItemString(scriptName, "OwnScripts");
+	}
+
+	menuManager->addMenuItemStringsToRememberedMenu("OwnScripts", scriptsActions);
+}
+
+/**
+ * Detect the scripts in the paths defined in the Preferences > Scripter.
+ *
+ * The following scripts are detected:
+ *
+ * - The *.py files at the root of the repository.
+ * - The main.py files in the directories at the root of the repository.
+ * - The .py files with the same name as their directory (at root level):
+ *   the-script/the-script.py
+ *
+ *   TODO: we might prefer using a QList<QPair<QString, QString>> with the name to be shown and the absolute path to the script.
+ */
+void ScriptPaths::updateScriptsList()
+{
+	scriptsList.clear();
+	// TODO: how to manage duplicate file names? (in different repositories)
+	for (const auto& path: paths.paths) {
+		{
+			QDir scriptDirectory(QDir::toNativeSeparators(path), "*.py", QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
+			for (const auto& file: scriptDirectory.entryList())
+			{
+				scriptsList.append(ScriptPathsInfo(QDir(path).filePath(file), QFileInfo{file}.baseName()));
+			}
+		}
+		{
+			QDir scriptDirectory(QDir::toNativeSeparators(path), "*", QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoSymLinks);
+			for (const auto& directory: scriptDirectory.entryList())
+			{
+				{
+					auto script = QFileInfo(QDir(path).filePath(directory + "/main.py"));
+					if (script.exists() || script.isFile())
+					{
+						scriptsList.append(ScriptPathsInfo(script.absoluteFilePath(), directory));
+						continue;
+					}
+				}
+				{
+					auto script = QFileInfo(QDir(path).filePath(directory + "/" + directory + ".py"));
+					if (script.exists() || script.isFile())
+					{
+						scriptsList.append(ScriptPathsInfo(script.absoluteFilePath(), directory));
+					}
+				}
+			}
+		}
+	}
+	std::sort(scriptsList.begin(), scriptsList.end());
+}
+
+void ScriptPaths::runScript(const QString& path)
+{
+	// TODO: give some sort of warning?
+	if (!QFileInfo(path).exists())
+		return;
+
+	emit runScriptFile(path);
+}
+
+QStringList ScriptPaths::get()
+{
+	return paths.paths;
+}
+
+void ScriptPaths::append(const QString& s)
+{
+	paths.paths.append(s);
+}
+
+void ScriptPaths::remove(int i)
+{
+	paths.paths.remove(i);
+}
+
+void ScriptPaths::clear()
+{
+	paths.paths.clear();
+}
+
+QString ScriptPaths::item(int i) const
+{
+	return paths.paths.at(i);
+}
+
+ScriptPathsList::ScriptPathsList()
+{
+	PrefsContext* prefs = PrefsManager::instance().prefsFile->getPluginContext("scriptplugin");
+	if (!prefs)
+		return;
+
+	auto scriptPaths = prefs->getTable("scriptpaths");
+	for (int i = 0; i < scriptPaths->getRowCount(); ++i)
+	{
+		paths.append(QDir::toNativeSeparators(scriptPaths->get(i, 0)));
+	}
+}
+
+void ScriptPathsList::saveToPrefs() const
+{
+	PrefsContext* prefs = PrefsManager::instance().prefsFile->getPluginContext("scriptplugin");
+	if (!prefs)
+		return;
+
+	auto scriptPaths = prefs->getTable("scriptpaths");
+	scriptPaths->clear();
+	for (int i = 0; i < paths.count(); i++)
+	{
+		// pathListWidget->item(i)->text()
+		scriptPaths->set(i, 0, QDir::fromNativeSeparators(paths[i]));
+	}
+}
diff --git a/scribus/plugins/scriptplugin/scriptpaths.h b/scribus/plugins/scriptplugin/scriptpaths.h
new file mode 100644
index 000000000..9002e6e1b
--- /dev/null
+++ b/scribus/plugins/scriptplugin/scriptpaths.h
@@ -0,0 +1,74 @@
+/*
+For general Scribus (>=1.3.2) copyright and licensing information please refer
+to the COPYING file provided with the program. Following this notice may exist
+a copyright and/or license notice that predates the release of Scribus 1.3.2
+for which a new license (GPL+exception) is in place.
+*/
+
+#ifndef SCRIPTPATHS_H
+#define SCRIPTPATHS_H
+
+/**
+ * Allow the user to add local script to the Script menu and run them.
+ */
+
+#include <QStringList>
+#include <QPointer>
+#include "scraction.h"
+
+class MenuManager;
+
+struct ScriptPathsList
+{
+		ScriptPathsList();
+		void saveToPrefs() const;
+		QStringList paths;
+};
+
+struct ScriptPathsInfo
+{
+	ScriptPathsInfo(QString path, QString name): path{path}, name{name} {}
+
+	QString path;
+	QString name;
+
+	friend bool operator<(const ScriptPathsInfo& l, const ScriptPathsInfo& r)
+	{
+		return l.name < r.name;
+	}
+};
+
+class ScriptPaths : public QObject
+{
+	Q_OBJECT
+
+public:
+	ScriptPaths();
+	void saveToPrefs() const;
+
+	void updateScriptsList();
+	void attachToMenu(MenuManager* menuManager);
+	void buildMenu();
+
+	bool empty() { return paths.paths.count() == 0; }
+	QStringList get();
+	void append(const QString& s);
+	void remove (int i);
+	void clear ();
+	QString item(int i) const;
+
+signals:
+	void runScriptFile(const QString& path);
+
+public slots:
+	void runScript(const QString& name);
+
+private:
+	MenuManager* menuManager = nullptr;
+	QList<ScriptPathsInfo> scriptsList;
+
+	ScriptPathsList paths;
+	QMap<QString, QPointer<ScrAction>> scriptsActions;
+};
+
+#endif
diff --git a/scribus/scraction.cpp b/scribus/scraction.cpp
index fde4064af..e045fa330 100644
--- a/scribus/scraction.cpp
+++ b/scribus/scraction.cpp
@@ -114,6 +114,8 @@ void ScrAction::triggeredToTriggeredData()
 		emit triggeredData(data().toString());
 	if (m_actionType == ScrAction::RecentScript)
 		emit triggeredData(data().toString());
+	if (m_actionType == ScrAction::OwnScript)
+		emit triggeredData(data().toString());
 	if (m_actionType == ScrAction::UnicodeChar)
 		emit triggeredUnicodeShortcut(data().toInt());
 	if (m_actionType == ScrAction::Layer)
@@ -144,6 +146,8 @@ void ScrAction::toggledToToggledData(bool ison)
 		emit toggledData(ison, data().toString());
 	if (m_actionType == ScrAction::RecentScript)
 		emit toggledData(ison, text());
+	if (m_actionType == ScrAction::OwnScript)
+		emit toggledData(ison, text());
 	if (m_actionType == ScrAction::Layer)
 		emit toggledData(ison, data().toInt());
 	// no toggle for UnicodeChar
diff --git a/scribus/scraction.h b/scribus/scraction.h
index 48a95d8a7..eae2db59d 100644
--- a/scribus/scraction.h
+++ b/scribus/scraction.h
@@ -37,7 +37,7 @@ class SCRIBUS_API ScrAction : public QAction
 	Q_OBJECT
 
 public:
-	enum ActionType { Normal, DataInt, DataDouble, DataQString, RecentFile, DLL, Window, RecentScript, UnicodeChar, Layer, ActionDLL, RecentPaste, ActionDLLSE };
+	enum ActionType { Normal, DataInt, DataDouble, DataQString, RecentFile, DLL, Window, RecentScript, UnicodeChar, Layer, ActionDLL, RecentPaste, ActionDLLSE, OwnScript };
 	
 	/*!
 		\author Craig Bradney
