import os
import string
import json
from PyQt5 import QtCore
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import (
QWidget,
QDockWidget,
QTreeView,
QStyle,
QFileDialog,
QLineEdit,
QPushButton,
QMessageBox,
QHBoxLayout,
QVBoxLayout,
QAbstractItemView,
QTextEdit,
)
script_folder = os.path.dirname(os.path.realpath(__file__))
cfg_file = os.path.join(script_folder, "cfg.json")
# default connection config
default_config = {"path": r""}
def read_cfg(data_file):
if not os.path.isfile(data_file):
with open(data_file, "w", encoding="utf-8") as d:
json.dump(default_config, d, indent=4, ensure_ascii=False)
data = default_config
else:
with open(data_file, "r") as fp:
data = json.load(fp)
path = data["path"]
descriptions_path = os.path.join(path, "descriptions.json")
if os.path.isfile(descriptions_path):
with open(descriptions_path, "r") as fp:
data_desc = json.load(fp)
else:
data_desc = {}
return path, data_desc
class Scripter(QDockWidget):
closingPlugin = pyqtSignal()
def __init__(self, wrapper):
QDockWidget.__init__(self)
self.wrapper = wrapper
self.setWindowTitle("Scripter")
self.ispnippets = Scripter_widget(self)
self.setWidget(self.ispnippets)
def closeEvent(self, event):
self.closingPlugin.emit()
event.accept()
class Scripter_widget(QWidget):
# Main widget tab tool
def __init__(self, parent):
super().__init__()
self.initUI()
def initUI(self):
self.wpath, self.descriptions = read_cfg(cfg_file)
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.upd_table = QPushButton()
self.upd_table.setIcon(self.style().standardIcon(QStyle.SP_BrowserReload))
self.upd_table.setToolTip("Update script list")
self.upd_table.setMaximumWidth(35)
self.path_line = QLineEdit()
self.path_line.setPlaceholderText("Path to scripts...")
self.path_line.setText(self.wpath)
self.settings = QPushButton()
self.settings.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
self.settings.setToolTip("Path to scripts")
self.settings.setMaximumWidth(35)
self.dataView = QTreeView()
self.dataView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.dataView.setRootIsDecorated(False)
self.dataView.doubleClicked.connect(self.on_double_click)
self.model = QStandardItemModel(0, 1, self.dataView)
self.model.setColumnCount(1)
self.model.setHeaderData(0, Qt.Horizontal, "Script")
self.description_area = QTextEdit()
self.description_area.setReadOnly(True)
self.dataView.setModel(self.model)
self.btn_run = QPushButton()
self.btn_run.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
h_layout = QVBoxLayout(self)
buttons_layout = QHBoxLayout(self)
content_layout = QHBoxLayout(self)
h_layout.addLayout(buttons_layout)
h_layout.addLayout(content_layout)
buttons_layout.addWidget(self.upd_table, 1)
buttons_layout.addWidget(self.path_line, 1)
buttons_layout.addWidget(self.settings, 1)
buttons_layout.addStretch()
content_layout.addWidget(self.dataView, 1)
content_layout.addWidget(self.description_area, 1)
self.description_area.setAlignment(Qt.AlignLeft | Qt.AlignTop)
h_layout.addWidget(self.btn_run)
self.upd_table.clicked.connect(lambda: self.get_actions(self.model))
self.btn_run.clicked.connect(self.run_action)
self.settings.clicked.connect(self.load_folder)
self.dataView.clicked.connect(self.get_description)
self.get_actions(self.model)
def on_double_click(self, index):
self.run_action()
def get_description(self):
selected_data = self.dataView.selectedIndexes()
script_name = selected_data[0].data()
self.description_area.setHtml(
"{}".format(self.descriptions.get(script_name, ""))
)
def load_folder(self):
result = QFileDialog.getExistingDirectoryUrl(self, "Select scripts folder")
if result:
selected_path = result.path().strip(string.punctuation)
if selected_path:
self.wpath = selected_path
else:
return
with open(cfg_file, "w", encoding="utf-8") as d:
json.dump({"path": self.wpath}, d, indent=4, ensure_ascii=False)
self.path_line.setText(self.wpath)
self.get_actions(self.model)
self.description_area.setHtml("")
def get_actions(self, model):
current_path = self.path_line.text()
if not current_path:
return
if not os.path.isdir(current_path):
self.warning_message("Wrong path")
return
self.wpath = current_path
model.setRowCount(0)
for afile in os.listdir(self.wpath):
if os.path.isfile(os.path.join(self.wpath, afile)):
if "." not in afile:
continue
action_name, action_type = os.path.splitext(afile)
if action_type == ".py":
model.insertRow(0)
model.setData(model.index(0, 0), action_name)
self.description_area.setHtml("")
print("-->", current_path)
file_descriptions = os.path.join(current_path, "descriptions.json")
if os.path.isfile(file_descriptions):
with open(file_descriptions, "r") as fp:
self.descriptions = json.load(fp)
else:
self.descriptions = {}
with open(cfg_file, "w", encoding="utf-8") as d:
json.dump({"path": self.wpath}, d, indent=4, ensure_ascii=False)
def run_action(self):
selected_data = self.dataView.selectedIndexes()
if selected_data:
script_name = selected_data[0].data()
self.run_script(script_name)
else:
self.warning_message("Select script then press ▶︎ button")
def run_script(self, script):
script_path = os.path.join(self.wpath, "{}.py".format(script))
try:
self.result = exec(
open("{}".format(script_path).encode("utf-8")).read(),
{"wrapper": self, "project_folder": self.wpath, "script_name": script},
)
except Exception as e:
print(e)
self.warning_message("Error in script\nSee Python console for details")
def warning_message(self, err_text):
msg = QMessageBox()
msg.warning(self, "Warning", err_text)