shell cleanup/reordering
This commit is contained in:
213
src/Python/Scripts/GTK/edit-path
Executable file
213
src/Python/Scripts/GTK/edit-path
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/usr/sbin/python
|
||||
|
||||
# GTK Imports
|
||||
import gi, faulthandler, signal
|
||||
gi.require_version('Gtk', '3.0')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
|
||||
# Python Imports
|
||||
import os, threading, time
|
||||
|
||||
from setproctitle import setproctitle
|
||||
|
||||
|
||||
|
||||
app_name = "PATH Edit Tool"
|
||||
|
||||
|
||||
|
||||
def threaded(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
|
||||
return wrapper
|
||||
|
||||
|
||||
class Main(Gtk.Window):
|
||||
def __init__(self):
|
||||
super(Main, self).__init__()
|
||||
self._USER_HOME = os.path.expanduser('~')
|
||||
PREFERED_BASH_PATH = f"{self._USER_HOME}/.bash_paths"
|
||||
|
||||
icon_size = 16
|
||||
box = Gtk.Box()
|
||||
box2 = Gtk.Box()
|
||||
separator = Gtk.Separator()
|
||||
self._insert_entry = Gtk.Entry()
|
||||
self.message_widget = Gtk.Popover.new(separator)
|
||||
self.message_label = Gtk.Label()
|
||||
add_button = Gtk.Button.new_from_icon_name("gtk-add", icon_size)
|
||||
delete_button = Gtk.Button.new_from_icon_name("gtk-delete", icon_size)
|
||||
save_button = Gtk.Button.new_from_icon_name("gtk-save", icon_size)
|
||||
|
||||
scroll_vw, grid, self.store = self._create_treeview_widget(title="PATHs")
|
||||
tree_selection = grid.get_selection()
|
||||
|
||||
box2.add(self._insert_entry)
|
||||
box2.add(add_button)
|
||||
box2.add(delete_button)
|
||||
|
||||
box.add(separator)
|
||||
box.add(scroll_vw)
|
||||
box.add(box2)
|
||||
box.add(save_button)
|
||||
|
||||
self.message_widget.add(self.message_label)
|
||||
self.add(box)
|
||||
self.add(self.message_widget)
|
||||
|
||||
self.message_widget.set_default_widget(self.message_label)
|
||||
self._insert_entry.set_hexpand(True)
|
||||
self._insert_entry.set_placeholder_text("Path...")
|
||||
save_button.set_label("Save")
|
||||
scroll_vw.set_vexpand(True)
|
||||
box.set_orientation(1)
|
||||
box.set_vexpand(True)
|
||||
self.set_default_size(480, 560)
|
||||
self.set_title(f"{app_name}")
|
||||
self.set_icon_name("applications-accessories")
|
||||
|
||||
add_button.connect("clicked", self.add_entry)
|
||||
delete_button.connect("clicked", self.delete_entry)
|
||||
save_button.connect("clicked", self.save_enteries)
|
||||
tree_selection.connect("changed", self._set_selected)
|
||||
|
||||
self.connect("delete-event", Gtk.main_quit)
|
||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit)
|
||||
|
||||
self.success = "#88cc27"
|
||||
self.warning = "#ffa800"
|
||||
self.error = "#ff0000"
|
||||
self.selected = None
|
||||
|
||||
if os.path.isfile(PREFERED_BASH_PATH):
|
||||
self.bashrc_path = PREFERED_BASH_PATH
|
||||
else:
|
||||
self.bashrc_path = f"{self._USER_HOME}/.bashrc"
|
||||
|
||||
self._load_paths_data()
|
||||
|
||||
self.message_widget.show_all()
|
||||
self.message_widget.popdown()
|
||||
box.show_all()
|
||||
box2.show_all()
|
||||
self.show_all()
|
||||
|
||||
|
||||
|
||||
|
||||
def add_entry(self, widget):
|
||||
path = self._insert_entry.get_text().strip()
|
||||
|
||||
if os.path.isdir(path):
|
||||
self.store.append([path])
|
||||
else:
|
||||
self.display_message(self.warning, "Not a directory!")
|
||||
|
||||
def delete_entry(self, widget):
|
||||
self.store.remove(self.selected)
|
||||
|
||||
def save_enteries(self, widget):
|
||||
try:
|
||||
paths = list()
|
||||
iter = self.store.get_iter_first()
|
||||
while iter != None:
|
||||
pth = self.store.get_value(iter, 0)
|
||||
pth = pth.replace(self._USER_HOME, "$HOME")
|
||||
paths.append(pth)
|
||||
iter = self.store.iter_next(iter)
|
||||
|
||||
|
||||
toExport = "export PATH=\"" + ':'.join(paths) + "\"\n\n"
|
||||
file = open(self.bashrc_path, mode='r')
|
||||
for line in file:
|
||||
if "export PATH=" in line:
|
||||
continue
|
||||
else:
|
||||
toExport += line
|
||||
|
||||
file.close()
|
||||
file = open(self.bashrc_path, mode='w')
|
||||
file.write(toExport)
|
||||
file.close()
|
||||
self.display_message(self.success, "Successfully saved file!")
|
||||
except Exception as e:
|
||||
self.display_message(self.error, "Opening/Writing to file failed!")
|
||||
print("Opening/Writing to file failed with the following:\n\n")
|
||||
print(e)
|
||||
|
||||
|
||||
def _set_selected(self, user_data):
|
||||
selected = user_data.get_selected()[1]
|
||||
if selected:
|
||||
self.selected = selected
|
||||
|
||||
def _load_paths_data(self):
|
||||
PATH_str = os.getenv("PATH")
|
||||
|
||||
# If path exists in bashrc replace default selection...
|
||||
file = open(self.bashrc_path, mode='r')
|
||||
for line in file:
|
||||
if "export PATH=" in line:
|
||||
part = line.replace("export PATH=", "")
|
||||
cleaned = part.replace("\"", "")
|
||||
PATH_str = cleaned.strip()
|
||||
|
||||
# Split string into list/tuple and add parts to store
|
||||
paths = PATH_str.split(":")
|
||||
for path in paths:
|
||||
self.store.append([path])
|
||||
|
||||
|
||||
|
||||
|
||||
def display_message(self, type, text):
|
||||
markup = f"<span foreground='{type}'>{text}</span>"
|
||||
self.message_label.set_markup(markup)
|
||||
self.message_widget.popup()
|
||||
self.hide_message_timed()
|
||||
|
||||
@threaded
|
||||
def hide_message_timed(self):
|
||||
time.sleep(3)
|
||||
GLib.idle_add(self.message_widget.popdown)
|
||||
|
||||
|
||||
|
||||
|
||||
def _create_treeview_widget(self, title = "Not Set"):
|
||||
scroll = Gtk.ScrolledWindow()
|
||||
grid = Gtk.TreeView()
|
||||
store = Gtk.ListStore(str)
|
||||
column = Gtk.TreeViewColumn(title)
|
||||
name = Gtk.CellRendererText()
|
||||
selec = grid.get_selection()
|
||||
|
||||
grid.set_model(store)
|
||||
selec.set_mode(2)
|
||||
|
||||
column.pack_start(name, True)
|
||||
column.add_attribute(name, "text", 0)
|
||||
column.set_expand(False)
|
||||
|
||||
grid.append_column(column)
|
||||
grid.set_search_column(0)
|
||||
grid.set_headers_visible(True)
|
||||
grid.set_enable_tree_lines(False)
|
||||
|
||||
grid.show_all()
|
||||
scroll.add(grid)
|
||||
grid.columns_autosize()
|
||||
return scroll, grid, store
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
faulthandler.enable() # For better debug info
|
||||
setproctitle(f"{app_name}")
|
||||
|
||||
main = Main()
|
||||
Gtk.main()
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# GTK Imports
|
||||
import gi, faulthandler, signal
|
||||
gi.require_version('Gtk', '3.0')
|
||||
|
||||
from gi.repository import Gtk as gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
|
||||
# Python Imports
|
||||
import os, threading, time
|
||||
|
||||
from setproctitle import setproctitle
|
||||
|
||||
|
||||
def threaded(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
|
||||
class Main:
|
||||
def __init__(self):
|
||||
setproctitle('PATH Edit Tool')
|
||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, gtk.main_quit)
|
||||
faulthandler.enable() # For better debug info
|
||||
|
||||
self.HOME = os.path.expanduser('~')
|
||||
PREFERED_BASH_PATH = self.HOME + "/" + ".bash_paths"
|
||||
SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||
GLADE_FILE = "main.glade"
|
||||
|
||||
self.builder = gtk.Builder()
|
||||
self.builder.add_from_file(SCRIPT_PTH + GLADE_FILE)
|
||||
self.builder.connect_signals(self)
|
||||
|
||||
self.pathTreeView = self.builder.get_object("pathTreeView")
|
||||
self.messageWidget = self.builder.get_object("messageWidget")
|
||||
self.messageLabel = self.builder.get_object("messageLabel")
|
||||
|
||||
self.pathListStore = gtk.ListStore(str)
|
||||
self.success = "#88cc27"
|
||||
self.warning = "#ffa800"
|
||||
self.error = "#ff0000"
|
||||
self.selected = None
|
||||
self.bashrcPath = ""
|
||||
|
||||
if os.path.isfile(PREFERED_BASH_PATH):
|
||||
self.bashrcPath = PREFERED_BASH_PATH
|
||||
else:
|
||||
self.bashrcPath = self.HOME + "/" + ".bashrc"
|
||||
|
||||
self.setupTreeview()
|
||||
self.loadPaths()
|
||||
|
||||
window = self.builder.get_object("Main_Window")
|
||||
window.connect("delete-event", gtk.main_quit)
|
||||
window.show()
|
||||
|
||||
|
||||
|
||||
def addEntry(self, widget):
|
||||
toAddPathTxt = self.builder.get_object("toAddPathEntry").get_text().strip()
|
||||
|
||||
if os.path.isdir(toAddPathTxt):
|
||||
self.pathListStore.append([toAddPathTxt])
|
||||
else:
|
||||
self.displayMessage(self.warning, "Not a directory!")
|
||||
|
||||
def deleteEntry(self, widget):
|
||||
self.pathListStore.remove(self.selected)
|
||||
|
||||
def saveToBashrc(self, widget):
|
||||
try:
|
||||
paths = list()
|
||||
iter = self.pathListStore.get_iter_first()
|
||||
while iter != None:
|
||||
pth = self.pathListStore.get_value(iter, 0)
|
||||
pth = pth.replace(self.HOME, "$HOME")
|
||||
paths.append(pth)
|
||||
# paths.append(self.pathListStore.get_value(iter, 0))
|
||||
iter = self.pathListStore.iter_next(iter)
|
||||
|
||||
|
||||
toExport = "export PATH=\"" + ':'.join(paths) + "\"\n\n"
|
||||
file = open(self.bashrcPath, mode='r')
|
||||
for line in file:
|
||||
if "export PATH=" in line:
|
||||
continue
|
||||
else:
|
||||
toExport += line
|
||||
|
||||
file.close()
|
||||
file = open(self.bashrcPath, mode='w')
|
||||
file.write(toExport)
|
||||
file.close()
|
||||
self.displayMessage(self.success, "Successfully saved file!")
|
||||
except Exception as e:
|
||||
self.displayMessage(self.error, "Opening/Writing to file failed!")
|
||||
print("Opening/Writing to file failed with the following:\n\n")
|
||||
print(e)
|
||||
|
||||
|
||||
def setSelected(self, user_data):
|
||||
selected = user_data.get_selected()[1]
|
||||
if selected:
|
||||
self.selected = selected
|
||||
|
||||
def loadPaths(self):
|
||||
pathsStr = os.getenv("PATH")
|
||||
|
||||
# If path exists in bashrc replace default selection...
|
||||
file = open(self.bashrcPath, mode='r')
|
||||
for line in file:
|
||||
if "export PATH=" in line:
|
||||
part = line.replace("export PATH=", "")
|
||||
cleaned = part.replace("\"", "")
|
||||
pathsStr = cleaned.strip()
|
||||
|
||||
# Split string into list/tuple and add parts to store
|
||||
paths = pathsStr.split(":")
|
||||
for path in paths:
|
||||
self.pathListStore.append([path])
|
||||
|
||||
|
||||
def setupTreeview(self):
|
||||
renderer = gtk.CellRendererText()
|
||||
pathColumn = gtk.TreeViewColumn(title="Paths", cell_renderer=renderer, text=0)
|
||||
self.pathTreeView.append_column(pathColumn)
|
||||
self.pathTreeView.set_model(self.pathListStore)
|
||||
|
||||
|
||||
def displayMessage(self, type, text):
|
||||
markup = "<span foreground='" + type + "'>" + text + "</span>"
|
||||
self.messageLabel.set_markup(markup)
|
||||
self.messageWidget.popup()
|
||||
self.hideMessageTimed()
|
||||
|
||||
@threaded
|
||||
def hideMessageTimed(self):
|
||||
time.sleep(3)
|
||||
GLib.idle_add(self.messageWidget.popdown)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main = Main()
|
||||
gtk.main()
|
||||
@@ -1,162 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkImage" id="delImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-delete</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="plusImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="Main_Window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Edit PATH App</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="default_width">480</property>
|
||||
<property name="default_height">560</property>
|
||||
<property name="icon_name">applications-accessories</property>
|
||||
<property name="gravity">center</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="pathTreeView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection">
|
||||
<signal name="changed" handler="setSelected" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="toAddPathEntry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="placeholder_text" translatable="yes">Path...</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Add path...</property>
|
||||
<property name="image">plusImage</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="addEntry" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Delete...</property>
|
||||
<property name="image">delImage</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="deleteEntry" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">gtk-save</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Save...</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="saveToBashrc" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkPopover" id="messageWidget">
|
||||
<property name="width_request">320</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="relative_to">separator1</property>
|
||||
<property name="position">bottom</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="messageLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="justify">center</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="2"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
Reference in New Issue
Block a user