#!/usr/bin/python3
import gi, os, re, sys, jwmkit_utils
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf
import xml.etree.ElementTree as ET

# JWM Kit - A set of Graphical Apps to simplify use of JWM (Joe's Window Manager) <https://codeberg.org/JWMKit/JWM_Kit>
# Copyright © 2020-2022 Calvin Kent McNabb <apps.jwmkit@gmail.com>
#
# This file is part of JWM Kit.
#
# JWM Kit is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# JWM Kit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with JWM Kit.  If not, see <https://www.gnu.org/licenses/>.


def warning_settings(main_box):
    def clear_boxes(button):
        main_box.remove(prompt_box)
    message = "<big><b>!!! NOTICE !!! </b></big> Reverting to the default icon set.\nSettings file is missing," \
              " incomplete or damaged. Use JWM Kit Repair &amp; Restore to repair the settings file" \
              "\n...or you can do it manually if you like."
    prompt_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
    image_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
    center_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
    main_box.add(prompt_box)
    prompt_box.pack_start(image_box, True, True, 5)
    prompt_box.pack_start(center_box, True, True, 0)
    image = Gtk.Image()
    pb = GdkPixbuf.Pixbuf.new_from_file_at_scale('/usr/share/pixmaps/jwmkit/info_yellow.svg', 48, 48,
                                                 preserve_aspect_ratio=False)
    image.set_from_pixbuf(pb)
    image_box.add(image)
    message_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
    center_box.add(message_box)
    label = Gtk.Label()
    label.set_markup(message)
    message_box.add(label)
    ok_button = Gtk.Button(label='OK', image=Gtk.Image(stock=Gtk.STOCK_OK))
    ok_button.connect("clicked", clear_boxes)
    ok_button.set_property("width-request", 120)
    message_box.pack_end(ok_button, False, False, 5)
    center_box.add(Gtk.Label())
    return


def read_desktop(filename):
    def get_action_data():
        try:
            action_titles = re.findall('\n\[Desktop Action ([^\]]*)', appdata)
        except IndexError:
            action_titles = []
        try:
            actions_enabled = re.findall('\nActions=(.*)', appdata)[0]
        except IndexError:
            actions_enabled = ''
        keys, data = ['Name', 'Exec', 'Icon'], []
        if action_titles:
            for action_title in action_titles:
                action_data = re.findall('(?s)(\[Desktop Action ' +
                                         re.escape(action_title) + '\].+?(?=\[Desktop|\Z))', appdata, re.MULTILINE)[0]
                info = []
                for key in keys:
                    try:
                        info.append(re.findall('\n%s=(.*)' % key, action_data)[0])
                    except IndexError:
                        info.append('')
                if action_title in actions_enabled:
                    data.append([True, action_title, info[0], info[1], info[2], info[2]])
                else:
                    data.append([False, action_title, info[0], info[1], info[2], info[2]])
        return data

    def get_appdata():
        try:
            with open(filename) as f:
                data = f.read()
        except FileNotFoundError:
            data = ''
        return data

    def get_values():
        keys = ['Comment', 'Exec', 'Path', 'Categories', 'GenericName', 'TryExec', 'OnlyShowIn',
                'NotShowIn', 'MimeType', 'Keywords', 'StartupWMClass', 'Implements']
        values = []
        for key in keys:
            try:
                values.append(re.findall('\n%s=(.*)' % key, appdata)[0])
            except IndexError:
                values.append('')
        return values

    def get_tf_values():
        keys, data = ['Terminal', 'StartupNotify', 'Hidden', 'DBusActivatable'], []
        for key in keys:
            if re.findall('%s=true' % key, appdata):
                data.append(True)
            else:
                data.append(False)
        return data

    appdata = get_appdata()
    action_info = get_action_data()
    try:
        appdata = re.findall('(?s)(\[Desktop Entry\].+?(?=\[Desktop|\Z))', appdata, re.MULTILINE)[0]
    except IndexError:
        appdata = ''
    return get_values(), get_tf_values(), action_info


class MenusWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="JWM Kit Freedesktops")
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        self.add(main_box)
        self.set_border_width(15)
        try:
            self.set_icon_from_file('/usr/share/pixmaps/jwmkit/config.svg')
        except gi.repository.GLib.Error:
            self.set_icon_name('edit-paste')

        self.home = os.path.expanduser('~')
        self.xdg_data = self.get_xdg_data()
        self.cat_selection, self.save_index, self.data = 0, 0, []
        self.default_icons = True
        self.lang = os.getenv('LANG')[:3].replace('_', '')

        if len(sys.argv) > 1:
            if sys.argv[1].lower() in ['jwm', '-jwm', '--jwm']:
                self.jwm_icon_paths = self.get_icon_paths()
            if self.jwm_icon_paths == 'warning_settings':
                warning_settings(main_box)
            elif self.jwm_icon_paths not in ['', None]:
                self.default_icons = False

        main_top_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        main_mid_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        main__bottom_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)

        left_header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        mid_header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        right_header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)

        mid_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        mid_mid = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        mid_right = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        mid_right.set_property("width-request", 300)

        main_box.pack_start(main_top_box, True, True, 0)
        main_box.pack_start(main_mid_box, True, True, 0)
        main_box.pack_start(main__bottom_box, True, True, 0)

        main_mid_box.pack_start(mid_left, True, True, 5)
        main_mid_box.pack_start(mid_mid, True, True, 5)
        main_mid_box.pack_start(mid_right, True, True, 5)

        self.cat_icon = Gtk.Image()
        self.cat_label = Gtk.Label()
        self.app_icon = Gtk.Image()
        mid_header_box.pack_start(self.cat_icon, False, False, 0)
        mid_header_box.pack_start(self.cat_label, False, False, 10)
        mid_left.pack_start(left_header_box, False, False, 0)
        mid_mid.add(mid_header_box)
        mid_right.add(right_header_box)
        scroll_mid_mid = Gtk.ScrolledWindow()
        scroll_mid_mid.set_min_content_width(280)
        scroll_mid_mid.set_min_content_height(600)
        mid_mid.pack_start(scroll_mid_mid, True, True, 0)

        self.listbox_mid_mid = Gtk.ListBox()
        self.listbox_mid_mid.set_selection_mode(Gtk.SelectionMode.SINGLE)
        self.listbox_mid_mid.connect("row-activated", self.listbox_changed)
        scroll_mid_mid.add(self.listbox_mid_mid)

        accessories_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-accessories', Gtk.IconSize.BUTTON), label="Accessories", xalign=0)
        edu_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-education', Gtk.IconSize.BUTTON), label="Education", xalign=0)
        dev_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-development', Gtk.IconSize.BUTTON), label="Development", xalign=0)
        game_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-games', Gtk.IconSize.BUTTON), label="Games", xalign=0)
        graphics_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-graphics', Gtk.IconSize.BUTTON), label="Graphics", xalign=0)
        internet_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-internet', Gtk.IconSize.BUTTON), label="Internet", xalign=0)
        av_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-multimedia', Gtk.IconSize.BUTTON), label="Multimedia", xalign=0)
        office_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-office', Gtk.IconSize.BUTTON), label="Office", xalign=0)
        science_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-science', Gtk.IconSize.BUTTON), label="Science", xalign=0)
        settings_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('preferences-system', Gtk.IconSize.BUTTON), label="Settings", xalign=0)
        system_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-system', Gtk.IconSize.BUTTON), label="System", xalign=0)
        other_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('applications-other', Gtk.IconSize.BUTTON), label="Other", xalign=0)
        hidden_button = Gtk.Button(image=Gtk.Image.new_from_icon_name
        ('system-help', Gtk.IconSize.BUTTON), label="Hidden", xalign=0)

        buttons = [accessories_button, edu_button, dev_button, game_button, graphics_button, internet_button,
                   av_button, office_button, science_button, settings_button, system_button, other_button,
                   hidden_button]

        for i, button in enumerate(buttons):
            button.set_property("width-request", 120)
            button.set_relief(Gtk.ReliefStyle.NONE)
            button.connect('clicked', self.populate_listbox, i)
            button.set_always_show_image(True)
            button.set_no_show_all(True)
            button.set_visible(True)
            if len(self.xdg_data[i]) == 0: button.set_visible(False)
            mid_left.add(button)

        mid_left.add(Gtk.Separator())
        h_separator_row = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        h_separator_row.add(Gtk.Label())
        name_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        icon_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        comment_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        command_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        work_dir_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        terminal_run_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        start_notice_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        hide_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)

        icon_button = Gtk.Button()
        icon_button.set_tooltip_text('Click to update icon preview')
        icon_button.set_relief(Gtk.ReliefStyle.NONE)
        icon_button.set_image(self.app_icon)
        icon_button.set_always_show_image(True)

        save_button = Gtk.Button(label="Save", image=Gtk.Image(stock=Gtk.STOCK_SAVE))
        save_button.set_tooltip_text('Save Changes')
        save_button.set_property("width-request", 120)
        save_button.set_always_show_image(True)
        save_button.connect("clicked", self.on_save, buttons)

        add_new_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ADD))
        self.remove_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_REMOVE))
        launch_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_EXECUTE))
        about_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ABOUT))

        top_buttons = [[add_new_button, 'Create a new launcher', self.create_launcher],
                       [self.remove_button, '', self.delete_launcher, buttons],
                       [launch_button, 'Test launcher', self.test_launch],
                       [about_button, 'About', jwmkit_utils.get_about, self]]

        for button in top_buttons:
            button[0].set_always_show_image(True)
            button[0].set_tooltip_text(button[1])
            if len(button) == 4:
                button[0].connect('clicked', button[2], button[3])
            else:
                button[0].connect('clicked', button[2])
            left_header_box.pack_start(button[0], False, False, 0)

        self.name_entry = Gtk.Entry()
        self.icon_entry = Gtk.Entry()
        self.comment_entry = Gtk.Entry()
        self.command_entry = Gtk.Entry()
        self.work_dir_entry = Gtk.Entry()
        self.cat_entry = Gtk.Entry()
        self.cat_check = Gtk.CheckButton(label='Categories')
        self.cat_check.set_tooltip_text('Choose buttons or manual entry for Category data.')
        self.cat_check.connect("toggled", self.on_cat_check)
        self.cat_entry.set_sensitive(False)

        self.command_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'system-file-manager')
        self.work_dir_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'system-file-manager')
        self.icon_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'system-file-manager')

        self.command_entry.connect('icon-press', self.browse_command_wrapper, 'exec')
        self.work_dir_entry.connect('icon-press', self.browse_command_wrapper, 'path')
        self.icon_entry.connect('icon-press', self.browse_command_wrapper, 'icon')
        self.icon_entry.connect('activate', self.update_app_icon, '')
        icon_button.connect("clicked", self.update_app_icon, '')

        self.name_entry.set_property("width-request", 240)
        self.icon_entry.set_property("width-request", 240)
        self.comment_entry.set_property("width-request", 240)
        self.command_entry.set_property("width-request", 240)
        self.work_dir_entry.set_property("width-request", 240)

        self.terminal_run_switch = Gtk.Switch()
        self.start_notice_switch = Gtk.Switch()
        self.hide_switch = Gtk.Switch()

        right_header_box.pack_end(save_button, False, False, 0)
        right_header_box.pack_end(Gtk.Label(), False, False, 40)
        right_header_box.pack_end(icon_button, False, False, 0)
        name_row.pack_end(self.name_entry, False, False, 0)
        name_row.pack_end(Gtk.Label(label='Name:'), False, False, 0)
        comment_row.pack_end(self.comment_entry, False, False, 0)
        comment_row.pack_end(Gtk.Label(label='Comment:'), False, False, 0)
        icon_row.pack_end(self.icon_entry, False, False, 0)
        icon_row.pack_end(Gtk.Label(label='Icon:'), False, False, 0)
        command_row.pack_end(self.command_entry, False, False, 0)
        command_row.pack_end(Gtk.Label(label='Command:'), False, False, 0)
        work_dir_row.pack_end(self.work_dir_entry, False, False, 0)
        work_dir_row.pack_end(Gtk.Label(label='Working Directory:'), False, False, 0)
        terminal_run_row.pack_end(self.terminal_run_switch, False, False, 20)
        terminal_run_row.pack_end(Gtk.Label(label='Run in Terminal'), False, False, 30)
        start_notice_row.pack_end(self.start_notice_switch, False, False, 20)
        start_notice_row.pack_end(Gtk.Label(label='Use startup notification'), False, False, 30)
        hide_row.pack_end(self.hide_switch, False, False, 20)
        hide_row.pack_end(Gtk.Label(label='Do not show'), False, False, 30)

        mid_right.add(h_separator_row)
        mid_right.add(name_row)
        mid_right.add(comment_row)
        mid_right.add(icon_row)
        mid_right.add(command_row)
        mid_right.add(work_dir_row)
        mid_right.add(Gtk.Label())
        mid_right.add(terminal_run_row)
        mid_right.add(start_notice_row)
        mid_right.add(hide_row)
        mid_right.add(Gtk.Label())

        notebook = Gtk.Notebook()
        cat_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        action_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        adv_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        adv_scroll = Gtk.ScrolledWindow()
        adv_scroll.add(adv_page)

        notebook.append_page(cat_page, Gtk.Label(label='Categories'))
        notebook.append_page(action_page, Gtk.Label(label='Actions'))
        notebook.append_page(adv_scroll, Gtk.Label(label='Advanced'))

        self.cat_utility = Gtk.ToggleButton(label="Accessories")
        self.cat_dev = Gtk.ToggleButton(label="Development")
        self.cat_edu = Gtk.ToggleButton(label="Education")
        self.cat_game = Gtk.ToggleButton(label="Game")
        self.cat_graphic = Gtk.ToggleButton(label="Graphics")
        self.cat_net = Gtk.ToggleButton(label="Network")
        self.cat_media = Gtk.ToggleButton(label="Multimedia")
        self.cat_office = Gtk.ToggleButton(label="Office")
        self.cat_sci = Gtk.ToggleButton(label="Science")
        self.cat_settings = Gtk.ToggleButton(label="Settings")
        self.cat_sys = Gtk.ToggleButton(label="System")
        self.cat_odd = Gtk.ToggleButton(label="Other")

        buttons = [self.cat_utility, self.cat_dev, self.cat_edu, self.cat_game, self.cat_graphic, self.cat_net,
                   self.cat_media, self.cat_office, self.cat_sci, self.cat_settings, self.cat_sys, self.cat_odd]
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        cat_page.add(row)
        index = 0
        for button in buttons:
            index += 1
            if index == 1:
                row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                cat_page.add(row)
            button.set_property("width-request", 120)
            row.pack_start(button, False, False, 0)
            if index == 3:
                index = 0
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        cat_page.add(row)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.pack_end(self.cat_entry, True, True, 0)
        row.pack_end(self.cat_check, False, False, 0)
        cat_page.add(row)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        cat_page.add(row)

        self.action_store = Gtk.ListStore(bool, str, str, str, str, GdkPixbuf.Pixbuf)
        self.action_tree_view = Gtk.TreeView(model=self.action_store)
        renderer_toggle = Gtk.CellRendererToggle()
        renderer_toggle.connect("toggled", self.toggle_cell)
        column_toggle = Gtk.TreeViewColumn("Show", renderer_toggle, active=0)
        self.action_tree_view.append_column(column_toggle)

        renderer_text = Gtk.CellRendererText()
        renderer_text.set_property("editable", True)
        renderer_text.connect("edited", self.edit_cell_text, 2)
        column_text = Gtk.TreeViewColumn("Name", renderer_text, text=2)
        self.action_tree_view.append_column(column_text)

        renderer_text = Gtk.CellRendererText()
        renderer_text.set_property("editable", True)
        renderer_text.connect("edited", self.edit_cell_text, 3)
        column_text = Gtk.TreeViewColumn("Command", renderer_text, text=3)
        self.action_tree_view.append_column(column_text)

        renderer_pixbuf = Gtk.CellRendererPixbuf()
        column_pixbuf = Gtk.TreeViewColumn("Icon", renderer_pixbuf, pixbuf=5)
        self.action_tree_view.append_column(column_pixbuf)

        renderer_text = Gtk.CellRendererText()
        renderer_text.set_property("editable", True)
        renderer_text.connect("edited", self.edit_cell_text, 4)
        column_text = Gtk.TreeViewColumn("Icon Name", renderer_text, text=4)
        self.action_tree_view.append_column(column_text)

        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        action_page.add(row)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        action_scroll = Gtk.ScrolledWindow()
        action_scroll.add(self.action_tree_view)
        row.pack_start(action_scroll, True, True, 10)
        action_page.pack_start(row, True, True, 0)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label(label=' '))

        action_add_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ADD))
        action_remove_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_REMOVE))
        action_up_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_GO_UP))
        action_down_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_GO_DOWN))

        buttons = [[action_add_button, 'Create a action'], [action_remove_button, 'Remove selected action'],
                   [action_up_button, 'Move action up'], [action_down_button, 'Move action down']]
        for button in buttons:
            button[0].set_always_show_image(True)
            button[0].set_tooltip_text(button[1])
            row.add(button[0])
        action_page.pack_start(row, False, True, 0)
        action_add_button.connect("clicked", self.add_action_row)
        action_remove_button.connect("clicked", self.delete_action_row)
        action_up_button.connect("clicked", self.action_move_up)
        action_down_button.connect("clicked", self.action_move_down)

        generic_label = Gtk.Label(label="Generic Name: ")
        self.generic_entry = Gtk.Entry()
        try_exec_label = Gtk.Label(label="Try Exec: ")
        self.try_exec_entry = Gtk.Entry()
        only_show_label = Gtk.Label(label="Only Show In: ")
        self.only_show_entry = Gtk.Entry()
        not_shown_label = Gtk.Label(label="Not Shown In: ")
        self.not_shown_entry = Gtk.Entry()
        mime_label = Gtk.Label(label="Mimetypes: ")
        self.mime_entry = Gtk.Entry()
        keywords_label = Gtk.Label(label="Keywords: ")
        self.keywords_entry = Gtk.Entry()
        wm_class_label = Gtk.Label(label="Startup WM Class: ")
        self.wm_class_entry = Gtk.Entry()
        implements_label = Gtk.Label(label="Implements: ")
        self.implements_entry = Gtk.Entry()

        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        adv_page.add(row)
        entries = [[generic_label, self.generic_entry, ], [try_exec_label, self.try_exec_entry],
                   [only_show_label, self.only_show_entry], [not_shown_label, self.not_shown_entry],
                   [mime_label, self.mime_entry], [keywords_label, self.keywords_entry],
                   [wm_class_label, self.wm_class_entry], [implements_label, self.implements_entry]]
        for entry in entries:
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
            entry[1].set_property("width-request", 210)
            row.pack_end(entry[1], False, False, 10)
            row.pack_end(entry[0], False, False, 10)
            adv_page.add(row)

        hidden_label = Gtk.Label(label="Hidden:")
        self.hidden_switch = Gtk.Switch()
        dbus_label = Gtk.Label(label="DBUS Activatable:")
        self.dbus_switch = Gtk.Switch()
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.pack_start(hidden_label, False, False, 10)
        row.pack_start(self.hidden_switch, False, False, 0)
        row.pack_end(self.dbus_switch, False, False, 10)
        row.pack_end(dbus_label, False, False, 0)
        adv_page.add(row)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        adv_page.add(row)
        mid_right.pack_end(notebook, True, True, 0)
        for i in enumerate(self.xdg_data):
            if len(i[1]) != 0:
                break
        self.populate_listbox('', i[0])

    def on_cat_check(self, check):
        buttons = [self.cat_utility, self.cat_dev, self.cat_edu, self.cat_game, self.cat_graphic, self.cat_net,
                   self.cat_media, self.cat_office, self.cat_sci, self.cat_settings, self.cat_sys, self.cat_odd]
        if check.get_active():
            self.cat_entry.set_sensitive(True)
            for button in buttons:
                button.set_sensitive(False)
        else:
            self.cat_entry.set_sensitive(False)
            for button in buttons:
                button.set_sensitive(True)

    def populate_listbox(self, button, index):
        cat_list = ['Accessories', 'Education', 'Development', 'Games', 'Graphics', 'Internet',
                    'Multimedia', 'Office', 'Science', 'Settings', 'System', 'Other', 'Hidden']
        icon_list = ['applications-accessories', 'applications-education', 'applications-development',
                     'applications-games', 'applications-graphics', 'applications-internet',
                     'applications-multimedia', 'applications-office', 'applications-science', 'preferences-system',
                     'applications-system', 'applications-other', 'system-help']

        self.cat_selection = index
        self.clear_list()
        self.cat_label.set_markup('<big><b>' + cat_list[index] + '</b></big>')
        self.cat_icon.set_from_icon_name(icon_list[index], Gtk.IconSize.DND)

        for i in self.xdg_data[index]:
            if isinstance(i, list):
                row = Gtk.ListBoxRow()
                row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                icon = i[1]
                image = Gtk.Image()
                image.set_from_pixbuf(self.update_icon(icon, 24))
                row_box.pack_start(image, False, False, 0)
                row_box.pack_start(Gtk.Label(label=i[0]), False, False, 0)
                row.add(row_box)
                self.listbox_mid_mid.insert(row, -1)
        self.listbox_mid_mid.show_all()
        self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(0))
        self.listbox_changed(self.listbox_mid_mid, self.listbox_mid_mid.get_row_at_index(0))

    def set_cat_toggle(self, cats):
        buttons = [[self.cat_utility, 'Utility'], [self.cat_dev, 'Development'], [self.cat_edu, 'Education'],
                   [self.cat_game, 'Game'], [self.cat_graphic, 'Graphics'], [self.cat_net, 'Network'],
                   [self.cat_media, 'AudioVideo'], [self.cat_office, 'Office'], [self.cat_sci, 'Science'],
                   [self.cat_settings, 'Settings'], [self.cat_sys, 'System'], [self.cat_odd, 'Other']]
        for button in buttons:
            if button[1] in cats:
                button[0].set_active(True)
            else:
                button[0].set_active(False)

    def listbox_changed(self, listbox, row):
        index = row.get_index()
        dot_desktop = self.xdg_data[self.cat_selection][index][2]
        if dot_desktop == '':
            self.remove_button.set_tooltip_text('Delete this launcher')
        elif self.home not in dot_desktop:
            self.remove_button.set_tooltip_text('You do not have permission to delete this launcher')
        else:
            self.remove_button.set_tooltip_text('Delete this launcher')
        self.name_entry.set_text((self.xdg_data[self.cat_selection][index][0]))
        current_icon = self.xdg_data[self.cat_selection][index][1]
        self.icon_entry.set_text(current_icon)
        self.update_app_icon('', current_icon)
        self.data = read_desktop(dot_desktop)
        if dot_desktop == '':
            cats = ['Utility', 'Education', 'Development', 'Game', 'Graphics', 'Network',
                    'AudioVideo', 'Office', 'Science', 'Settings', 'System', 'Other', 'Hidden']
            self.data[0][3] = ''.join([cats[self.cat_selection], ';'])

        self.comment_entry.set_text(self.data[0][0])
        self.command_entry.set_text(self.data[0][1])
        self.work_dir_entry.set_text(self.data[0][2])
        self.cat_entry.set_text(self.data[0][3])
        self.terminal_run_switch.set_active(self.data[1][0])
        self.start_notice_switch.set_active(self.data[1][1])
        if self.cat_selection == 12:
            self.hide_switch.set_active(True)
        else:
            self.hide_switch.set_active(False)
        cats = self.data[0][3].split(';')
        self.set_cat_toggle(cats)
        self.generic_entry.set_text(self.data[0][4])
        self.try_exec_entry.set_text(self.data[0][5])
        self.only_show_entry.set_text(self.data[0][6])
        self.not_shown_entry.set_text(self.data[0][7])
        self.mime_entry.set_text(self.data[0][8])
        self.keywords_entry.set_text(self.data[0][9])
        self.wm_class_entry.set_text(self.data[0][10])
        self.implements_entry.set_text(self.data[0][11])
        self.hidden_switch.set_active(self.data[1][2])
        self.dbus_switch.set_active(self.data[1][3])
        self.action_store.clear()
        for item in self.data[2]:
            item[5] = self.update_icon(item[4], 24)
            self.action_store.append(list(item))
        self.save_index = index

    def update_app_icon(self, button, icon):
        # Big app icon next to save button
        if button:
            self.app_icon.set_from_pixbuf(self.update_icon(self.icon_entry.get_text(), 32))
        else:
            self.app_icon.set_from_pixbuf(self.update_icon(icon, 32))

    def update_icon(self, icon, size):
        if not os.path.isfile(icon):
            if '/' in icon:
                icon = ''
            if self.default_icons:
                if Gtk.IconTheme.get_default().has_icon(icon):
                    icon = Gtk.IconTheme.get_default().load_icon(icon, size, Gtk.IconLookupFlags.FORCE_SIZE)
                else:
                    icon = Gtk.IconTheme.get_default().load_icon('image-missing', size, Gtk.IconLookupFlags.FORCE_SIZE)
            else:
                try:
                    icon = self.get_icon_dir(icon)
                    icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon, size, size, preserve_aspect_ratio=False)
                except (IndexError, gi.repository.GLib.Error):
                    icon = Gtk.IconTheme.get_default().load_icon('image-missing', size, Gtk.IconLookupFlags.FORCE_SIZE)
        else:
            try:
                icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon, size, size, preserve_aspect_ratio=False)
            except gi.repository.GLib.Error:
                icon = Gtk.IconTheme.get_default().load_icon('image-missing', size, Gtk.IconLookupFlags.FORCE_SIZE)
        return icon

    def get_icon_dir(self, icon_name):
        # search the icon directories to find the icon
        icons = []
        icon_name = icon_name.replace(' ', '\ ')
        for icon_dir in self.jwm_icon_paths:
            icon_list = os.listdir(icon_dir)
            for icon in ['{}.png'.format(icon_name), '{}.svg'.format(icon_name),
                         '{}.xpm'.format(icon_name), '{}'.format(icon_name)]:
                if icon in icon_list:
                    icons.append(os.path.join(icon_dir, icon))
                    while '' in icons: icons.remove('')
                    if icons:
                        break
        return icons[0]

    def get_icon_paths(self):
        # read settings file to find user defined icons file
        home = os.path.expanduser('~')
        settings = home + '/.config/jwmkit/settings'
        path_ok = False
        if os.path.isfile(settings):
            with open(settings) as f:
                f = f.read()
            f = '\n{}'.format(f)
            try:
                icon_path = re.findall('\nicons.*=(.+)', f)[0]
                if icon_path.startswith('$HOME'):
                    icon_path = home + icon_path[5:]
                path_ok = True
            except IndexError:
                pass
        if not path_ok:
            return 'warning_settings'

        # make a list of icons paths defined in the JWM xml icon file
        try:
            tree = ET.parse(icon_path)
            root = tree.getroot()
            icon_path = []
            for node in root:
                node = node.text
                if node.startswith('$HOME'):
                    node = home + node[5:]
                # if the file exist add it to the list
                if os.path.isdir(node):
                    icon_path.append(node)
        except (ET.ParseError, FileNotFoundError):
            icon_path = []
        return icon_path

    def clear_list(self):
        ok = True
        while ok:
            try:
                self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(0))
                self.listbox_mid_mid.remove(self.listbox_mid_mid.get_selected_rows()[0])
            except IndexError:
                ok = False

    def get_xdg_data(self):
        sys_appdir = '/usr/share/applications/'
        home_appdir = self.home + '/.local/share/applications/'
        if not os.path.isdir(home_appdir):
            os.makedirs(home_appdir)
        applications = sorted(os.listdir(sys_appdir), key=str.lower)
        sys_applications = re.findall("'([^']+?desktop)'", str(applications))
        applications = sorted(os.listdir(home_appdir), key=str.lower)
        home_applications = re.findall("'([^']+?desktop)'", str(applications))
        sys_applications = [i for i in sys_applications if i not in home_applications]
        sys_applications = [sys_appdir + i for i in sys_applications]
        home_applications = [home_appdir + i for i in home_applications]
        applications = sys_applications + home_applications
        jwmoffice, jwmgraphics, jwmautil, jwmgame, jwmav, jwmsys = [], [], [], [], [], []
        jwmset, jwmnet, jwmedu, jwmother, jwmdev, jwmhidden, jwmsci = [], [], [], [], [], [], []

        for application in applications:
            type_value, appdata = '', ''
            with open(application) as f:
                appdata = f.read()
            try:
                appdata = re.findall('(?s)(\[Desktop Entry\].+?(?=\[Desktop|\Z))', appdata, re.MULTILINE)[0]
            except IndexError:
                print(application + ' is incomplete or invalid')
            if appdata:
                try:
                    type_value = re.findall('\nType=(.+)', appdata, re.MULTILINE)[0]
                except IndexError:
                    print(application + ' is not an Application')
            if type_value == 'Application':
                hidden = re.findall('NoDisplay=true', appdata)
                try:
                    name_data = re.findall('\nName=(.*)', appdata)[0]
                except IndexError:
                    name_data = ''
                try:
                    icondata = re.findall('\nIcon=(.*)', appdata)[0]
                except IndexError:
                    icondata = ''

                if 'NoDisplay=true' in hidden:
                    catdata = 'Hidden'
                else:
                    try:
                        catdata = re.findall('\nCategories=(.*)', appdata)[0]
                    except IndexError:
                        catdata = 'Other'
                if catdata == '':
                    catdata = 'Other'
                catdata = catdata.split(';')
                categories = ('Office', 'Graphics', 'AudioVideo', 'Game', 'Utility', 'System', 'Settings', 'Science',
                              'Network', 'Education', 'Development', 'Other', 'Hidden')

                # add to Others category  if category is not a reconized category
                if len(set(categories) - set(list(catdata))) == len(categories):
                    jwmother.append([name_data, icondata, application])

                if 'Office' in catdata:
                    jwmoffice.append([name_data, icondata, application])
                if 'Graphics' in catdata:
                    jwmgraphics.append([name_data, icondata, application])
                if 'Audio' in catdata or 'Video' in catdata or 'AudioVideo' in catdata:
                    jwmav.append([name_data, icondata, application])
                if 'Game' in catdata:
                    jwmgame.append([name_data, icondata, application])
                if 'Utility' in catdata:
                    jwmautil.append([name_data, icondata, application])
                if 'System' in catdata:
                    jwmsys.append([name_data, icondata, application])
                if 'Settings' in catdata:
                    jwmset.append([name_data, icondata, application])
                if 'Science' in catdata:
                    jwmsci.append([name_data, icondata, application])
                if 'Network' in catdata:
                    jwmnet.append([name_data, icondata, application])
                if 'Education' in catdata or 'Science' in catdata:
                    jwmedu.append([name_data, icondata, application])
                if 'Development' in catdata:
                    jwmdev.append([name_data, icondata, application])
                if 'Other' in catdata:
                    jwmother.append([name_data, icondata, application])
                if 'Hidden' in catdata:
                    jwmhidden.append([name_data, icondata, application])

        return sorted(jwmautil, key=lambda x: x[0].lower()), sorted(jwmedu, key=lambda x: x[0].lower()), \
               sorted(jwmdev, key=lambda x: x[0].lower()), sorted(jwmgame, key=lambda x: x[0].lower()), \
               sorted(jwmgraphics, key=lambda x: x[0].lower()), sorted(jwmnet, key=lambda x: x[0].lower()), \
               sorted(jwmav, key=lambda x: x[0].lower()), sorted(jwmoffice, key=lambda x: x[0].lower()), \
               sorted(jwmsci, key=lambda x: x[0].lower()), sorted(jwmset, key=lambda x: x[0].lower()), \
               sorted(jwmsys, key=lambda x: x[0].lower()), sorted(jwmother, key=lambda x: x[0].lower()), \
               sorted(jwmhidden, key=lambda x: x[0].lower())

    def save_categories(self):
        # create Categories= line using toggle buttons and data from entry.
        cat_list = self.cat_entry.get_text().split(';')
        while '' in cat_list: cat_list.remove('')
        if not self.cat_check.get_active():
            buttons = [[self.cat_utility, 'Utility'], [self.cat_dev, 'Development'], [self.cat_edu, 'Education'],
                       [self.cat_game, 'Game'], [self.cat_graphic, 'Graphics'], [self.cat_net, 'Network'],
                       [self.cat_media, 'AudioVideo'], [self.cat_office, 'Office'], [self.cat_sci, 'Science'],
                       [self.cat_settings, 'Settings'], [self.cat_sys, 'System'], [self.cat_odd, 'Other']]
            for button in buttons:
                if button[0].get_active():
                    if button[1] not in cat_list:
                        cat_list.append(button[1])
                else:
                    if button[1] in cat_list:
                        cat_list.remove(button[1])
        cat_list = ';'.join(cat_list)
        if cat_list != '':
            if cat_list[-1] != ';':
                cat_list += ';'
        return cat_list

    def save_new_filename(self):
        # generate a filename for newly created launchers and create file
        filename = self.name_entry.get_text()
        if filename != '':
            file_list = os.listdir(self.home + '/.local/share/applications/')
            file_list.extend(os.listdir('/usr/share/applications/'))
            if filename + '.desktop' in file_list:
                index = 0
                while filename + '-' + str(index) + '.desktop' in file_list: index += 1
                filename = filename + '-' + str(index) + '.desktop'
            else:
                filename = filename + '.desktop'
            self.xdg_data[self.cat_selection][self.save_index][2] = self.home + '/.local/share/applications/' + filename
            with open(self.xdg_data[self.cat_selection][self.save_index][2], "w+") as f:
                f.write('[Desktop Entry]\nVersion=1.1\nType=Application\n')

    def save_prepare_data(self, cat_list):
        with open(self.xdg_data[self.cat_selection][self.save_index][2]) as f:
            alldata = f.read()
        #  separate app data and action data to prevent possible errors.  Will be merged on save
        if "[Desktop Action" in alldata:
            # will crash if [Desktop Entry] is not in file
            appdata = re.findall('(?s)(\[Desktop Entry\].+?(?=\[Desktop|\Z))', alldata, re.MULTILINE)[0]
            # action_data = re.findall('(?s)(\[Desktop Action.+?(?=\[Desktop|\Z))', alldata, re.MULTILINE)
        else:
            appdata = alldata
            # action_data = []
        # removes blank lines at end of appdata
        while appdata[-1] == '\n':
            appdata = appdata[:-1]

        entries = [[self.name_entry, 'Name'], [self.icon_entry, 'Icon'], [self.comment_entry, 'Comment'],
                   [self.command_entry, 'Exec'], [self.work_dir_entry, 'Path'],
                   [self.generic_entry, 'GenericName'], [self.try_exec_entry, 'TryExec'],
                   [self.only_show_entry, 'OnlyShowIn'], [self.not_shown_entry, 'NotShowIn'],
                   [self.mime_entry, 'MimeType'], [self.keywords_entry, 'Keywords'],
                   [self.wm_class_entry, 'StartupWMClass'], [self.implements_entry, 'Implements']]
        for entry in entries:
            data = entry[0].get_text()
            key = entry[1]
            if data not in [None, '']:
                appdata = re.subn('\n%s=.*' % key, '\n%s=' % key + data, appdata)
                if appdata[1] != 0:
                    appdata = appdata[0]
                else:
                    appdata = appdata[0]
                    appdata = appdata + '\n%s=' % key + data
            else:
                appdata = re.sub('\n%s=.*' % key, '', appdata)

        appdata = re.subn('\nCategories=' + re.escape(self.data[0][3]),
                          '\nCategories=' + cat_list, appdata)
        if appdata[1] != 0:
            appdata = appdata[0]
        else:
            appdata = appdata[0]
            appdata = appdata + '\nCategories=' + cat_list

        if self.terminal_run_switch.get_active():
            appdata = re.subn('(\nTerminal=.*)', '\nTerminal=true', appdata)
            if appdata[1] != 0:
                appdata = appdata[0]
            else:
                appdata = appdata[0]
                appdata = appdata + '\nTerminal=true'
        else:
            appdata = re.sub('(\nTerminal=.*)', '', appdata)

        if self.start_notice_switch.get_active():
            appdata = re.subn('(\nStartupNotify=.*)', '\nStartupNotify=true', appdata)
            if appdata[1] != 0:
                appdata = appdata[0]
            else:
                appdata = appdata[0]
                appdata = appdata + '\nStartupNotify=true'
        else:
            appdata = re.sub('(\nStartupNotify=.*)', '', appdata)

        if self.hide_switch.get_active():
            appdata = re.subn('(\nNoDisplay=.*)', '\nNoDisplay=true', appdata)
            if appdata[1] != 0:
                appdata = appdata[0]
            else:
                appdata = appdata[0]
                appdata = appdata + '\nNoDisplay=true'
        else:
            appdata = re.sub('(\nNoDisplay=.*)', '', appdata)

        if self.hidden_switch.get_active():
            appdata = re.subn('(\nHidden=.*)', '\nHidden=true', appdata)
            if appdata[1] != 0:
                appdata = appdata[0]
            else:
                appdata = appdata[0]
                appdata = appdata + '\nHidden=true'
        else:
            appdata = re.sub('(\nHidden=.*)', '', appdata)

        if self.dbus_switch.get_active():
            appdata = re.subn('(\nDBusActivatable=.*)', '\nDBusActivatable=true', appdata)
            if appdata[1] != 0:
                appdata = appdata[0]
            else:
                appdata = appdata[0]
                appdata = appdata + '\nDBusActivatable=true'
        else:
            appdata = re.sub('(\nDBusActivatable=.*)', '', appdata)

        # prepare Actions Data
        action_data = []
        actions = ''
        for i in self.action_store:
            if i[2]:
                if i[0]:
                    actions += i[1] + ';'
                action = '\n[Desktop Action ' + i[2] + ']\nName=' + i[2]
                if i[2]:
                    action += '\nExec=' + i[3]
                if i[4]:
                    action += '\nIcon=' + i[4]
                action += '\n'
                action_data.append(action)

        # Add or edit Action= line
        if actions not in ['', None]:
            appdata = re.subn('\nActions=.*', '\nActions=' + actions, appdata)
        else:
            appdata = re.subn('\nActions=.*', '', appdata)
        if appdata[1] != 0:
            appdata = appdata[0]
        else:
            appdata = appdata[0]
            if actions not in ['', None]:
                appdata = appdata + '\nActions=' + actions

        # merge app and action data
        appdata += '\n'
        for action in action_data:
            appdata = appdata + action
        return appdata

    def on_save(self, button, buttons):
        cat_list = self.save_categories()
        selection = self.cat_selection
        row = self.save_index
        if self.xdg_data[selection][row][2] == '':
            self.save_new_filename()
        filename = self.xdg_data[selection][row][2]
        if filename != '':
            appdata = self.save_prepare_data(cat_list)
            filename = filename.replace('/usr/share/applications/', self.home + '/.local/share/applications/')
            with open(filename, "w") as f:
                f.write(appdata)
            filename = self.xdg_data[selection][row][2]
            self.xdg_data = self.get_xdg_data()
            for i, button in zip(self.xdg_data, buttons):
                if len(i) == 0:
                    button.set_visible(False)
                else:
                    button.set_visible(True)
            if filename != self.xdg_data[selection][row][2]:
                for i in enumerate(self.xdg_data[selection]):
                    if filename == i[1][2]:
                        row = i[0]
                        break
            self.cat_switch(row)

    def cat_switch(self, i):
        if len(self.xdg_data[self.cat_selection]) == 0:
            for i in range(len(self.xdg_data)):
                if len(self.xdg_data[i]) != 0:
                    self.populate_listbox(self.listbox_mid_mid, i)
                break
        else:
            self.populate_listbox(self.listbox_mid_mid, self.cat_selection)
            row = self.listbox_mid_mid.get_row_at_index(i)
            self.listbox_changed(self.listbox_mid_mid, row)
            self.listbox_mid_mid.select_row(row)

    def delete_launcher(self, button, buttons):
        filename = self.xdg_data[self.cat_selection][self.save_index][2]
        selection = self.cat_selection
        row = self.save_index
        if row != 0: row = row - 1

        if filename == '':
            del self.xdg_data[selection][self.save_index]
        elif self.home in filename:
            dialog = Gtk.Dialog("Confirm Deletion", self, 0)
            dialog.add_buttons("Cancel", 0, "OK", 1)
            dialog.set_default_size(320, 100)
            box = dialog.get_content_area()
            box.add(Gtk.Label())
            box.add(Gtk.Label(label='Delete the selected Launcher?'))
            dialog.show_all()
            if dialog.run():
                os.remove(filename)
                del self.xdg_data[selection][self.save_index]
            dialog.destroy()
        for i, button in zip(self.xdg_data, buttons):
            if len(i) == 0:
                button.set_visible(False)
            else:
                button.set_visible(True)
        try:
            if filename != self.xdg_data[selection][row][2]:
                for i in enumerate(self.xdg_data[selection]):
                    if filename == i[1][2]:
                        row = i[0]
                        break
        except IndexError:
            row = None
        self.cat_switch(row)

    def create_launcher(self, button):
        cats = ['Utility', 'Education', 'Development', 'Game', 'Graphics', 'Network',
                'AudioVideo', 'Office', 'Science', 'Settings', 'System', 'Other', 'Hidden']
        selection = self.cat_selection
        cats = cats[selection]
        self.xdg_data[selection].append(['', '', ''])
        self.populate_listbox(self.listbox_mid_mid, selection)
        row = self.listbox_mid_mid.get_row_at_index(len(self.xdg_data[selection]) - 1)
        self.listbox_mid_mid.select_row(row)
        self.listbox_changed(self.listbox_mid_mid, row)
        self.set_cat_toggle(cats)
        self.cat_entry.set_text(''.join([cats, ';']))

    def test_launch(self, button):
        path = self.work_dir_entry.get_text()
        command = self.command_entry.get_text()
        if self.data[0][1] == command and self.data[0][2] == path:
            dot_desk = re.sub((".*\/"), '', self.xdg_data[self.cat_selection][self.save_index][2])
            os.system('gtk-launch "' + dot_desk + '"')
        else:
            if path.startswith('~'):
                path = self.home + path[1:]
            test = os.path.isdir(path)
            if path == '':
                test = True
            if not test:
                print('Working Directory not found. No such directory')
            else:
                os.system(command)
            if not os.path.isfile(command):
                print('Command not found. No such file')

    def toggle_cell(self, widget, path):
        self.action_store[path][0] = not self.action_store[path][0]

    def delete_action_row(self, button):
        selection = self.action_tree_view.get_selection()
        model, paths = selection.get_selected_rows()
        for path in paths:
            self.action_store.remove(model.get_iter(path))

    def action_move_up(self, button):
        selection = self.action_tree_view.get_selection()
        model, tree_iter = selection.get_selected_rows()
        i = tree_iter[0].get_indices()[0]
        if i != 0:
            self.action_store[i][0], self.action_store[i - 1][0] = self.action_store[i - 1][0], self.action_store[i][0]
            self.action_store[i][1], self.action_store[i - 1][1] = self.action_store[i - 1][1], self.action_store[i][1]
            self.action_store[i][2], self.action_store[i - 1][2] = self.action_store[i - 1][2], self.action_store[i][2]
            self.action_store[i][3], self.action_store[i - 1][3] = self.action_store[i - 1][3], self.action_store[i][3]
            self.action_store[i][4], self.action_store[i - 1][4] = self.action_store[i - 1][4], self.action_store[i][4]
            self.action_store[i][5], self.action_store[i - 1][5] = self.action_store[i - 1][5], self.action_store[i][5]
            selection.select_path(i - 1)

    def action_move_down(self, button):
        selection = self.action_tree_view.get_selection()
        model, tree_iter = selection.get_selected_rows()
        i = tree_iter[0].get_indices()[0]
        if i != len(self.action_store) - 1:
            self.action_store[i][0], self.action_store[i + 1][0] = self.action_store[i + 1][0], self.action_store[i][0]
            self.action_store[i][1], self.action_store[i + 1][1] = self.action_store[i + 1][1], self.action_store[i][1]
            self.action_store[i][2], self.action_store[i + 1][2] = self.action_store[i + 1][2], self.action_store[i][2]
            self.action_store[i][3], self.action_store[i + 1][3] = self.action_store[i + 1][3], self.action_store[i][3]
            self.action_store[i][4], self.action_store[i + 1][4] = self.action_store[i + 1][4], self.action_store[i][4]
            self.action_store[i][5], self.action_store[i + 1][5] = self.action_store[i + 1][5], self.action_store[i][5]
            selection.select_path(i + 1)

    def add_action_row(self, button):
        icon = Gtk.IconTheme.get_default().load_icon('image-missing', 24, Gtk.IconLookupFlags.FORCE_SIZE)
        self.action_store.append([True, "New ShortCut", "New ShortCut", 'Command', '', icon])

    def edit_cell_text(self, widget, path, text, i):
        self.action_store[path][i] = text
        if i == 4:
            self.action_store[path][5] = self.update_icon(text, 24)

    def browse_command_wrapper(self, entry, icon_pos, event, browse_id):
        self.browse_command('', entry, browse_id)

    def browse_command(self, button, entry, browse_id):
        # create a file browsing dialog to select a path/file
        #  path of the selected file is add to the entry
        file_filter = Gtk.FileFilter()
        set_folder = self.home
        if browse_id == 'icon':
            set_folder = "/usr/share/icons/"
            for pat in ['*.png', '*.svg', '*.xpm,', '*.jpg', '*.jpeg']:
                file_filter.add_pattern(pat)
            file_filter.set_name('images')
            file_dialog = Gtk.FileChooserDialog(title="Select a file", parent=self, action=Gtk.FileChooserAction.OPEN)
        elif browse_id == 'exec':
            file_filter.add_pattern('*')
            file_filter.set_name('all files')
            file_dialog = Gtk.FileChooserDialog(title="Select a file", parent=self, action=Gtk.FileChooserAction.OPEN)
        else:
            file_filter.add_pattern('*')
            file_filter.set_name('all files')
            file_dialog = Gtk.FileChooserDialog \
                (title="Select a file", parent=self, action=Gtk.FileChooserAction.SELECT_FOLDER)

        file_dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
        file_dialog.set_current_folder(set_folder)
        file_dialog.add_filter(file_filter)
        file_selected = file_dialog.run()
        if file_selected == Gtk.ResponseType.OK:
            file_selected = file_dialog.get_filename()
            if file_selected not in [None, '']:
                entry.set_text(file_selected)
                if browse_id == 'icon':
                    self.update_app_icon('', file_selected)
        file_dialog.destroy()


win = MenusWindow()
win.connect("delete-event", Gtk.main_quit)
win.set_position(Gtk.WindowPosition.CENTER)
win.show_all()
Gtk.main()

# Note : Freedesktops uses the default system icon set.
#
# Parameters
# jwm, -jwm, --jwm  : use JWM's icons instead of the default icon set.
