summaryrefslogtreecommitdiff
path: root/gmm
diff options
context:
space:
mode:
Diffstat (limited to 'gmm')
-rwxr-xr-xgmm116
1 files changed, 109 insertions, 7 deletions
diff --git a/gmm b/gmm
index 44a8297..d0ae750 100755
--- a/gmm
+++ b/gmm
@@ -9,9 +9,20 @@
# https://stackoverflow.com/questions/23662280/how-to-log-the-contents-of-a-configparser/50362738#50362738
# srb_lib/srb_tk.py
# https://coderslegacy.com/python/list-of-tkinter-widgets/
+# https://stackoverflow.com/questions/46331408/limiting-python-filedialog-to-a-specific-filetype/46339932#46339932
+# https://stackoverflow.com/questions/30614279/tkinter-treeview-get-selected-item-values
+# https://www.reddit.com/r/learnpython/comments/hcn8cc/cant_bind_double_click_to_treeview_with_grid/
+# for drag and drop, I tried a few things that failed:
+# https://sourceforge.net/projects/tkdnd/ failed because it does not support python or in between applications
+# https://github.com/python/cpython/blob/main/Lib/tkinter/dnd.py says it is within the same application
+# https://stackoverflow.com/questions/44887576/how-can-i-create-a-drag-and-drop-interface within but it does not work with a file dragged in.
+# Improve:
+# get tkstackrpms in a venv, so I can try pip install tkinterdnd2., https://www.delftstack.com/howto/python-tkinter/tkinter-drag-and-drop/#download-and-setup-the-essential-packages-for-drag-and-drop-in-tkinter
+# need .desktop file that takes application/x-iso9660-image, that calls this with --gui
-import argparse, sys, os, psutil, subprocess, json, configparser, tkinter as tk, tkinter.simpledialog
+import argparse, sys, os, psutil, subprocess, json, configparser, tkinter as tk, tkinter.simpledialog, tkinter.filedialog
import tkstackrpms as stk
+import tkinter.ttk as ttk
# LOW-LEVEL values
appname = "gmm"
@@ -160,6 +171,15 @@ def unmount_iso_to_path(isofile, mount_point):
if debuglev(5):
if mount_e:
ferror(mount_e)
+ # and now delete the empty directory
+ if not mount_point:
+ mount_point = isofile
+ if os.path.isdir(mount_point) and (not os.listdir(mount_point)):
+ try:
+ os.rmdir(mount_point)
+ except Exception as e:
+ if debuglev(5):
+ ferror(f"INFO: while trying to remove now-empty dir {mount_point}, got error {e}, continuing...")
def get_iso_mounted_to_path(mount_point, mounts = None):
"""
@@ -244,9 +264,7 @@ def save_config(configfile):
config.write(cf)
# GRAPHICAL APP
-# want mount iso... file dialog, that has two mimetype choices: *.iso, or *
-# a combo box/list box thing of mounted isos, mount point
-# a config file/dialog for choosing default mounts dir, which is managed by this app. E.g., /mnt/iso so the first disc is /mnt/iso/1 or something. Or ~/mnt/iso. Something like that.
+# Settings window
def NewWindow(textvar, func1, ok_button_func, mounts=None):
window = tk.Toplevel()
#window.geometry("250x250")
@@ -263,6 +281,10 @@ def NewWindow(textvar, func1, ok_button_func, mounts=None):
ent_mounts_dir.configure(state="disabled")
return window
+# want mount iso... file dialog, that has two mimetype choices: *.iso, or *
+# a combo box/list box thing of mounted isos, mount point
+# a config file/dialog for choosing default mounts dir, which is managed by this app. E.g., /mnt/iso so the first disc is /mnt/iso/1 or something. Or ~/mnt/iso. Something like that.
+# MAIN WINDOW
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
@@ -270,11 +292,12 @@ class App(tk.Frame):
self.mounts = list_mounts()
self.mounts_dir = tk.StringVar()
self.master.title("Graphical Mount Manager")
- self.master.minsize(250,250)
+ self.master.minsize(550,200)
imgicon = stk.get_scaled_icon("dvd_unmount",24,"default","","apps")
self.master.tk.call("wm","iconphoto",self.master._w,imgicon)
menu = tk.Menu(self.master)
menu_file = tk.Menu(menu,tearoff=0)
+ menu_file.add_command(label="Mount iso...", command=self.func_mount_iso_dialog, underline=0)
menu_file.add_command(label="Settings...", command=self.func_open_settings, underline=0)
menu_file.add_separator()
menu_file.add_command(label="Exit", command=self.func_exit, underline=1)
@@ -285,6 +308,19 @@ class App(tk.Frame):
self.master.config(menu=menu)
self.grid() # use this instead of pack()
self.background_color = self.master.cget("bg")
+ self.mlframe = tk.Frame(self.master)
+ self.mlframe.grid(row=0,column=0,columnspan=3,sticky="ew")
+ # treeview, which requires ttk
+ self.ml = ttk.Treeview(self.mlframe, columns=("source","mountpoint"),show="headings")
+ #help(self.ml)
+ self.ml.grid(column=0,row=0,columnspan=3,sticky="ew")
+ self.ml.heading("source",text="Source")
+ self.ml.heading("mountpoint",text="Mount point")
+ self.ml.column("source",width=400)
+ self.ml.bind("<Double-1>", self.func_double_click_entry)
+ # unmount button
+ self.unmount_btn = tk.Button(self.master,text="Unmount",command=self.func_unmount_current_selection,underline=0).grid(column=0,row=1)
+ self.master.bind("<Alt-u>",self.func_unmount_current_selection)
# initial load
self.refresh_form("initial")
@@ -310,12 +346,63 @@ class App(tk.Frame):
ferror(f"DEBUG: when trying to hide settings window, got {e}")
self.refresh_form()
+ def get_current_selection(self, attribute="mountpoint"):
+ """
+ Get the current path, or other attribute, from the treeview
+ """
+ value = None
+ # There might be nothing selected, so return nothing
+ values = self.ml.item(self.ml.focus())["values"]
+ if debuglev(9):
+ ferror(f"DEBUG: got values {values}")
+ try:
+ if attribute == "mountpoint":
+ value = values[1]
+ elif attribute == "source":
+ value = values[0]
+ except IndexError:
+ return None
+ return value
+
+ def func_unmount_current_selection(self, o1 = None):
+ if debuglev(9):
+ ferror(f"func_unmount_current_selection: {o1}")
+ # get current selection
+ path = self.get_current_selection()
+ if path:
+ unmount_iso_to_path(path,"")
+ self.refresh_form()
+ elif debuglev(4):
+ ferror(f"INFO: Nothing selected to unmount, continuing...")
+
def refresh_form(self,secondObj = None):
if debuglev(9):
ferror(f"DEBUG: refresh_form got secondObj {secondObj}, class {type(secondObj)}")
# compare all config settings to see if they are different
load_config(conffile) # this populates object "config"
self.mounts_dir.set(config[appname]["mounts_dir"])
+ # reload mounts
+ self.mounts = list_mounts()
+ self.ml.delete(*self.ml.get_children())
+ for i in self.mounts:
+ self.ml.insert("",tk.END, values=(i["source"],i["mountpoint"]))
+
+ def func_double_click_entry(self, o1 = None, o2 = None, o3 = None):
+ """
+ Open the mounted directory when double-clicked.
+ """
+ if debuglev(9):
+ ferror(f"DEBUG: double-click {o1},{o2},{o3}")
+ # It is possible to have nothing selected, so just throw a warning
+ path = self.get_current_selection()
+ if path:
+ if debuglev(1):
+ ferror(f"Running xdg-open {path}")
+ subprocess.Popen(["xdg-open",path])
+ else:
+ if debuglev(4):
+ ferror(f"INFO: No item selected to open, continuing...")
+ pass
def save_settings(self,secondObj = None):
if debuglev(1):
@@ -324,7 +411,22 @@ class App(tk.Frame):
save_config(conffile)
self.refresh_form()
+ def func_mount_iso_dialog(self):
+ """
+ Display a file chooser dialog to mount.
+ """
+ filename = tk.filedialog.askopenfilename(
+ filetypes = [
+ ("Disc image","*.iso"),
+ ("All files","*")
+ ]
+ )
+ if filename:
+ ferror(f"Got {filename}")
+ mount_iso_to_default(filename,config)
+ self.refresh_form()
+# WORKHERE: support drag-and-drop onto the treeview?
# MAIN CLI
if "__main__" == __name__:
mounts = list_mounts()
@@ -349,7 +451,7 @@ if "__main__" == __name__:
left = paths[0]
right = paths[1]
if os.path.isfile(left):
- if os.path.isdir(right) or (not os.paths.exists(right)):
+ if os.path.isdir(right) or (not os.path.exists(right)):
if os.path.ismount(right):
if debuglev(8):
ferror(f"DEBUG: Investigating current mount {right} to see if it is same as {left}")
@@ -371,7 +473,7 @@ if "__main__" == __name__:
print(f"INFO: will mount {left} to {right}.")
mount_iso_to_path(left, right)
elif os.path.isfile(right):
- for i in path:
+ for i in paths:
mount_iso_to_default(i,config)
else:
ferror(f"ERROR: second path {right} is not a dir or file. Choose a different spot")
bgstack15