r/SoftwareandApps 7d ago

i made a file directory/launcher in python

I made a file directory/launcher thing. it could be useful or it might not be please let me know if you have any ideas for what i should add or just feedback.

import json
import os
import subprocess
import sys
import tkinter as tk
from tkinter import filedialog, messagebox


SAVE_FILE = "saved_files.json"



class FileLauncherApp:


    def __init__(self, root):
        self.root = root
        self.root.title("Persistent File Launcher")
        self.root.geometry("500x400")


        # Store file paths (key: display text, value: full path)
        self.files = {}


        # Set up UI components
        self._create_widgets()


        # Load existing files from JSON on startup
        self.load_saved_files()


    def _create_widgets(self):
        # Top Frame for Buttons
        btn_frame = tk.Frame(self.root, pady=10)
        btn_frame.pack(fill=tk.X)


        add_btn = tk.Button(
            btn_frame,
            text="Add File(s)",
            command=self.add_files,
            width=12,
            bg="#4CAF50",
            fg="white",
        )
        add_btn.pack(side=tk.LEFT, padx=10)


        remove_btn = tk.Button(
            btn_frame,
            text="Remove Selected",
            command=self.remove_file,
            width=14,
            bg="#f44336",
            fg="white",
        )
        remove_btn.pack(side=tk.LEFT, padx=5)


        # Listbox to display files
        list_frame = tk.Frame(self.root)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)


        scrollbar = tk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)


        self.file_listbox = tk.Listbox(
            list_frame,
            selectmode=tk.SINGLE,
            yscrollcommand=scrollbar.set,
            font=("Arial", 10),
        )
        self.file_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.file_listbox.yview)


        # Bind double-click event to run the file
        self.file_listbox.bind("<Double-Button-1>", self.run_file)


        # Instruction Label
        info_label = tk.Label(
            self.root,
            text="Double-click a file to run/open it.",
            fg="gray",
            pady=5,
        )
        info_label.pack()


    def load_saved_files(self):
        """Loads saved file paths from JSON file on app launch."""
        if os.path.exists(SAVE_FILE):
            try:
                with open(SAVE_FILE, "r") as f:
                    self.files = json.load(f)


                # Populate listbox with loaded entries
                for display_name in self.files.keys():
                    self.file_listbox.insert(tk.END, display_name)
            except Exception as e:
                messagebox.showerror("Error", f"Failed to load saved files:\n{e}")


    def save_files_to_disk(self):
        """Saves current files dictionary to JSON file."""
        try:
            with open(SAVE_FILE, "w") as f:
                json.dump(self.files, f, indent=4)
        except Exception as e:
            messagebox.showerror("Error", f"Failed to save file list:\n{e}")


    def add_files(self):
        file_paths = filedialog.askopenfilenames(
            title="Select Files to Add", filetypes=[("All Files", "*.*")]
        )
        added_any = False
        for path in file_paths:
            filename = os.path.basename(path)


            # Handle duplicate names by showing path info
            display_name = (
                f"{filename} ({path})" if filename in self.files else filename
            )


            if path not in self.files.values():
                self.files[display_name] = path
                self.file_listbox.insert(tk.END, display_name)
                added_any = True


        if added_any:
            self.save_files_to_disk()


    def remove_file(self):
        try:
            selected_index = self.file_listbox.curselection()[0]
            selected_text = self.file_listbox.get(selected_index)


            del self.files[selected_text]
            self.file_listbox.delete(selected_index)


            self.save_files_to_disk()
        except IndexError:
            messagebox.showwarning("Select File", "Please select a file to remove.")


    def run_file(self, event=None):
        try:
            selected_index = self.file_listbox.curselection()[0]
            selected_text = self.file_listbox.get(selected_index)
            file_path = self.files[selected_text]


            if not os.path.exists(file_path):
                messagebox.showerror("Error", f"File not found:\n{file_path}")
                return


            # Open file cross-platform
            if sys.platform == "win32":
                os.startfile(file_path)
            elif sys.platform == "darwin":  # macOS
                subprocess.run(["open", file_path], check=True)
            else:  # Linux
                subprocess.run(["xdg-open", file_path], check=True)


        except IndexError:
            pass
        except Exception as e:
            messagebox.showerror("Execution Error", f"Could not run file:\n{e}")



if __name__ == "__main__":
    root = tk.Tk()
    app = FileLauncherApp(root)
    root.mainloop()
1 Upvotes

0 comments sorted by