1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
#!/usr/bin/env python3
import sys
import subprocess
import json
import os
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QHBoxLayout, QVBoxLayout, QWidget, QAction, QFileDialog, QInputDialog, QMenu, QStyle
from PyQt5.QtCore import Qt, QMimeData
class ScriptRunnerGUI(QMainWindow):
def __init__(self):
super().__init__()
self.script_buttons = {}
self.terminal_emulators = self.find_terminal_emulators()
self.selected_terminal = self.terminal_emulators[0] if self.terminal_emulators else None
self.initUI()
def initUI(self):
self.setWindowTitle("Dynamic Script Runner")
self.setGeometry(300, 300, 400, 400)
self.setAcceptDrops(True)
self.mainLayout = QVBoxLayout()
self.container = QWidget()
self.container.setLayout(self.mainLayout)
self.setCentralWidget(self.container)
# Menu for actions
self.menu_bar = self.menuBar()
file_menu = self.menu_bar.addMenu('File')
add_script_action = QAction('Add Script', self)
add_script_action.setShortcut('Ctrl+N')
add_script_action.triggered.connect(self.add_script)
file_menu.addAction(add_script_action)
# Terminal emulator selection
terminal_menu = QMenu('Select Terminal', self)
for term in self.terminal_emulators:
term_action = QAction(term, self, checkable=True)
term_action.triggered.connect(lambda checked, t=term: self.set_terminal_emulator(t))
if term == self.selected_terminal:
term_action.setChecked(True)
terminal_menu.addAction(term_action)
file_menu.addMenu(terminal_menu)
self.load_scripts()
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.acceptProposedAction()
def dropEvent(self, event):
for url in event.mimeData().urls():
if url.isLocalFile() and url.toLocalFile().endswith('.sh'):
self.add_script_from_path(url.toLocalFile())
def add_script_from_path(self, script_path):
script_name, ok = QInputDialog.getText(self, 'Script Name', 'Enter name for the script button:', text=os.path.basename(script_path))
if ok and script_name:
self.create_script_button(script_name, script_path)
self.save_script(script_name, script_path)
def add_script(self):
file_dialog = QFileDialog(self)
file_dialog.setNameFilter("Shell scripts (*.sh)")
script_path, _ = file_dialog.getOpenFileName(self, "Select Script", "", "Shell scripts (*.sh)")
if script_path:
self.add_script_from_path(script_path)
def create_script_button(self, name, path):
scriptLayout = QHBoxLayout()
# Script execution button
btn = QPushButton(name, self)
btn.clicked.connect(lambda: self.run_script(path))
scriptLayout.addWidget(btn)
# Edit button
edit_icon = self.style().standardIcon(QStyle.SP_FileDialogDetailedView)
edit_btn = QPushButton(edit_icon, '', self)
edit_btn.setFixedSize(30, 30)
edit_btn.clicked.connect(lambda: self.edit_script(path))
scriptLayout.addWidget(edit_btn)
# Delete button
delete_icon = self.style().standardIcon(QStyle.SP_TrashIcon)
delete_btn = QPushButton(delete_icon, '', self)
delete_btn.setFixedSize(30, 30)
delete_btn.clicked.connect(lambda: self.delete_script(name, scriptLayout))
scriptLayout.addWidget(delete_btn)
self.mainLayout.addLayout(scriptLayout)
self.script_buttons[name] = (scriptLayout, path)
def delete_script(self, name, layout):
# Assuming the script's layout contains three widgets: run button, edit button, and delete button
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Remove layout from main layout and delete
self.mainLayout.removeItem(layout)
layout.deleteLater()
# Remove the script from the dictionary
if name in self.script_buttons:
del self.script_buttons[name]
self.save_all_scripts()
def edit_script(self, script_path):
terminal_command = self.get_terminal_command()
if terminal_command:
subprocess.Popen(terminal_command + ['vim', script_path])
else:
print("Default terminal emulator not found.")
def run_script(self, script_path):
terminal_command = self.get_terminal_command()
if terminal_command:
subprocess.Popen(terminal_command + ['sh', '-c', f'"{script_path}"; read -p "Press enter to exit..."'])
else:
print("Default terminal emulator not found.")
def find_terminal_emulators(self):
terminals = ['x-terminal-emulator', 'gnome-terminal', 'konsole', 'xterm', 'kitty']
return [t for t in terminals if os.path.exists('/usr/bin/' + t)]
def set_terminal_emulator(self, terminal):
self.selected_terminal = terminal
def get_terminal_command(self):
if self.selected_terminal:
return ['/usr/bin/' + self.selected_terminal, '-e']
return None
def save_script(self, name, path):
with open('scripts.json', 'r+') as file:
scripts = json.load(file)
scripts[name] = path
file.seek(0)
json.dump(scripts, file)
def save_all_scripts(self):
scripts = {name: data[1] for name, data in self.script_buttons.items()}
with open('scripts.json', 'w') as file:
json.dump(scripts, file)
def load_scripts(self):
try:
with open('scripts.json', 'r') as file:
scripts = json.load(file)
for name, path in scripts.items():
self.create_script_button(name, path)
except FileNotFoundError:
with open('scripts.json', 'w') as file:
json.dump({}, file)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = ScriptRunnerGUI()
ex.show()
sys.exit(app.exec_())
|