|
|
#!/usr/bin/python3 |
|
|
# -*- coding:Utf-8 -*- |
|
|
|
|
|
|
|
|
""" |
|
|
Description : |
|
|
Configuration du handymenu |
|
|
""" |
|
|
|
|
|
import sys |
|
|
import os |
|
|
import gi |
|
|
gi.require_version('Gtk', '3.0') |
|
|
from gi.repository import Gtk, GObject, Gdk, GdkPixbuf |
|
|
from xdg import DesktopEntry |
|
|
import gettext |
|
|
import locale |
|
|
|
|
|
from hm_utils import * |
|
|
|
|
|
def get_info_desktop(desktopfile): |
|
|
"""return infos from a .desktop file""" |
|
|
name, cmd, icon, generic= "", "", "", "" |
|
|
lang = locale.setlocale(locale.LC_ALL, "")[0:2] |
|
|
d = DesktopEntry.DesktopEntry(desktopfile) |
|
|
name = d.getName() |
|
|
icon = d.getIcon() |
|
|
generic = d.getGenericName() |
|
|
cmd = d.getExec() |
|
|
|
|
|
cmd = cmd.split('%')[0].strip() |
|
|
# handle wine shortcuts |
|
|
if cmd.startswith('env WINEPREFIX'): |
|
|
cmd = cmd.replace('\\\\','\\') |
|
|
return(name, cmd, icon, generic) |
|
|
|
|
|
class ViewHMConfig(Gtk.Dialog): |
|
|
|
|
|
def __init__(self, parent, config): |
|
|
Gtk.Dialog.__init__(self, ("Configuration du HandyMenu"), parent, 0) |
|
|
self.set_border_width(10) |
|
|
self.set_default_size(450, 300) |
|
|
|
|
|
scrolledwindow = Gtk.ScrolledWindow() |
|
|
scrolledwindow.set_hexpand(True) |
|
|
scrolledwindow.set_vexpand(True) |
|
|
|
|
|
self.textview = Gtk.TextView() |
|
|
self.textbuffer = self.textview.get_buffer() |
|
|
|
|
|
configuration = "" |
|
|
for s in config: |
|
|
configuration += str(s['name']) + "\n" |
|
|
for app in s['apps']: |
|
|
configuration += " {}\n".format(str(app)) |
|
|
|
|
|
self.textbuffer.set_text(configuration) |
|
|
scrolledwindow.add(self.textview) |
|
|
|
|
|
# on récupère la zone de stockage du dialogue |
|
|
box = self.get_content_area() |
|
|
box.add(scrolledwindow) |
|
|
|
|
|
self.show_all() |
|
|
|
|
|
class HandymenuConfig(): |
|
|
def about(self): |
|
|
# fenêtre à propos. |
|
|
m = Gtk.MessageDialog(parent=self.window) |
|
|
m.add_buttons(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE) |
|
|
m.set_markup(('<b>Handymenu</b>\n\n\ |
|
|
version : {0}\n\ |
|
|
auteur : {1}\n\ |
|
|
licence : {2}\n\ |
|
|
homepage : <a href="{3}" title="HandyMenu homepage">{3}</a>').format(version, auteur, licence, homepage)) |
|
|
|
|
|
import base64 |
|
|
import random |
|
|
imgsrc = random.choice(imglist) |
|
|
|
|
|
g = base64.b64decode(imgsrc) |
|
|
imgpath = "/tmp/.hmbtn.png" |
|
|
with open(imgpath, "wb") as t: |
|
|
t.write(g) |
|
|
image = Gtk.Image.new_from_file(imgpath) |
|
|
|
|
|
btnbox = m.get_action_area() |
|
|
for btn in btnbox: # il n'y en a qu'un |
|
|
btn.set_label(("HandyLinux pour Debian-Facile")) |
|
|
btn.set_image(image) |
|
|
btn.set_image_position(Gtk.PositionType.TOP) |
|
|
|
|
|
ret = m.run() |
|
|
if ret == Gtk.ResponseType.CLOSE: |
|
|
open_cmd("x-www-browser https://debian-facile.org") |
|
|
os.remove(imgpath) |
|
|
m.destroy() |
|
|
|
|
|
def view_config(self): |
|
|
m = ViewHMConfig(self.window, self.config) |
|
|
ret = m.run() |
|
|
GObject.idle_add(m.hide) |
|
|
GObject.idle_add(m.destroy) |
|
|
|
|
|
def close_application(self, widget, event, data=None): |
|
|
open_cmd("handymenu --force &") |
|
|
Gtk.main_quit() |
|
|
return False |
|
|
|
|
|
def appfinder(self, widget=None, event=None): |
|
|
open_cmd('xfce4-appfinder &') |
|
|
|
|
|
def restart(self, widget=None, event=None): |
|
|
page = self.section_list.get_current_page() |
|
|
self.config = load_config() |
|
|
self.make_menu(initialize = False) |
|
|
if page > len(self.config): |
|
|
page = 0 |
|
|
self.section_list.set_current_page(page) |
|
|
|
|
|
def back_to_default(self, widget): |
|
|
set_default_config() |
|
|
self.restart() |
|
|
|
|
|
def add_new_section(self, widget): |
|
|
name = widget.get_text().strip() |
|
|
if len(name) != 0: |
|
|
newsec = {'name' : name, 'id': "", 'apps': [] } |
|
|
add_section(self.config, newsec) |
|
|
self.restart() |
|
|
|
|
|
def del_section(self, section): |
|
|
self.config.remove(section) |
|
|
save_config(self.config) |
|
|
self.restart() |
|
|
|
|
|
def move_sec(self, section, index): |
|
|
reload = move_section(self.config, section, index) |
|
|
self.section_list.set_current_page(self.config.index(section)) |
|
|
if reload: |
|
|
self.restart() |
|
|
|
|
|
def add_item_to_section(self, name, cmd, icon, generic, section): |
|
|
app = {'name' : name, 'icon' : icon, 'cmd' : cmd, 'generic' : generic} |
|
|
add_app(self.config, section, app) |
|
|
self.restart() |
|
|
|
|
|
def del_item_from_section(self, section, app): |
|
|
del_app(self.config, section, app) |
|
|
self.restart() |
|
|
|
|
|
def mod_app_name(self, widget, event, dialog, section, app): |
|
|
newname = widget.get_text().strip() |
|
|
if len(newname) != 0: |
|
|
mod_app(self.config, section, app, newname) |
|
|
self.restart() |
|
|
dialog.destroy() |
|
|
|
|
|
def mod_app_icon_dialog(self, widget, event, dialog, section, app): |
|
|
chooser = Gtk.FileChooserDialog(title=("Choisir une icône")) |
|
|
chooser.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) |
|
|
chooser.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) |
|
|
chooser.set_current_folder(os.getcwd()) |
|
|
filter = Gtk.FileFilter() |
|
|
filter.set_name(("Images")) |
|
|
filter.add_mime_type("image/png") |
|
|
filter.add_mime_type("image/jpeg") |
|
|
chooser.add_filter(filter) |
|
|
|
|
|
response = chooser.run() |
|
|
|
|
|
if response == Gtk.ResponseType.CANCEL: |
|
|
print(("Fermeture : pas de fichiers sélectionnés")) |
|
|
chooser.destroy() |
|
|
elif response == Gtk.ResponseType.OK: |
|
|
i = chooser.get_filename() |
|
|
chooser.destroy() |
|
|
mod_app_icon(self.config, section, app, i) |
|
|
self.restart() |
|
|
|
|
|
dialog.destroy() |
|
|
|
|
|
def move_app_up(self, widget, dialog, section, app): |
|
|
move_app(self.config, section, app, -1) |
|
|
dialog.destroy() |
|
|
self.restart() |
|
|
|
|
|
def move_app_down(self, widget, dialog, section, app): |
|
|
move_app(self.config, section, app, 1) |
|
|
dialog.destroy() |
|
|
self.restart() |
|
|
|
|
|
def handle_drop(self, data, section): |
|
|
'''handle drag n drop to add to configuration''' |
|
|
if data.startswith('file://'): |
|
|
f = data.replace("file://", "").strip() |
|
|
if os.path.isdir(f): # parse directories |
|
|
name = os.path.basename(f) |
|
|
cmd = 'exo-open --launch FileManager "{}"'.format(f) |
|
|
icon = "folder" |
|
|
self.add_item_to_section(name, cmd, icon, None, section) |
|
|
elif os.path.isfile(f): # is it file? |
|
|
if data.endswith('.desktop'): # une applicatino |
|
|
name, cmd, icon, generic = get_info_desktop(f) |
|
|
self.add_item_to_section(name, cmd, icon, generic, section) |
|
|
else: |
|
|
name = os.path.basename(f) # un fichier |
|
|
cmd = 'exo-open "{}"'.format(f) |
|
|
#raccourci pour fichier sans icone |
|
|
self.add_item_to_section(name, cmd, "empty", None, section) |
|
|
elif data.startswith("http://") or \ |
|
|
data.startswith("https://") or \ |
|
|
data.startswith("ftp://"): # cas d'une url |
|
|
name = data.split('/')[2] |
|
|
cmd = "exo-open --launch WebBrowser {}".format(data) |
|
|
self.add_item_to_section(name, cmd, "text-html", "Lien vers une url", section) |
|
|
|
|
|
def on_drag_data_received(self, widget, drag_context, x, y, data, info, time, section): |
|
|
if data.get_data_type().name() == "text/uri-list": |
|
|
uris = data.get_uris() |
|
|
for u in uris: |
|
|
self.handle_drop(u, section) |
|
|
drag_context.finish(True, False, time) |
|
|
return(True) |
|
|
|
|
|
def on_drag_motion(self, widgt, context, c, y, time): |
|
|
Gdk.drag_status(context, Gdk.DragAction.COPY, time) |
|
|
return True |
|
|
|
|
|
def on_drag_drop(self, widget, context, x, y, time): |
|
|
widget.drag_get_data(context, context.list_targets()[-1], time) |
|
|
return(True) |
|
|
|
|
|
def del_appli(self, widget, dialog, section, app): |
|
|
self.del_item_from_section(section, app) |
|
|
dialog.destroy() # delete parent |
|
|
|
|
|
def edit_appli(self, widget, event, section, app): |
|
|
d = Gtk.Dialog(title=("Éditer le lanceur")) |
|
|
# Edition du nom de l'appli |
|
|
entry = Gtk.Entry() |
|
|
entry.connect("activate", self.mod_app_name, entry, d, section, app) # entrée valide |
|
|
entry.show() |
|
|
|
|
|
namebtn = Gtk.Button(label = ("Changer")) |
|
|
namebtn.connect_object("clicked", self.mod_app_name, entry, None, d, section, app ) |
|
|
namebtn.show() |
|
|
|
|
|
# on met ça dans une boîte |
|
|
box = Gtk.HBox(False,2) |
|
|
box.pack_start(entry, True, True, 3) |
|
|
box.pack_start(namebtn, False, False, 0) |
|
|
box.show() |
|
|
|
|
|
# et le tout dans un étiquette |
|
|
nameframe = Gtk.Frame(label = ("Changer le nom")) |
|
|
nameframe.add(box) |
|
|
nameframe.show() |
|
|
|
|
|
# Changement de l'icône |
|
|
iconbtn = Gtk.Button(label = ("Changer l'icône")) |
|
|
iconbtn.connect_object("clicked", self.mod_app_icon_dialog, entry, None, d, section, app ) |
|
|
iconbtn.show() |
|
|
|
|
|
# on met ça dans une boîte |
|
|
# et le tout dans un étiquette |
|
|
iconframe = Gtk.Frame(label = ("Changer l'icône de l'application")) |
|
|
iconframe.add(iconbtn) |
|
|
iconframe.show() |
|
|
|
|
|
# déplacement de l'application |
|
|
upbtn = Gtk.Button(label=("Monter")) |
|
|
downbtn = Gtk.Button(label=("Descendre")) |
|
|
|
|
|
upi = Gtk.Image() |
|
|
upi.set_from_stock(Gtk.STOCK_GO_UP, Gtk.IconSize.MENU) |
|
|
upbtn.set_image(upi) |
|
|
downi = Gtk.Image() |
|
|
downi.set_from_stock(Gtk.STOCK_GO_DOWN, Gtk.IconSize.MENU) |
|
|
downbtn.set_image(downi) |
|
|
|
|
|
upbtn.connect_object("clicked", self.move_app_up, None, d, section, app) |
|
|
downbtn.connect_object("clicked", self.move_app_down, None, d, section, app) |
|
|
|
|
|
upbtn.show() |
|
|
downbtn.show() |
|
|
|
|
|
# on met ça dans une boîte |
|
|
box = Gtk.HBox(False,2) |
|
|
box.pack_start(upbtn, True, True, 3) |
|
|
box.pack_start(downbtn, False, False, 0) |
|
|
box.show() |
|
|
|
|
|
# et le tout dans un étiquette |
|
|
moveframe = Gtk.Frame(label = ("Déplacer ce lanceur")) |
|
|
moveframe.add(box) |
|
|
moveframe.show() |
|
|
|
|
|
# Nécessaire pour la suppression |
|
|
delbtn = Gtk.Button(label = ("Supprimer"), stock=Gtk.STOCK_DELETE) |
|
|
delbtn.connect("clicked", self.del_appli, d, section, app) |
|
|
delbtn.show() |
|
|
delframe = Gtk.Frame(label = ("Supprimer ce lanceur")) |
|
|
delframe.add(delbtn) |
|
|
delframe.show() |
|
|
|
|
|
# ajout des objets au dialogue |
|
|
d.vbox.pack_start(nameframe, True, True, 0) |
|
|
d.vbox.pack_start(iconframe, True, True, 0) |
|
|
d.vbox.pack_start(moveframe, True, True, 0) |
|
|
d.vbox.pack_start(delframe, True, True, 0) |
|
|
d.run() |
|
|
|
|
|
def make_entrylist(self): |
|
|
self.section_list = Gtk.Notebook() |
|
|
self.section_list.set_tab_pos(Gtk.PositionType.LEFT) |
|
|
self.section_list.set_scrollable(True) |
|
|
|
|
|
for s in self.config: |
|
|
label = Gtk.Label(s['name']) |
|
|
applist = Gtk.VBox() |
|
|
|
|
|
scrolled_window = Gtk.ScrolledWindow() |
|
|
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) |
|
|
scrolled_window.set_size_request(620,-1) |
|
|
self.section_list.append_page(scrolled_window, label) |
|
|
|
|
|
# pour ajouter des applications |
|
|
scrolled_window.drag_dest_set(0, [], 0) |
|
|
scrolled_window.drag_dest_add_text_targets() |
|
|
scrolled_window.drag_dest_add_uri_targets() |
|
|
scrolled_window.connect("drag-data-received", self.on_drag_data_received, s) |
|
|
scrolled_window.connect("drag-drop", self.on_drag_drop) |
|
|
scrolled_window.connect('drag-motion', self.on_drag_motion) |
|
|
|
|
|
# boutons de config |
|
|
hb = Gtk.HBox(False, 10) |
|
|
|
|
|
delbtn = Gtk.Button(label = ("Supprimer cette section")) |
|
|
delbtn.connect_object("clicked", self.del_section, s) |
|
|
|
|
|
addbtn = Gtk.Button(label= ("Rechercher une application")) |
|
|
addbtn.connect("button_press_event", self.appfinder) |
|
|
|
|
|
hb.pack_start(addbtn, True, True, 0) |
|
|
hb.pack_start(delbtn, True, True, 0) |
|
|
|
|
|
if self.config.index(s) > 0: |
|
|
upbtn = Gtk.Button(label = ("Monter la section")) |
|
|
upbtn.connect_object("clicked", self.move_sec, s, -1) |
|
|
hb.pack_start(upbtn, True, True, 0) |
|
|
if self.config.index(s) < len(self.config)-1: |
|
|
downbtn = Gtk.Button(label = ("Descendre la section")) |
|
|
downbtn.connect_object("clicked", self.move_sec, s, +1) |
|
|
hb.pack_start(downbtn, True, True, 0) |
|
|
|
|
|
applist.pack_start(hb, False,False, 10) |
|
|
|
|
|
dragdrophelp = Gtk.Label(("Pour ajouter une application, glissez-la dans la liste")) |
|
|
applist.pack_start(dragdrophelp, False,False, 2) |
|
|
|
|
|
for a in s['apps']: |
|
|
appname, icon, cmd= a['name'], a['icon'], a['cmd'] |
|
|
image = Gtk.Image() |
|
|
if icon.endswith('.png') or icon.endswith('.jpg'): |
|
|
image.set_from_file(icon) |
|
|
else: |
|
|
image.set_from_icon_name(icon, iconsize) |
|
|
image.set_from_icon_name(icon, Gtk.IconSize.DIALOG) |
|
|
image.set_pixel_size(iconsize) |
|
|
# nom de l'appli |
|
|
bapp = Gtk.Button(label=appname) |
|
|
bapp.set_image(image) |
|
|
#l'image est au dessus du texte |
|
|
bapp.set_image_position(Gtk.PositionType.TOP) |
|
|
# apparence du bouton |
|
|
bapp.set_relief(Gtk.ReliefStyle.NONE) |
|
|
bapp.connect("button_release_event", self.edit_appli, s, a) |
|
|
applist.pack_start(bapp, True, True, 0) |
|
|
|
|
|
scrolled_window.add_with_viewport(applist) |
|
|
|
|
|
# ajout de la possibilité d'ajouter des sections |
|
|
addbox = Gtk.VBox() |
|
|
instruction = Gtk.Label(("Nom de la nouvelle section : ")) |
|
|
entry = Gtk.Entry() |
|
|
entry.connect("activate", self.add_new_section) # entrée valide |
|
|
addbox.pack_start(instruction, False, True, 3) |
|
|
addbox.pack_start(entry, False, False, 20) |
|
|
|
|
|
addbtn = Gtk.Button(label = ("Plus"), stock=Gtk.STOCK_ADD) |
|
|
addbtn.connect_object("clicked", self.add_new_section, entry ) |
|
|
addbox.pack_start(addbtn, False, False, 10) |
|
|
|
|
|
addlabel = Gtk.Image() |
|
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(os.path.join(handy_icons,"add_section.png")) |
|
|
scaled_buf = pixbuf.scale_simple(24,24,GdkPixbuf.InterpType.BILINEAR) |
|
|
addlabel.set_from_pixbuf(scaled_buf) |
|
|
addlabel.set_tooltip_text(("Ajouter une section")) |
|
|
self.section_list.append_page(addbox, addlabel) |
|
|
|
|
|
self.mainbox.pack_start(self.section_list, True, True, 0) |
|
|
|
|
|
def module_toggle(self, widget, module): |
|
|
if widget.get_active(): |
|
|
add_module(module) |
|
|
else: |
|
|
del_module(module) |
|
|
|
|
|
def make_menu(self, initialize = True): |
|
|
"""build the menu""" |
|
|
if initialize : |
|
|
self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL) |
|
|
self.window.connect("delete_event", self.close_application) |
|
|
|
|
|
self.window.set_title("Configuration du HandyMenu") |
|
|
self.window.set_border_width(0) |
|
|
else: |
|
|
self.window.remove(self.mainbox) |
|
|
|
|
|
# Conteneur principal |
|
|
self.mainbox = Gtk.VBox(False, 10) |
|
|
self.mainbox.set_border_width(10) |
|
|
|
|
|
# configuration principale |
|
|
self.make_entrylist() |
|
|
|
|
|
# extra options |
|
|
extrabox = Gtk.HBox(False, 5) |
|
|
self.mainbox.pack_start(extrabox, False, False, 0) |
|
|
|
|
|
# coches pour modules |
|
|
modulesbox = Gtk.HBox(False, 5) |
|
|
modulesframe = Gtk.Frame(label = ("Modules")) |
|
|
modulesframe.add(modulesbox) |
|
|
extrabox.pack_start(modulesframe, False, False, 0) |
|
|
|
|
|
recents_files_check = Gtk.CheckButton(("Afficher les fichiers récents")) |
|
|
recents_files_check.set_tooltip_text(("Afficher les fichiers récents")) |
|
|
if "_recent_files_" in load_modules()[1]: |
|
|
recents_files_check.set_active(True) |
|
|
recents_files_check.connect("toggled", self.module_toggle, "_recent_files_") |
|
|
modulesbox.pack_start(recents_files_check, False, False,0) |
|
|
|
|
|
# module firefox most viewed |
|
|
#most_ffox_check = Gtk.CheckButton(_("Most visited")) |
|
|
#most_ffox_check.set_tooltip_text(_("Show most visited uri")) |
|
|
#if "_most_ffox_view_" in load_modules()[1]: |
|
|
# most_ffox_check.set_active(True) |
|
|
#most_ffox_check.connect("toggled", self.module_toggle, "_most_ffox_view_") |
|
|
#modulesbox.pack_start(most_ffox_check, False, False,0) |
|
|
|
|
|
# position des modules |
|
|
self.modules_position = Gtk.SpinButton() |
|
|
#adjustment = Gtk.Adjustment(0, start, max, step, 10, 0) |
|
|
adjustment = Gtk.Adjustment(0, 1, len(self.config)+1, 1, 10, 0) |
|
|
self.modules_position.set_adjustment(adjustment) |
|
|
self.modules_position.set_numeric(True) |
|
|
self.modules_position.set_value(load_modules()[0]) |
|
|
self.modules_position.set_tooltip_text(("Position des modules dans le menu")) |
|
|
self.modules_position.connect("value-changed", \ |
|
|
lambda x: set_modules_position(self.modules_position.get_value_as_int())) |
|
|
modulesbox.pack_start(self.modules_position, False, False,1) |
|
|
|
|
|
# conteneur pour les boutons |
|
|
btnbox = Gtk.HBox(True, 2) |
|
|
self.mainbox.pack_start(btnbox, False, False, 0) |
|
|
|
|
|
aboutbtn = Gtk.Button().new_from_icon_name("stock_about", Gtk.IconSize.BUTTON) |
|
|
aboutbtn.connect("clicked", lambda x: self.about()) |
|
|
btnbox.pack_start(aboutbtn, False, False, 0) |
|
|
|
|
|
defaultbtn = Gtk.Button(label = ("Réinitialiser")) |
|
|
resetimg = Gtk.Image() |
|
|
resetimg.set_from_stock(Gtk.STOCK_REDO, Gtk.IconSize.BUTTON) |
|
|
defaultbtn.set_image(resetimg) |
|
|
defaultbtn.connect_object("clicked", self.back_to_default, self.window ) |
|
|
btnbox.pack_start(defaultbtn, True, True,0) |
|
|
|
|
|
viewbtn = Gtk.Button(label = ("Afficher la configuration")) |
|
|
viewbtn.connect("clicked", lambda x: self.view_config()) |
|
|
btnbox.pack_start(viewbtn, True, True, 0) |
|
|
|
|
|
savebtn = Gtk.Button(label = ("Quitter"), stock=Gtk.STOCK_CLOSE) |
|
|
savebtn.connect_object("clicked", self.close_application, self.window, None ) |
|
|
btnbox.pack_start(savebtn, True, True, 0) |
|
|
|
|
|
self.window.add(self.mainbox) |
|
|
self.window.set_default_size(620, 560) |
|
|
self.window.show_all() |
|
|
|
|
|
def __init__(self): |
|
|
self.config = load_config() |
|
|
self.make_menu() |
|
|
|
|
|
def main(): |
|
|
menu = HandymenuConfig() |
|
|
Gtk.main() |
|
|
return 0 |
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |
|
|
|
|
|
|
|
|
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
|
|
|