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

# 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 the0
# 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 get_menu_xml(file):
    # Read the menu file
    home = os.path.expanduser('~')
    if os.path.isfile(file):
        if file.startswith('$HOME'):
            file = os.path.join(home, file[6:])

    tree = ET.parse(file)
    root = tree.getroot()
    return root


def verify_menu(filename):
    # Ensure an imported files is a JWM Menu and a valid XML file
    if filename:
        try:
            tree = ET.parse(filename)
            root = tree.getroot()
            if root.tag == 'JWM':
                if root[0].tag == 'RootMenu':
                    return True
        except (ET.ParseError, IndexError):
            return False


def get_menu_files(jwmrc):
    # Make a list of Menu files, and the icon file
    home = os.path.expanduser('~')

    icon_files, menu_files, tmp = '', [], []
    try:
        tree = ET.parse(jwmrc)
    except Exception as exception_message:
        print(str(exception_message))
        jwmkit_utils.app_fail()
    root = tree.getroot()
    for node in root:
        if node.tag == 'Include':
            node = node.text
            if node.startswith('$HOME'):
                node = os.path.join(home, node[6:])
            if os.path.isfile(node):
                tmp.append(node)
    for filename in tmp:
        try:
            tree = ET.parse(filename)
            root = tree.getroot()
            if root[0].tag == 'RootMenu':
                menu_files.append([os.path.basename(filename), filename])
            elif root[0].tag == 'IconPath':
                icon_files = filename
        except (ET.ParseError, IndexError):
            print('Unable to process {}'.format(filename))
    return menu_files, icon_files


def get_icon_paths(icon_path):
    # make a list of icons paths defined in the JWM's icon file
    home = os.path.expanduser('~')
    try:
        tree = ET.parse(icon_path)
        root = tree.getroot()
        icon_path = []
        for node in root:
            node = node.text
            if node.startswith('$HOME'):
                node = '{}{}'.format(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):
        # file is empty, or corrupt.
        print('The file either contains no icons paths, is missing or corrupt.\n')
        icon_path = ''
    return icon_path


def get_languages():
    try:
        with open('/etc/locale.gen') as f:
            locale_tmp = f.read()
    except (FileNotFoundError, UnicodeDecodeError):
        return ['Default']
    locale_tmp = locale_tmp.split('\n')
    locale_data = ['Default']
    l_data, t_data = [], []
    for data in locale_tmp:
        if not data.startswith('# '):
            if data not in ['', ' ', '#', '# ']:
                data = data.strip('#').strip(' ')
                try:
                    data = re.findall('([^ .]+)', data)[0]
                    l_data.append(data.split('_')[0])
                    t_data.append(data)
                except IndexError:
                    pass
    l_data = list(set(l_data))
    l_data.sort()
    t_data = list(set(t_data))
    t_data.sort()
    locale_data.extend(l_data)
    locale_data.extend(t_data)
    return locale_data


def check_swap(check, check2):
    if check.get_active():
        check2.set_active(False)
    else:
        check2.set_active(True)


class MenusWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="JWM Kit Menus")
        self.set_border_width(15)
        try:
            self.set_icon_from_file('/usr/share/pixmaps/jwmkit/menugray.svg')
        except gi.repository.GLib.Error:
            self.set_icon_name('edit-paste')
        self.jwmrc = jwmkit_utils.get_jwmrc()
        files = get_menu_files(self.jwmrc)
        self.menu_files = files[0]
        self.jwm_icon_paths = get_icon_paths(files[1])
        self.selected_menu = ('Root Level', '/usr/share/pixmaps/jwmkit/folder_root_blue.svg', 0)
        self.select_menu_data, self.menu_buttons = [], []
        self.previous_index = -2
        self.app_data = jwmkit_utils.get_applications_data()
        self.selected_list_item = ''
        self.preview_icon, item_spacer, self.item_label = Gtk.Image(), Gtk.Label(label='  \t  '), Gtk.Label()

        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        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)
        mid_header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        right_header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        self.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_top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        items_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        prop_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        below_bottom_right = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        bottom_right = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)

        items_box.set_property("width-request", 320)
        self.mid_left.set_property("width-request", 160)
        mid_right.pack_start(mid_right_top, False, False, 0)
        main_mid_box.pack_end(mid_right, False, False, 0)
        mid_right.pack_end(bottom_right, False, False, 0)
        mid_right.pack_end(below_bottom_right, False, False, 0)
        self.add(main_box)
        main_box.pack_start(main_top_box, False, False, 0)
        main_box.pack_start(main_mid_box, True, True, 0)
        main_box.pack_start(main__bottom_box, False, False, 0)
        main_mid_box.pack_start(self.mid_left, True, True, 5)
        main_mid_box.pack_start(mid_mid, True, True, 5)

        # tabs
        notebook = Gtk.Notebook()
        item_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        prop_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        notebook.append_page(item_page, Gtk.Label(label='Item'))
        notebook.append_page(prop_page, Gtk.Label(label='Properties'))
        item_page.set_border_width(15)
        prop_page.set_border_width(15)
        item_page.add(items_box)
        prop_page.add(prop_box)
        mid_right.pack_start(notebook, True, True, 5)

        # rows for items tab
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        type_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        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)
        confirm_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        items_box.add(row)
        items_box.add(type_row)
        items_box.add(name_row)
        items_box.add(comment_row)
        items_box.add(icon_row)
        items_box.add(command_row)
        items_box.add(Gtk.Label())
        items_box.add(confirm_row)
        items_box.add(Gtk.Label())

        # rows for properties tab
        prop_row_label = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        prop_row_onroot = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        prop_row_switch = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        prop_row_dynamic = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.add(Gtk.Label())
        prop_box.add(row)
        prop_box.add(prop_row_label)
        prop_box.add(prop_row_dynamic)
        prop_box.add(prop_row_onroot)
        row = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=1)
        prop_box.add(row)
        prop_box.add(prop_row_switch)

        # listbox menu items
        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_mid.pack_start(mid_header_box, False, False, 0)
        mid_right_top.add(right_header_box)
        scroll_mid_mid = Gtk.ScrolledWindow()
        scroll_mid_mid.set_min_content_width(280)
        scroll_mid_mid.set_min_content_height(550)
        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.BROWSE)
        scroll_mid_mid.add(self.listbox_mid_mid)
        self.listbox_mid_mid.connect("selected-rows-changed", self.listbox_changed)
        self.listbox_mid_mid.connect("row-activated", self.listbox_double)
        self.listbox_mid_mid.set_activate_on_single_click(False)
        self.menu_combo = Gtk.ComboBoxText()
        for menu in self.menu_files:
            self.menu_combo.append_text(menu[0].capitalize())
        self.menu_combo.set_tooltip_text("select a menu to edit")
        self.menu_combo.connect("changed", self.on_menu_selection)

        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)

        add_new_button = Gtk.Button(label="Add", image=Gtk.Image(stock=Gtk.STOCK_ADD))
        add_new_button.set_tooltip_text('Add an Item')
        add_new_button.set_property("width-request", 120)
        add_new_button.set_always_show_image(True)
        add_new_button.connect("clicked", self.on_add_item)

        delete_button = Gtk.Button(label="Delete", image=Gtk.Image(stock=Gtk.STOCK_DELETE))
        delete_button.set_tooltip_text('Delete the Item')
        delete_button.set_property("width-request", 120)
        delete_button.set_always_show_image(True)
        delete_button.connect("clicked", self.remove_item)

        close_button = Gtk.Button(label="Close", image=Gtk.Image(stock=Gtk.STOCK_CANCEL))
        close_button.set_property("width-request", 120)
        close_button.set_always_show_image(True)
        close_button.connect("clicked", Gtk.main_quit)

        up_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_GO_UP))
        up_button.set_tooltip_text('Move Item Up')
        up_button.set_property("width-request", 80)
        up_button.set_always_show_image(True)
        up_button.connect("clicked", self.move_up)

        down_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_GO_DOWN))
        down_button.set_tooltip_text('Move Item Down')
        down_button.set_property("width-request", 80)
        down_button.set_always_show_image(True)
        down_button.connect("clicked", self.move_down)

        add_menu_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_PREFERENCES))
        add_menu_button.set_tooltip_text('Create / Import / Restore / Remove a Menu')
        add_menu_button.set_always_show_image(True)
        add_menu_button.connect("clicked", self.add_menu)

        about_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ABOUT))
        about_button.set_always_show_image(True)
        about_button.set_tooltip_text("About")
        about_button.connect("clicked", jwmkit_utils.get_about, self)

        # widgets for items tab
        self.name_label = Gtk.Label(label='Name:')
        self.icon_label = Gtk.Label(label='Icon:')
        self.command_label = Gtk.Label(label='Command:')
        self.comment_label = Gtk.Label(label='Tooltip:')

        self.name_entry = Gtk.Entry()
        self.icon_entry = Gtk.Entry()
        self.comment_entry = Gtk.Entry()
        self.command_entry = Gtk.Entry()
        self.command_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'system-file-manager')
        self.command_entry.connect("icon-press", self.cmd_entry_pressed)
        self.icon_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'system-file-manager')
        self.icon_entry.connect("changed", self.icon_preview)
        self.icon_entry.connect("icon-press", self.icon_entry_pressed)

        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.easy_button = Gtk.Button(label=" Easy Menu Settings", image=Gtk.Image(stock=Gtk.STOCK_INDEX))
        self.easy_button.set_always_show_image(True)
        self.easy_button.set_property("width-request", 240)
        self.easy_button.set_tooltip_text('add or modify Easy Menu')
        self.easy_button.connect("clicked", self.easy_dialog)

        self.easy_button.set_no_show_all(True)
        self.name_entry.set_no_show_all(True)
        self.icon_entry.set_no_show_all(True)
        self.comment_entry.set_no_show_all(True)
        self.command_entry.set_no_show_all(True)
        self.name_label.set_no_show_all(True)
        self.icon_label.set_no_show_all(True)
        self.comment_label.set_no_show_all(True)
        self.command_label.set_no_show_all(True)
        self.easy_button.set_visible(False)
        self.name_entry.set_visible(True)
        self.icon_entry.set_visible(True)
        self.comment_entry.set_visible(True)
        self.command_entry.set_visible(True)
        self.name_label.set_visible(True)
        self.icon_label.set_visible(True)
        self.comment_label.set_visible(True)
        self.command_label.set_visible(True)

        adjustment = Gtk.Adjustment(value=0, lower=0, upper=100, step_increment=1)
        self.menu_h_spin = Gtk.SpinButton()
        self.menu_h_spin.set_tooltip_text("Height of each menu item in pixel")
        self.menu_h_spin.set_adjustment(adjustment)

        self.height_check = Gtk.CheckButton(label="height")
        self.height_check.set_tooltip_text("Uncheck to use the parent menu height")
        self.height_check.connect("toggled", self.on_menu_check)
        self.height_check.set_active(True)
        self.confirm_switch = Gtk.Switch()

        self.confirm_label = Gtk.Label(xalign=0)
        self.confirm_switch.set_no_show_all(True)
        self.confirm_switch.set_visible(False)
        self.confirm_label.set_no_show_all(True)
        self.confirm_label.set_visible(False)

        self.height_check.set_no_show_all(True)
        self.height_check.set_visible(False)
        self.menu_h_spin.set_no_show_all(True)
        self.menu_h_spin.set_visible(False)

        # widgets from properties tab
        self.label_entry = Gtk.Entry()
        self.onroot_entry = Gtk.Entry()
        self.onroot_entry.set_max_length(6)
        self.onroot_entry.set_width_chars(6)

        self.onroot_entry.connect("changed", self.onroot_change, self.menu_combo)
        self.dynamic_entry = Gtk.Entry()
        self.dynamic_label = Gtk.Label(label='Dynamic:')
        self.dynamic_entry.set_no_show_all(True)
        self.dynamic_entry.set_visible(False)
        self.dynamic_label.set_no_show_all(True)
        self.dynamic_label.set_visible(False)

        self.label_switch = Gtk.Switch()

        adjustment = Gtk.Adjustment(value=0, lower=0, upper=100, step_increment=1)
        self.file_h_spin = Gtk.SpinButton()
        self.file_h_spin.set_tooltip_text("Height of each menu item in pixel")
        self.file_h_spin.set_adjustment(adjustment)

        self.label_entry.set_property("width-request", 240)
        self.dynamic_entry.set_property("width-request", 240)
        # End of widgets

        # add widgets window
        prop_row_label.pack_end(self.label_entry, False, False, 0)
        prop_row_label.pack_end(Gtk.Label(label='Label:'), False, False, 0)
        prop_row_onroot.pack_end(self.file_h_spin, False, False, 0)
        prop_row_onroot.pack_end(Gtk.Label(label='height:'), False, False, 0)
        prop_row_onroot.pack_start(Gtk.Label(label='\t  onroot:'), False, False, 0)
        prop_row_onroot.pack_start(self.onroot_entry, False, False, 0)
        prop_row_dynamic.pack_end(self.dynamic_entry, False, False, 0)
        prop_row_dynamic.pack_end(self.dynamic_label, False, False, 0)
        prop_row_switch.pack_end(self.label_switch, False, False, 0)
        prop_row_switch.pack_end(Gtk.Label(label='Show Label'), False, False, 0)
        bottom_right.pack_start(down_button, False, False, 0)
        bottom_right.pack_end(close_button, False, False, 0)
        bottom_right.pack_end(delete_button, False, False, 0)
        below_bottom_right.pack_start(up_button, False, False, 0)
        below_bottom_right.pack_end(save_button, False, False, 0)
        below_bottom_right.pack_end(add_new_button, False, False, 0)
        right_header_box.pack_end(about_button, False, False, 0)
        right_header_box.pack_end(add_menu_button, False, False, 0)
        right_header_box.pack_end(self.menu_combo, True, True, 0)
        type_row.pack_start(item_spacer, False, False, 0)
        type_row.pack_start(self.preview_icon, False, False, 0)
        type_row.pack_start(self.item_label, False, False, 0)
        name_row.pack_end(self.name_entry, False, False, 0)
        name_row.pack_end(self.name_label, False, False, 0)
        comment_row.pack_end(self.comment_entry, False, False, 0)
        comment_row.pack_end(self.comment_label, False, False, 0)
        icon_row.pack_end(self.icon_entry, False, False, 0)
        icon_row.pack_end(self.icon_label, False, False, 0)

        icon_row.pack_end(self.easy_button, False, False, 0)
        command_row.pack_end(self.command_entry, False, False, 0)
        command_row.pack_end(self.command_label, False, False, 0)
        confirm_row.pack_end(self.confirm_switch, False, False, 0)
        confirm_row.pack_end(self.confirm_label, False, False, 0)
        confirm_row.pack_start(self.height_check, False, False, 0)
        confirm_row.pack_start(self.menu_h_spin, False, False, 0)

        # popup for add item button
        self.popover = Gtk.Popover()
        pbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        options = ['Program', 'Include', 'Easy Menu', 'Menu', 'Dynamic', 'Separator', 'Restart', 'Exit',
                   'SendTo', 'Desktops', 'Stick', 'Maximize', 'Minimize', 'Shade', 'Move', 'Resize', 'Kill', 'Close']
        for option in options:
            pop_up_button = Gtk.ModelButton(label=option)
            pop_up_button.connect("clicked", self.pop_add_item, option)
            pbox.pack_start(pop_up_button, False, True, 2)
        self.popover.add(pbox)
        self.popover.set_position(Gtk.PositionType.BOTTOM)

        self.menu_combo.set_active(0)
        save_button.connect("clicked", self.save)

    def dialogs(self, dialog_type):
        def clear_status(notebook, label, page):
            status_label.set_text('')

        def selection_made(box, row, response):
            def add_jwmrc_include():
                filename = self.selected_list_item
                home = os.path.expanduser('~')
                tree = ET.parse(self.jwmrc)
                root = tree.getroot()
                new_include = ET.SubElement(root, "Include")
                include_name = filename
                if include_name.startswith(home):
                    include_name = include_name[len(home) + 1:]
                    include_name = os.path.join('$HOME/', include_name)
                new_include.text = include_name
                root = b'\n'.join([s.strip() for s in ET.tostring(root).splitlines() if s.strip()])
                pretty = minidom.parseString(root).toprettyxml(newl='', indent='   ')
                tree = ET.ElementTree(ET.fromstring(pretty))
                tree.write(self.jwmrc, encoding="utf-8", xml_declaration=True)
                self.menu_files.append([os.path.basename(filename), filename])
                self.menu_combo.append_text(os.path.basename(filename).capitalize())
                os.system('jwm -restart')

            def create_menu():
                # Create a new Menu File and it add it to jwmrc
                filename = self.selected_list_item
                home = os.path.expanduser('~')
                if not filename.lower().startswith('menu'):
                    filename = 'menu-{}'.format(filename)
                if not os.path.exists(os.path.join(home, '.config/jwm', filename)):
                    with open(os.path.join(home, '.config/jwm', filename), "w+") as f:
                        f.write('<JWM><RootMenu onroot="{}"></RootMenu></JWM>'.format(onroot))
                    self.selected_list_item = os.path.join(home, '.config/jwm', filename)
                    add_jwmrc_include()

            def clean_settings():
                # clean up JWM Kit's Setting file. remove old history
                home = os.path.expanduser('~')
                filename = self.selected_list_item[len(home):]
                with open(os.path.join(home, '.config/jwmkit/settings'), 'r+') as f:
                    lines = f.readlines()
                    f.seek(0)
                    for line in lines:
                        if not line.strip('\n').endswith(filename):
                            f.write(line)
                    f.truncate()

            def clean_settings_file():
                with open(os.path.join(home, '.config/jwmkit/settings'), 'r+') as f:
                    lines = f.readlines()
                    f.seek(0)
                    for line in lines:
                        if line.strip('\n'):
                            f.write(line)
                    f.truncate()

            def remove_xml_include():
                tree = ET.parse(self.jwmrc)
                root = tree.getroot()
                for child in root:
                    if child.text.endswith(filename):
                        root.remove(child)
                pretty = minidom.parseString(ET.tostring(root)).toprettyxml()
                pretty = os.linesep.join([s for s in pretty.splitlines() if s.strip()])
                tree = ET.ElementTree(ET.fromstring(pretty))
                tree.write(self.jwmrc, encoding="utf-8", xml_declaration=True)
                os.system('jwm -restart')

            def update_onroot():
                tree = ET.parse(os.path.join(self.selected_list_item))
                root = tree.getroot()
                root[0].attrib['onroot'] = onroot
                tree.write(self.selected_list_item)

            def find_by_index(i):
                for node in self.menu_xml.findall('.//'):
                    if node.get('index') == i:
                        break
                return node

            if response == -5:
                if dialog_type == 'app':
                    row = listbox.get_selected_row()
                    # App:: Select Command with File Browser Action
                    if notebook.get_current_page() == 1:
                        entry_data = self.selected_list_item
                        self.command_entry.set_text(entry_data)
                    else:
                        # App: Application List Action
                        index = row.get_index()
                        entry_data = data[index][2]
                        while entry_data[-3:] in [' %U', ' %u', ' %F', ' %f', ' %i', ' %c', ' %k']:
                            entry_data = '{}'.format(entry_data[:-3])
                        if name_check.get_active():
                            if self.name_entry.get_visible():
                                self.name_entry.set_text(data[index][0])
                        if tooltip_check.get_active():
                            if self.comment_entry.get_visible():
                                self.comment_entry.set_text(data[index][1])
                        if icon_check.get_active():
                            if self.icon_entry.get_visible():
                                self.icon_entry.set_text(data[index][3])
                        if self.command_entry.get_visible():
                            self.command_entry.set_text(entry_data)
                elif dialog_type == 'icon':
                    # Icon Viewer and Import icon with File Browser Action
                    if self.icon_entry.get_text() != self.selected_list_item:
                        if notebook.get_current_page() == 0:
                            if not path_check.get_active():
                                self.selected_list_item = os.path.basename(self.selected_list_item)
                                self.selected_list_item = os.path.splitext(self.selected_list_item)[0]
                        self.icon_entry.set_text(self.selected_list_item)
                elif dialog_type == 'move_copy':
                    grand_index = self.selected_menu[2]
                    parent_index = self.selected_list_item
                    item_index = self.select_menu_data[self.listbox_mid_mid.get_selected_row().get_index()][-1]
                    parent = find_by_index(parent_index)
                    child = find_by_index(item_index)
                    # Move item to another Menu Action
                    if move_check.get_active():
                        grandparent = find_by_index(grand_index)
                        grandparent.remove(child)
                        parent.append(child)
                        item_index = self.listbox_mid_mid.get_selected_row().get_index()
                        self.listbox_mid_mid.remove(self.listbox_mid_mid.get_selected_row())
                        self.select_menu_data.pop(item_index)
                        self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(item_index))
                    elif copy_check.get_active():
                        # Copy item to another Menu Action
                        child_copy = copy.deepcopy(child)
                        parent.append(child_copy)
                    self.move_index()
                    self.make_buttons()
                elif dialog_type == 'add_menu':
                    current_page = notebook.get_current_page()
                    page_label = notebook.get_tab_label(notebook.get_nth_page(current_page)).get_text()
                    # Create Menu File Action
                    # TODO make status messages for user in place of the print statements below
                    if current_page == 0:
                        onroot = onroot_entry.get_text()
                        self.selected_list_item = menu_entry.get_text()
                        if self.selected_list_item != '':
                            if onroot != '':
                                create_menu()
                                dialog.destroy()
                            else:
                                status_label.set_text('Assign onroot key(s)')
                        else:
                            status_label.set_text('Give the menu a name')

                    elif page_label == 'Restore':
                        # Restore Menu File Action
                        onroot = onroot_entry.get_text()
                        i = listbox.get_selected_row().get_index()
                        self.selected_list_item = data[i]
                        if onroot != '':
                            if verify_menu(self.selected_list_item):
                                update_onroot()
                                add_jwmrc_include()
                                clean_settings()
                                dialog.destroy()
                        else:
                            status_label.set_text('Assign onroot key(s)')
                    elif current_page == len(notebook) - 1:
                        # Remove Menu File Action
                        home = os.path.expanduser('~')
                        confirm = self.confirm_dialog('b1', 'Remove Menu', 'Do you want to remove this menu', '')
                        if confirm == -6:
                            return
                        index = remove_listbox.get_selected_rows()[0].get_index()
                        filename = self.menu_files[index][1]
                        active = self.menu_combo.get_active()
                        if filename[:5] == '$HOME':
                            filename = filename[6:]
                        elif filename.startswith(home):
                            filename = filename[len(home) + 1:]
                        if not filename.startswith('.config/jwm/'):
                            clean_settings_file()
                            with open(os.path.join(home, '.config/jwmkit/settings'), 'a') as f:
                                f.write('menu-history={}'.format(os.path.join('$HOME/', filename)))
                        remove_xml_include()
                        if delete_check.get_active():
                            os.remove(os.path.join(home, filename))
                        del self.menu_files[index]
                        self.menu_combo.remove(index)
                        if index == active:
                            self.menu_combo.set_active(0)
                        dialog.destroy()

                    else:
                        # Import Menu File with File Browser
                        onroot = onroot_entry.get_text()
                        if self.selected_list_item:
                            if not os.path.isfile(self.selected_list_item):
                                return
                        if onroot != '':
                            menu_files = []
                            for menu_file in self.menu_files:
                                menu_files.append(menu_file[1])
                            if verify_menu(self.selected_list_item):
                                if self.selected_list_item not in menu_files:
                                    update_onroot()
                                    add_jwmrc_include()
                                    dialog.destroy()
                                else:
                                    status_label.set_text('File is already in use. Try again')
                            else:
                                status_label.set_text('Not a valid JWM menu file. Try again')
                        else:
                            status_label.set_text('Assign onroot key(s)')

            if dialog_type != 'add_menu':
                dialog.destroy()
            if response == -6:
                dialog.destroy()

        def image_selected(button, icon):
            # update the icon preview at top of icon viewer
            self.selected_list_item = icon
            icon = self.update_icon(icon, 48, 'image-missing')
            self.selected_preview.set_from_pixbuf(icon)

        def hide_path_check(notebook, label, page):
            # hide / show check buttons on Icon dialog
            path_check.set_visible(True) if page == 0 else path_check.set_visible(False)

        def hide_app_checks(notebook, label, page):
            # hide / show check buttons on App dialog
            if page == 0:
                name_check.set_visible(True)
                icon_check.set_visible(True)
                tooltip_check.set_visible(True)
            else:
                name_check.set_visible(False)
                icon_check.set_visible(False)
                tooltip_check.set_visible(False)

        def hide_remove_widgets(notebook, label, page):
            page = notebook.get_tab_label(notebook.get_nth_page(page)).get_text()
            if page == 'Remove':
                onroot_entry.set_visible(False)
                onroot_label.set_visible(False)
                onroot_message.set_visible(False)
            else:
                onroot_entry.set_visible(True)
                onroot_label.set_visible(True)
                onroot_message.set_visible(True)

        def icon_tab():
            # tab 1 Icon Browser
            icons = []
            jwm_icon_paths = self.jwm_icon_paths
            # Create a list of icons in all icon paths
            for path in jwm_icon_paths:
                icons.append(os.listdir(path))
            icon_list = []
            for i, path in zip(icons, jwm_icon_paths):
                tmp = []
                for icon in i:
                    if icon not in icon_list:
                        file = os.path.join(path, icon)
                        if os.path.isfile(file):
                            tmp.append(file)
                icon_list.extend(tmp)
            viewer_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            scroll = Gtk.ScrolledWindow()
            notebook.set_border_width(15)
            scroll.set_property("width-request", 1000)
            scroll.add(main_box)
            viewer_page.pack_start(scroll, True, True, 0)
            notebook.append_page(viewer_page, Gtk.Label(label='Icon Viewer'))
            box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
            # Create and Render the icons & add them to window
            for count, icon in enumerate(icon_list):
                try:
                    image = Gtk.Image()
                    pix = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon, 32, 32, preserve_aspect_ratio=False)
                    image.set_from_pixbuf(pix)
                    button = Gtk.Button(image=image)
                    button.set_relief(Gtk.ReliefStyle.NONE)
                    button.connect("clicked", image_selected, icon)
                    box.pack_start(button, True, True, 0)
                    if (count + 1) % 18 == 0:
                        main_box.pack_start(box, True, True, 0)
                        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                except gi.repository.GLib.Error:
                    print('unable to process image')
                    if (count + 1) % 18 == 0:
                        main_box.add(box)
                        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
            main_box.pack_start(box, True, True, 0)

        def copy_tab():
            def row_change(box):
                index = box.get_selected_row().get_index()
                self.selected_list_item = data[index][-1]

            scroll = Gtk.ScrolledWindow()
            scroll.set_min_content_width(-1)
            scroll.set_min_content_height(340)
            notebook.append_page(scroll, Gtk.Label(label='Target Menus'))
            listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
            listbox.set_activate_on_single_click(False)
            listbox.connect("selected-rows-changed", row_change)
            listbox.connect("row-activated", selection_made, -5)
            scroll.add(listbox)
            select_menu_index = self.select_menu_data[self.listbox_mid_mid.get_selected_row().get_index()][-1]
            count, rm_index = 0, None
            for i in data:
                if i[-1] != select_menu_index:
                    count += 1
                    row = Gtk.ListBoxRow()
                    row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                    icon = i[1]
                    try:
                        image = Gtk.Image()
                        image.set_from_pixbuf(self.update_icon(icon, 24, 'image-missing'))
                        row_box.pack_start(image, False, False, 0)
                    except gi.repository.GLib.Error:
                        print('unable to process image')
                    row_box.pack_start(Gtk.Label(label='{}'.format(i[0])), False, False, 0)
                    row.add(row_box)
                    listbox.insert(row, -1)
                else:
                    rm_index = count
            if rm_index:
                del data[rm_index]
            listbox.show_all()
            listbox.select_row(listbox.get_row_at_index(0))

        def menu_tab():
            def row_change(widget):
                index = widget.get_selected_row().get_index()
                self.selected_list_item = data[index]
                status_label.set_text('')

            # Tab1 Create
            vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
            row.set_border_width(20)
            menu_entry.set_text('menu')
            onroot_entry.connect("changed", self.onroot_change, '')
            onroot_entry.set_max_length(6)
            onroot_entry.set_width_chars(6)
            row.pack_end(menu_entry, True, True, 0)
            row.pack_end(Gtk.Label(label='Menu Name:'), False, False, 0)
            vbox.pack_start(row, False, False, 0)
            notebook.append_page(vbox, Gtk.Label(label='Create'))
            # Tab2 Restore
            if data:
                vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
                vbox.set_border_width(20)
                row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                label = Gtk.Label()
                label.set_markup('<b>Select a menu to restore</b>')
                row.pack_start(label, False, False, 10)
                scroll = Gtk.ScrolledWindow()
                scroll.set_min_content_width(-1)
                scroll.set_min_content_height(180)
                vbox.pack_start(row, False, False, 0)
                vbox.pack_start(scroll, True, True, 0)
                listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
                listbox.set_activate_on_single_click(False)
                listbox.connect("selected-rows-changed", row_change)
                listbox.connect("row-activated", selection_made, -5)
                scroll.add(listbox)
                for i in data:
                    row = Gtk.ListBoxRow()
                    row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                    row_box.pack_start(Gtk.Label(label='{}'.format(i)), False, False, 0)
                    row.add(row_box)
                    listbox.insert(row, -1)
                listbox.show_all()
                listbox.select_row(listbox.get_row_at_index(0))
                notebook.append_page(vbox, Gtk.Label(label='Restore'))

        def app_tab():
            scroll = Gtk.ScrolledWindow()
            scroll.set_min_content_width(-1)
            scroll.set_min_content_height(340)
            notebook.append_page(scroll, Gtk.Label(label='Items'))
            listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
            listbox.set_activate_on_single_click(False)
            listbox.connect("row-activated", selection_made, -5)
            scroll.add(listbox)
            for i in data:
                row = Gtk.ListBoxRow()
                row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                icon = i[3]
                try:
                    image = Gtk.Image()
                    image.set_from_pixbuf(self.update_icon(icon, 24, 'image-missing'))
                    row_box.pack_start(image, False, False, 0)
                    row_box.pack_start(Gtk.Label(label='{}\n{}'.format(i[0], i[1])), False, False, 0)
                    row.add(row_box)
                    listbox.insert(row, -1)
                except gi.repository.GLib.Error:
                    print('unable to process image')
            listbox.show_all()
            listbox.select_row(listbox.get_row_at_index(0))

        def remove_tab():
            scroll = Gtk.ScrolledWindow()
            scroll.set_min_content_width(-1)
            scroll.set_min_content_height(240)
            remove_listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
            remove_listbox.set_activate_on_single_click(False)
            scroll.add(remove_listbox)
            try:
                selected_menu = self.menu_files[self.menu_combo.get_active()]
            except:
                selected_menu = ''
            for i in self.menu_files:
                row = Gtk.ListBoxRow()
                row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                if i == selected_menu:
                    label_text = '{}\t<b>* selected for editing</b>\n{}'.format(i[0], i[1])
                else:
                    label_text = '{}\n{}'.format(i[0], i[1])
                label = Gtk.Label()
                label.set_markup(label_text)
                row_box.pack_start(label, False, False, 5)
                row.add(row_box)
                remove_listbox.insert(row, -1)
            remove_listbox.show_all()
            remove_listbox.select_row(remove_listbox.get_row_at_index(0))
            vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
            vbox.add(row)
            notebook.append_page(vbox, Gtk.Label(label='Remove'))
            message = '\n<big><b>Remove a Menu</b></big>'
            label = Gtk.Label()
            label.set_markup(message)
            row.pack_start(label, False, False, 15)
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
            delete_check.connect("clicked", check_swap, keep_check)
            keep_check.connect("clicked", check_swap, delete_check)
            row.pack_start(keep_check, False, False, 40)
            vbox.pack_start(row, False, False, 0)
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
            row.pack_start(delete_check, False, False, 40)
            vbox.pack_start(row, False, False, 0)
            keep_check.set_active(True)
            vbox.pack_start(scroll, True, True, 0)

        def browser_tab():
            def file_change(button):
                if dialog_type == 'app':
                    self.selected_list_item = file_chooser.get_filename()
                elif dialog_type == 'add_menu':
                    self.selected_list_item = file_chooser.get_filename()
                    status_label.set_text('')
                elif dialog_type == 'icon':
                    icon = file_chooser.get_filename()
                    if icon:
                        if os.path.isfile(icon):
                            self.selected_list_item = icon
                    icon = self.update_icon(self.selected_list_item, 48, 'image-missing')
                    self.selected_preview.set_from_pixbuf(icon)

            # Tab 2 file chooser
            browse_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
            browse_page.add(box)
            notebook.append_page(browse_page, Gtk.Label(label='File Browser'))
            file_chooser = Gtk.FileChooserWidget(action=Gtk.FileChooserAction.OPEN)
            if dialog_type == 'app':
                file_chooser.set_current_folder('/usr/bin')
            elif dialog_type == 'icon':
                file_chooser.set_current_folder('/usr/share/icons')
                file_filter = Gtk.FileFilter()
                for pat in ['*.png', '*.svg', '*.xpm,', '*.jpg', '*.jpeg']:
                    file_filter.add_pattern(pat)
                file_filter.set_name('images')
                file_chooser.add_filter(file_filter)
            elif dialog_type == 'add_menu':
                file_chooser.set_current_folder(os.path.expanduser('~/.config/jwm/'))
            file_chooser.connect("file-activated", selection_made, '', -5)
            file_chooser.connect("selection-changed", file_change)
            box.add(file_chooser)
        if dialog_type == 'app':
            message = '\t<big><b>Select an Application</b></big>\n\tfrom list or file Browser'
            title = 'Select an Application'
            icon = '/usr/share/pixmaps/jwmkit/traybutton.svg'
        elif dialog_type == 'icon':
            self.selected_list_item = self.icon_entry.get_text()
            message = '<big><b>Select an icon</b></big>\nfrom the icon viewer or file browser'
            title = 'Select an Icon'
            icon = self.selected_list_item
            self.selected_preview = Gtk.Image()
            self.selected_preview.set_from_pixbuf(self.update_icon(icon, 48, 'image-missing'))
            path_check = Gtk.CheckButton(label='Full Path')
            path_check.set_tooltip_text('Use full path instead of icon name')
        elif dialog_type == 'add_menu':
            message = '\t<big><b>Add or Remove a Menu</b></big>\n\tCreate, restore, import, or remove a Menu.'
            title = 'Add Menu'
            icon = '/usr/share/pixmaps/jwmkit/menugray.svg'
        elif dialog_type == 'move_copy':
            message = '<big><b>Copy or Move</b></big>\nSelect operation &amp; target'
            title = 'Copy / Move'
            icon = '/home/riot/storage/python/JWMKit/icons/showdesktop.svg'
            copy_check = Gtk.CheckButton(label='Copy')
            move_check = Gtk.CheckButton(label='Move')
            copy_check.connect("clicked", check_swap, move_check)
            move_check.connect("clicked", check_swap, copy_check)
            copy_check.set_active(True)

        dialog = Gtk.Dialog(title, self, 0)
        dialog.set_default_size(370, 340)
        dialog.set_border_width(10)

        cancel_button = Gtk.Button(label='Cancel', image=Gtk.Image(stock=Gtk.STOCK_CANCEL))
        apply_button = Gtk.Button(label='Apply', image=Gtk.Image(stock=Gtk.STOCK_APPLY))
        cancel_button.set_always_show_image(True)
        apply_button.set_always_show_image(True)
        cancel_button.set_property("width-request", 90)
        apply_button.set_property("width-request", 90)
        cancel_button.connect("clicked", selection_made, '', -6)
        apply_button.connect("clicked", selection_made, '', -5)
        vbox = dialog.get_content_area()
        vbox.set_spacing(10)

        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        row.pack_end(apply_button, False, False, 0)
        row.pack_end(cancel_button, False, False, 0)
        if dialog_type == 'add_menu':
            onroot_entry = Gtk.Entry()
            row.pack_end(onroot_entry, False, False, 0)
            onroot_label = Gtk.Label(label='onroot:')
            row.pack_end(onroot_label, False, False, 0)
            status_label = Gtk.Label()
            status_label.set_text('test')
            row.pack_end(status_label, True, True, 0)
        elif dialog_type == 'icon':
            row.pack_start(path_check, False, False, 20)
        elif dialog_type == 'app':
            name_check = Gtk.CheckButton(label='Set Name')
            name_check.set_tooltip_text("Allow / Deny updating name entry")
            icon_check = Gtk.CheckButton(label='Set Icon')
            icon_check.set_tooltip_text("Allow / Deny updating icon entry")
            tooltip_check = Gtk.CheckButton(label='Set Tooltip')
            tooltip_check.set_tooltip_text("Allow / Deny updating tooltip entry")
            name_check.set_active(True)
            icon_check.set_active(True)
            tooltip_check.set_active(True)
            row.pack_start(name_check, False, False, 10)
            row.pack_start(icon_check, False, False, 10)
            row.pack_start(tooltip_check, False, False, 10)
        vbox.pack_end(row, False, False, 0)
        label = Gtk.Label()
        label.set_markup(message)
        row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        if dialog_type == 'icon':
            row.pack_start(self.selected_preview, False, False, 0)
        elif dialog_type == 'move_copy':
            image = Gtk.Image.new_from_icon_name(Gtk.STOCK_COPY, size=Gtk.IconSize.DIALOG)
            row.pack_start(image, False, False, 0)
        else:
            image = Gtk.Image()
            image.set_from_pixbuf(self.update_icon(icon, 48, 'image-missing'))
            row.pack_start(image, False, False, 0)
        row.pack_start(label, False, False, 0)
        if dialog_type == 'move_copy':
            vbox.pack_start(row, False, False, 0)
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
            row.pack_start(copy_check, False, False, 50)
            row.pack_start(move_check, False, False, 0)
        vbox.pack_start(row, False, False, 0)
        notebook = Gtk.Notebook()
        notebook.set_border_width(15)
        vbox.add(notebook)
        if dialog_type == 'app':
            listbox = Gtk.ListBox()
            data = self.app_data
            notebook.connect("switch-page", hide_app_checks)
            app_tab()
            browser_tab()
        elif dialog_type == 'icon':
            notebook.connect("switch-page", hide_path_check)
            icon_tab()
            browser_tab()
        elif dialog_type == 'add_menu':
            notebook.connect("switch-page", hide_remove_widgets)
            listbox = Gtk.ListBox()
            menu_entry = Gtk.Entry()
            data = self.get_unused_menus()
            row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
            onroot_message = Gtk.Label(label='* onroot value must be assigned to continue')
            row.pack_end(onroot_message, False, False, 20)
            vbox.pack_end(row, False, False, 10)
            remove_listbox = Gtk.ListBox()
            keep_check = Gtk.CheckButton(label="Keep:   Menu is removed, but can be restored")
            delete_check = Gtk.CheckButton(label="Delete: Menu is removed, and deleted.  "
                                                 "It can NOT be be restored")
            onroot_entry.set_no_show_all(True)
            onroot_label.set_no_show_all(True)
            notebook.connect("switch-page", clear_status)
            menu_entry.connect('changed', clear_status, '', '')
            menu_tab()
            browser_tab()
            remove_tab()
        elif dialog_type == 'move_copy':
            listbox = Gtk.ListBox()
            data = copy.deepcopy(self.menu_buttons)
            copy_tab()
        dialog.show_all()
        dialog.run()

    def listbox_double(self, listbox, row):
        index = row.get_index()
        if self.select_menu_data[index][0] != 'Separator':
            self.dialogs('move_copy')

    def icon_entry_pressed(self, entry, icon_pos, event):
        self.dialogs('icon')

    def cmd_entry_pressed(self, entry, icon_pos, event):
        self.dialogs('app')

    def icon_preview(self, entry):
        if self.select_menu_data[0] not in ['Include', 'Separator']:
            icon = entry.get_text()
            self.preview_icon.set_from_pixbuf(self.update_icon(icon, 32, 'image-missing'))

    def on_add_item(self, button):
        self.popover.set_relative_to(button)
        self.popover.show_all()
        self.popover.popup()

    def move_index(self):
        count = 0
        for child in self.menu_xml.findall('.//'):
            child.attrib['index'] = count
            count += 1

    def pop_add_item(self, button, add_type):
        def make_element():
            icon_path = '/usr/share/pixmaps/jwmkit/'
            icon_dict = {'Menu': 'folder_blue', 'Dynamic': 'folder_red', 'Restart': 'restartgray', 'Exit': 'exitgray',
                         'SendTo': 'sendtogray', 'Desktops': 'pager', 'Kill': 'killgray', 'Close': 'closegray',
                         'Stick': 'showdesktop', 'Maximize': 'showdesktop', 'Minimize': 'showdesktop',
                         'Shade': 'showdesktop', 'Move': 'showdesktop', 'Resize': 'showdesktop',
                         'Program': 'program'}
            new_element = ET.Element(add_type)
            new_element.attrib['index'] = xml_index
            if add_type == 'Easy Menu':
                new_element.tag = 'Include'
                new_element.text = 'exec:jwmkit_easymenu'
            elif add_type not in ('Include', 'Separator'):
                new_element.attrib['label'] = add_type
                new_element.attrib['icon'] = os.path.join(icon_path, icon_dict[add_type] + '.svg')
            return new_element

        def find_parent(parent):
            for child in parent:
                if child.get('index') == xml_index:
                    new_element = make_element()
                    parent.insert(index, new_element)
                    if parent.get('index') == 0:
                        menu = 'Root Level'
                    else:
                        menu = parent.get('label')
                    self.move_index()
                    self.select_menu_data = self.get_listbox_items(parent.get('index'))
                    self.populate_listbox()
                    break
                if len(child) > 0:
                    find_parent(child)

        try:
            index = self.listbox_mid_mid.get_selected_rows()[0].get_index()
            xml_index = self.select_menu_data[index][-1]
            find_parent(self.menu_xml[0])
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(index))
        except IndexError:
            # exception cause by empty menu
            xml_index = self.selected_menu[2]
            for parent in self.menu_xml.findall(".//"):
                if parent.get('index') == xml_index:
                    new_element = make_element()
                    parent.append(new_element)
                    self.move_index()
                    self.select_menu_data = self.get_listbox_items(xml_index)
                    self.populate_listbox()
                    self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(0))
                    break
        self.make_buttons()

    def update_data(self, i):
        def update_helper(value, var):
            if var != '':
                child.attrib[value] = var
        try:
            row = self.select_menu_data[i]
        except IndexError:
            return
        index = row[8]
        name = self.name_entry.get_text()
        comment = self.comment_entry.get_text()
        icon = self.icon_entry.get_text()
        cmd = self.command_entry.get_text()
        if self.height_check.get_active():
            height = str(int(self.menu_h_spin.get_value()))
        else:
            height = ''
        if self.confirm_switch.get_active():
            if row[0] == 'Exit':
                confirm = 'true'
                labeled = ''
            else:
                labeled = 'true'
                confirm = ''
        else:
            confirm = ''
            labeled = ''
        if row != [row[0], icon, name, comment, height, labeled, confirm, cmd, index]:
            for child in self.menu_xml.findall('.//'):
                if child.get('index') == index:
                    child.attrib.clear()
                    child.text = ''
                    update_helper('label', name)
                    update_helper('icon', icon)
                    update_helper('tooltip', comment)
                    update_helper('height', height)
                    update_helper('confirm', confirm)
                    update_helper('labeled', labeled)
                    update_helper('index', index)
                    child.text = cmd
                    break
            self.select_menu_data[self.previous_index] = \
                [row[0], icon, name, comment, height, labeled, confirm, cmd, index]
            self.listbox_mid_mid.remove(self.listbox_mid_mid.get_row_at_index(i))
            self.update_listbox_row([row[0], icon, name, comment, height, labeled, confirm, cmd, index], i)
            if row[0] == 'Menu':
                if row[1] != icon or row[2] != name:
                    self.make_buttons()

    def listbox_changed(self, listbox):
        def hide_show():
            # hide / show widget depending on entry_type
            self.icon_entry.set_visible(values[0])
            self.icon_label.set_visible(values[0])
            self.name_entry.set_visible(values[1])
            self.name_label.set_visible(values[1])
            self.comment_entry.set_visible(values[2])
            self.comment_label.set_visible(values[2])
            self.menu_h_spin.set_visible(values[3])
            self.height_check.set_visible(values[4])
            self.confirm_switch.set_visible(values[5])
            self.confirm_label.set_visible(values[6])
            self.command_entry.set_visible(values[7])
            self.command_label.set_visible(values[7])
            self.easy_button.set_visible(False)

        row = self.listbox_mid_mid.get_selected_row()
        do_return = False
        # quit function if no selected row
        if not row:
            self.item_label.set_text('')
            self.preview_icon.clear()
            values = (False, False, False, False, False, False, False, False)
            hide_show()
            return
        if self.previous_index != -2:
            # do not update if the current row is the same as the previous
            # to prevent update if the same row is selected again.
            if row:
                if self.confirm_switch.get_active():
                    if self.select_menu_data[row.get_index()][0] == 'Exit':
                        confirm = 'true'
                        labeled = ''
                    else:
                        labeled = 'true'
                        confirm = ''
                else:
                    confirm = ''
                    labeled = ''
                if self.previous_index != row.get_index():
                    self.update_data(self.previous_index)
                elif self.select_menu_data[row.get_index()][1:3] != \
                        [self.icon_entry.get_text(), self.name_entry.get_text(), self.comment_entry.get_text(),
                         str(int(self.menu_h_spin.get_value())), labeled, confirm, self.command_entry.get_text()]:
                    do_return = True
        self.previous_index = row.get_index()
        if self.select_menu_data:
            row_data = self.select_menu_data[self.previous_index]
        else:
            return
        if do_return:
            return
        entry_type = row_data[0]
        values = (True, True, True, False, False, False, False, False)
        if entry_type == 'Menu':
            self.confirm_label.set_text('Show Label')
            values = (True, True, True, True, True, True, True, False)
        elif entry_type == 'Dynamic':
            self.confirm_label.set_text('Show Label')
            values = (True, True, True, True, True, True, True, True)
        elif entry_type == 'Include':
            values = (False, False, False, False, False, False, False, True)
        elif entry_type == 'Program':
            values = (True, True, True, False, False, False, False, True)
        elif entry_type == 'Exit':
            self.confirm_label.set_text('Confirm')
            values = (True, True, True, False, False, True, True, True)
        elif entry_type == 'Separator':
            values = (False, False, False, False, False, False, False, False)
        hide_show()

        label = row_data[0]
        if row_data[0] in ['Include', 'Separator']:
            self.icon_entry.set_text('')
            self.preview_icon.clear()
            label = ''
            if row_data[7].startswith('exec:jwmkit_easymenu'):
                self.easy_button.set_visible(True)

        self.item_label.set_markup('\t<b>{}</b>'.format(label))
        self.icon_entry.set_text(row_data[1])
        self.name_entry.set_text(row_data[2])
        self.comment_entry.set_text(row_data[3])
        if row_data[4] != '':
            self.height_check.set_active(True)
            self.menu_h_spin.set_sensitive(True)
            self.height_check.set_active(True)
            self.menu_h_spin.set_value(int(row_data[4]))
        else:
            self.height_check.set_active(False)
            self.menu_h_spin.set_sensitive(False)
            self.height_check.set_active(False)
            self.menu_h_spin.set_value(0)
        if row_data[5] == 'true':
            self.confirm_switch.set_active(True)
        elif row_data[6] == 'true':
            self.confirm_switch.set_active(True)
        else:
            self.confirm_switch.set_active(False)
        self.command_entry.set_text(row_data[7])
        if row_data[0] == 'Menu':
            self.command_entry.set_text('')

    def get_used_onroot(self, combo):
        values = []
        if combo != '':
            current_menu = self.menu_files[combo.get_active()]
        else:
            current_menu = ''

        for filename in self.menu_files:
            if filename != current_menu:
                try:
                    tree = ET.parse(filename[1])
                    root = tree.getroot()
                    if root.tag == 'JWM':
                        value = root[0].get('onroot')
                        if not value:
                            value = ''
                        values.append(value.upper())
                except (ET.ParseError, IndexError):
                    print('onroot is not defined in {}'.format(filename[1]))
        return values

    def onroot_change(self, entry, combo):
        onroot_values = self.get_used_onroot(combo)
        input_data = entry.get_text().upper()
        # limit input to alphanumeric characters
        if not input_data.isalnum():
            entry.set_text(input_data[:-1])
            return
        # prevent double entries
        input_data = list(set(input_data))
        input_data.sort()
        # prevent values used by another menu
        invalid_entry = set(input_data) & set(onroot_values)
        if invalid_entry:
            invalid_entry = list(invalid_entry)[0]
            input_data.remove(invalid_entry)
        if input_data:
            input_data = "".join(list(input_data))
        else:
            input_data = ''
        entry.set_text(input_data)

    def on_menu_check(self, check):
        if check.get_active():
            self.menu_h_spin.set_sensitive(True)
        else:
            self.menu_h_spin.set_sensitive(False)

    def update_listbox_row(self, element, insert_row):
        row = Gtk.ListBoxRow()
        row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        if element[0] == 'Separator':
            row_box.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), True, True, 0)
            row_box.pack_start(Gtk.Label(label='Separator'), False, False, 0)
            row_box.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), True, True, 0)
        else:
            icon = element[1]
            label = element[2]
            if element[0] == 'Include':
                icon = '/usr/share/pixmaps/jwmkit/link.svg'
                label = 'Include'
            if icon != '':
                image = Gtk.Image()
                image.set_from_pixbuf(self.update_icon(icon, 24, 'image-missing'))
                row_box.add(image)
            else:
                row_box.add(Gtk.Label(label='\t'))
            label = Gtk.Label(label=label)
            if element[0] == 'Menu':
                label.set_markup('<big><b>{}</b></big>'.format(element[2]))
            elif element[0] == 'Dynamic':
                label.set_markup('<big><b><i>{}</i></b></big>'.format(element[2]))
            row_box.add(label)
        row.add(row_box)
        self.listbox_mid_mid.insert(row, insert_row)
        self.listbox_mid_mid.show_all()

    def populate_listbox(self):
        self.clear_list()
        if self.select_menu_data:
            for element in self.select_menu_data:
                self.previous_index = -2
                self.update_listbox_row(element, -1)
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(0))

    def clear_list(self):
        ok = True
        while ok:
            try:
                self.listbox_mid_mid.remove(self.listbox_mid_mid.get_row_at_index(0))
            except (IndexError, TypeError):
                ok = False

    def on_menu_selection(self, combo):
        i = combo.get_active()
        try:
            self.menu_xml = get_menu_xml(self.menu_files[i][1])
            self.move_index()
            self.get_properties()
            self.make_buttons()
            button = ('Root Level', '/usr/share/pixmaps/jwmkit/folder_root_blue.svg', 0)
            self.get_selected_menu('', button)
        except IndexError:
            self.menu_xml = ''

    def make_buttons(self):
        box = self.mid_left
        menu_buttons = self.get_menus_list()
        self.menu_buttons = menu_buttons
        for element in box:
            element.destroy()
        left_header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        box.add(Gtk.Label())
        box.pack_start(left_header_box, False, False, 0)
        for menu_button in menu_buttons:
            image = Gtk.Image()
            image.set_from_pixbuf(self.update_icon(menu_button[1], 24, 'image-missing'))
            button = Gtk.Button(image=image, label=menu_button[0], xalign=0)
            button.set_property("width-request", 120)
            button.set_relief(Gtk.ReliefStyle.NONE)
            button.set_always_show_image(True)
            button.connect('clicked', self.get_selected_menu, menu_button)
            box.add(button)
        box.add(Gtk.Separator())
        box.show_all()

    def update_icon(self, icon, size, missing):
        if not os.path.isfile(icon):
            if '/' in icon:
                icon = ''
            try:
                icon = self.get_icon_dir(icon)
                icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon, size, size, preserve_aspect_ratio=False)
            except IndexError:
                icon = Gtk.IconTheme.get_default().load_icon(missing, size, Gtk.IconLookupFlags.FORCE_SIZE)
        else:
            icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon, size, size, preserve_aspect_ratio=False)
        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:
                    if os.path.isfile(os.path.join(icon_dir, icon)):
                        icons.append(os.path.join(icon_dir, icon))
                    while '' in icons: icons.remove('')
                    if icons:
                        break
        return icons[0]

    def get_menus_list(self):
        menu_data = [['Root Level', '/usr/share/pixmaps/jwmkit/folder_root_blue.svg', 0]]
        for child in self.menu_xml.findall('.//'):
            if child.tag == 'Menu':
                data = [child.get('label'), child.get('icon'), child.get('index')]
                data = ['' if i is None else i for i in data]
                menu_data.append(data)
        return menu_data

    def update_properties(self):
        attributes = [('label', self.label_entry.get_text()), ('onroot', self.onroot_entry.get_text()),
                      ('height', str(int(self.file_h_spin.get_value())))]
        if self.label_switch.get_active():
            attributes.append(('labeled', 'true'))
        else:
            attributes.append(('labeled', ''))
        attributes.append(('index', 0))
        self.menu_xml[0].attrib.clear()
        for attribute in attributes:
            if attribute[1] != '':
                self.menu_xml[0].attrib[attribute[0]] = attribute[1]

    def get_unused_menus(self):
        def make_file_list(tmp_list, tmp_dir):
            for file in tmp_list:
                file = os.path.join(tmp_dir, file)
                if os.path.isfile(file):
                    file_list.append(file)
                elif os.path.isdir(file):
                    tmp_dir1 = file
                    make_file_list(os.listdir(tmp_dir1), tmp_dir1)

        home = os.path.expanduser('~')
        path = os.path.join(home, '.config/jwm/')
        tmp_file_list = os.listdir(path)
        file_list, vaild_list = [], []
        make_file_list(tmp_file_list, path)

        open(os.path.join(home, '.config/jwmkit/settings'), 'a').close()
        with open(os.path.join(home, '.config/jwmkit/settings')) as f:
            f = f.read()
        f = '\n{}'.format(f)
        menu_paths = re.findall('\nmenu.*=(.+)', f)
        if menu_paths:
            for file in menu_paths:
                if file.startswith('$HOME'):
                    file = os.path.join(home, file[6:])
                if os.path.isfile(file):
                    file_list.append(file)
        file_list = list(set(file_list))
        menu_files = []
        for menu_file in self.menu_files:
            menu_files.append(menu_file[1])

        for file in file_list:
            if verify_menu(file):
                if file not in menu_files:
                    vaild_list.append(file)
        return vaild_list

    def get_properties(self):
        data = [self.menu_xml[0].get('label'), self.menu_xml[0].get('onroot'), self.menu_xml[0].get('labeled'),
                self.menu_xml[0].get('height'), self.menu_xml[0].get('dynamic')]
        data = ['' if i is None else i for i in data]
        data[1] = data[1].upper()
        if data[1] == '':
            print('Warning onroot value is not assigned!'.format())
        self.label_entry.set_text(data[0])
        self.onroot_entry.set_text(data[1])
        if data[2] == 'true':
            self.label_switch.set_active(True)
        else:
            self.label_switch.set_active(False)
        if data[3] != '':
            self.file_h_spin.set_value(int(data[3]))
        else:
            self.file_h_spin.set_value(0)
        if data[4] != '':
            self.dynamic_label.set_visible(True)
            self.dynamic_entry.set_visible(True)
            self.dynamic_entry.set_text(data[4])
        else:
            self.dynamic_label.set_visible(False)
            self.dynamic_entry.set_visible(False)
            self.dynamic_entry.set_text('')
        return data

    def get_listbox_items(self, menu):
        def get_items():
            data = [child.tag, child.get('icon'), child.get('label'), child.get('tooltip'), child.get('height'),
                    child.get('labeled'), child.get('confirm'), child.text, child.get('index')]
            data = ['' if i is None else i for i in data]
            if data[0] not in ['Program', 'Dynamic', 'Exit', 'Include']:
                data[7] = ''
            menu_data.append(data)

        menu_data = []
        if menu == 0:
            for child in self.menu_xml[0]:
                get_items()
        else:
            for node in self.menu_xml.findall('.//'):
                if node.tag == 'Menu':
                    if node.get('index') == menu:
                        for child in node:
                            get_items()
                        break
        return menu_data

    def get_selected_menu(self, button, menus):
        self.selected_menu = menus
        icon = menus[1]
        menu = menus[0]
        index = menus[2]
        if self.previous_index != -2:
            self.update_data(self.previous_index)
        if icon != 'xxx_no_icon_':
            self.cat_icon.set_from_pixbuf(self.update_icon(icon, 24, 'image-missing'))
            self.cat_label.set_markup('<big><b>{}</b></big>'.format(menu))
        self.select_menu_data = self.get_listbox_items(index)
        self.populate_listbox()

    def move_up(self, button):
        def parent_move(parent):
            for child in parent:
                if child.get('index') == index1:
                    parent.remove(child)
                    parent.insert(i-1, child)
                    self.move_index()
                    self.select_menu_data = self.get_listbox_items(parent.get('index'))
                    break
                if len(child) > 0:
                    parent_move(child)

        i = self.listbox_mid_mid.get_selected_rows()[0].get_index()
        menu_data = self.select_menu_data
        if i != 0:
            selected_row = self.listbox_mid_mid.get_row_at_index(i)
            self.previous_index = selected_row.get_index() - 1
            self.listbox_mid_mid.remove(selected_row)
            self.listbox_mid_mid.insert(selected_row, i - 1)
            index1 = menu_data[i][-1]
            parent_move(self.menu_xml[0])
            self.make_buttons()
            # Ensure data is preserved by selecting the previous row before the current row
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(i))
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(i-1))

    def move_down(self, button):
        def parent_move(parent):
            for child in parent:
                if child.get('index') == index2:
                    parent.remove(child)
                    parent.insert(i+1, child)
                    self.move_index()
                    self.select_menu_data = self.get_listbox_items(parent.get('index'))
                if len(child) > 0:
                    parent_move(child)

        i = self.listbox_mid_mid.get_selected_rows()[0].get_index()
        menu_data = self.select_menu_data
        if i != len(self.listbox_mid_mid)-1:
            selected_row = self.listbox_mid_mid.get_row_at_index(i)
            self.previous_index = selected_row.get_index() + 1
            self.listbox_mid_mid.remove(selected_row)
            self.listbox_mid_mid.insert(selected_row, i + 1)
            index2 = menu_data[i][-1]
            parent_move(self.menu_xml[0])
            self.make_buttons()
            # Ensure data is preserved by selecting the previous row before the current row
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(i))
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(i+1))

    def confirm_dialog(self, button, title, message, info):
        dialog = Gtk.Dialog(title, self, 0)
        box = dialog.get_content_area()
        if button == 'b1':
            dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_REMOVE, Gtk.ResponseType.OK)
        elif button == 'b3':
            dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_REMOVE, Gtk.ResponseType.OK)
            keep_check = Gtk.CheckButton(label="Remove but keep the file. Menu can be restored")
            delete_check = Gtk.CheckButton(label="Remove and delete the file.")
            delete_check.connect("clicked", check_swap, keep_check)
            keep_check.connect("clicked", check_swap, delete_check)
            keep_check.set_active(True)
        else:
            dialog.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK)
        label = Gtk.Label(xalign=0)
        label.set_markup("<b>{}</b>\n".format(message))
        dialog.set_default_size(370, -1)
        box.set_border_width(20)
        box.add(label)
        label = Gtk.Label(label=info, xalign=0)
        box.add(label)
        if button == 'b3':
            box.add(keep_check)
            box.add(delete_check)
        dialog.show_all()
        if button == 'b1':
            response = dialog.run()
            dialog.destroy()
            return response
        elif button == 'b3':
            response = dialog.run()
            dialog.destroy()
            return response, delete_check.get_active()
        else:
            dialog.run()
            dialog.destroy()

    def easy_dialog(self, button):
        # configure easy_menu parameters
        def create_easy_cmd(button):
            cmd = 'exec:jwmkit_easymenu'
            # Terminal
            i = term_combo.get_active()
            if i == -1:
                tmp = term_combo.get_child().get_text()
            else:
                tmp = self.app_data[i-1][2]
                while tmp[-3:] in [' %U', ' %u', ' %F', ' %f', ' %i', ' %c', ' %k']:
                    tmp = '{}'.format(tmp[:-3])
                tmp = tmp.strip('"')
            if os.path.isfile(tmp) and os.access(tmp, os.X_OK):
                cmd = '{} -t:"{}"'.format(cmd, tmp)
            else:
                try:
                    subprocess.check_output('type {}'.format(tmp), shell=True, stderr=subprocess.STDOUT)
                    if len(tmp) > 1:
                        if tmp[0].isalnum():
                            cmd = '{} -t:"{}"'.format(cmd, tmp)
                except subprocess.CalledProcessError:
                    pass
            # Locale
            tmp = lang_combo.get_child().get_text()
            if tmp not in ['Default', '']:
                if '_' in tmp:
                    cmd = '{} -lt:"{}"'.format(cmd, tmp)
                else:
                    cmd = '{} -l:"{}"'.format(cmd, tmp)
            # No Dubs, and No Kit Menu options
            if dub_check.get_active():
                cmd = '{} -nodubs'.format(cmd)
            if kit_menu_check.get_active():
                cmd = '{} -nokitmenu'.format(cmd)
            # Merge Category
            for host, guest in zip(host_cats, merged_cats):
                cmd = '{} -m:"{}"'.format(cmd, host)
                for g in guest:
                    cmd = '{}:"{}"'.format(cmd, g)
            # Rename Category
            for old, new in zip(old_cats, new_cats):
                cmd = '{} -r:"{}":"{}"'.format(cmd, old, new)
            # hide category
            if hidden_cats:
                cmd = '{} -hc'.format(cmd)
            for hidden in hidden_cats:
                cmd = '{}:"{}"'.format(cmd, hidden)
            # hide app
            if hidden_apps:
                cmd = '{} -ha'.format(cmd)
            for hidden in hidden_apps:
                hidden = hidden[2].strip('"')
                while hidden[-3:] in [' %U', ' %u', ' %F', ' %f', ' %i', ' %c', ' %k']:
                    hidden = '{}'.format(hidden[:-3])
                hidden = hidden.strip('"')
                cmd = '{}:"{}"'.format(cmd, hidden)
            self.command_entry.set_text(cmd)
            dialog.destroy()

        def remove_rc(button, i):
            del old_cats[i]
            del new_cats[i]
            set_rc_label()

        def remove_hc(button, i):
            del hidden_cats[i]
            set_hc_label()

        def remove_ha(button, i):
            del hidden_apps[i]
            set_ha_label()

        def remove_mc(button, i, ii):
            cat_names.append(merged_cats[i][ii])
            merged_cat_combo.append_text(merged_cats[i][ii])
            merge_cat_combo.append_text(merged_cats[i][ii])
            if len(merged_cats[i]) == 1:
                del host_cats[i]
                del merged_cats[i]
            else:
                del merged_cats[i][ii]
            set_merge_label()

        def set_rc_label():
            for child in rc_box:
                rc_box.remove(child)
            i = 0
            for old, new in zip(old_cats, new_cats):
                button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_REMOVE))
                button.connect("clicked", remove_rc, i)
                box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                box.pack_start(button, False, False, 5)
                box.pack_start(Gtk.Label(label='{} --> {}'.format(old, new)), False, False, 0)
                rc_box.pack_start(box, False, False, 0)
                i += 1
            rc_box.show_all()

        def set_merge_label():
            for child in mc_box:
                mc_box.remove(child)
            i = 0
            for host, guest in zip(host_cats, merged_cats):
                ii = 0
                for g in guest:
                    button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_REMOVE))
                    button.connect("clicked", remove_mc, i, ii)
                    box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                    box.pack_start(button, False, False, 5)
                    box.pack_start(Gtk.Label(label='merge {} into {}'.format(g, host)), False, False, 0)
                    mc_box.pack_start(box, False, False, 0)
                    ii += 1
                i += 1
            mc_box.show_all()

        def set_ha_label():
            for child in ha_box:
                ha_box.remove(child)
            i = 0
            for ha in hidden_apps:
                button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_REMOVE))
                button.connect("clicked", remove_ha, i)
                box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                box.pack_end(button, False, False, 5)
                box.pack_end(Gtk.Label(label=ha[0]), False, False, 0)
                ha_box.pack_start(box, False, False, 0)
                i += 1
            ha_box.show_all()

        def set_hc_label():
            for child in hc_box:
                hc_box.remove(child)
            i = 0
            for hc in hidden_cats:
                button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_REMOVE))
                button.connect("clicked", remove_hc, i)
                box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
                box.pack_end(button, False, False, 5)
                box.pack_end(Gtk.Label(label=hc), False, False, 0)
                hc_box.pack_start(box, False, False, 0)
                i += 1
            hc_box.show_all()

        def close_action(button):
            dialog.destroy()

        def clear_term(button):
            term_combo.get_child().set_text('')

        def add_hide_app(button):
            i = hid_app_combo.get_active()
            if i != -1:
                if self.app_data[i] not in hidden_apps:
                    hidden_apps.append(self.app_data[i])
            hid_app_combo.set_active(-1)
            set_ha_label()

        def add_hide_cat(button):
            i = hide_cat_combo.get_active()
            if i != -1:
                if copy_cat[i] not in hidden_cats:
                    hidden_cats.append(copy_cat[i])
            hide_cat_combo.set_active(-1)
            set_hc_label()

        def rename_cat(button):
            new_name = rename_cat_entry.get_text()
            if new_name in [None, '']:
                return
            i = rename_cat_combo.get_active()
            if i == -1:
                return
            old_name = copy_cat[i]
            if new_name == old_name:
                return
            if old_name in old_cats:
                i = old_cats.index(old_name)
                del old_cats[i]
                del new_cats[i]
            old_cats.append(old_name)
            new_cats.append(new_name)
            set_rc_label()

        def merger_cat(button):
            id = merge_cat_combo.get_active()
            if id == -1:
                return
            merge_cat = cat_names[id]
            i = merged_cat_combo.get_active()
            if i == -1:
                return
            host_cat = cat_names[i]
            if host_cat == merge_cat:
                return
            if merge_cat in host_cats:
                return
            if host_cat in host_cats:
                i = host_cats.index(host_cat)
                merged_cats[i].append(merge_cat)
            else:
                host_cats.append(host_cat)
                merged_cats.append([merge_cat])
            merged_cat_combo.remove(id)
            merge_cat_combo.remove(id)
            del cat_names[id]
            merge_cat_combo.show_all()
            merged_cat_combo.show_all()
            set_merge_label()
        cat_names = ['Accessories', 'Education', 'Development', 'Games', 'Graphics', 'Internet',
                           'Multimedia', 'Office', 'Other', 'Settings', 'Science', 'System', 'JWM Kit']
        copy_cat = cat_names.copy()
        hidden_apps, hidden_cats, old_cats, new_cats, host_cats, merged_cats = [], [], [], [], [], []
        data = self.command_entry.get_text().split(' ')[1:]
        locales = get_languages()

        dialog = Gtk.Dialog('Easy Menu', self, 0)
        dialog.set_default_size(700, 610)
        mainbox = dialog.get_content_area()
        mainbox.set_spacing(15)
        mainbox.set_border_width(20)
        easy_grid = Gtk.Grid(row_spacing=10, column_spacing=10)

        label = Gtk.Label()
        label.set_markup("<big><b>JWM Kit Easy Menu</b></big>\nConfigure Easy Menu")
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
        mainbox.pack_start(box, False, False, 0)
        mainbox.pack_start(easy_grid, False, False, 0)
        box.pack_start(jwmkit_utils.create_image('/usr/share/pixmaps/jwmkit/menugray.svg', 48, 48, True), False,
                       False, 20)
        box.pack_start(label, False, False, 20)
        lang_combo = Gtk.ComboBoxText.new_with_entry()
        term_combo = Gtk.ComboBoxText.new_with_entry()
        hid_app_combo = Gtk.ComboBoxText()
        hide_cat_combo = Gtk.ComboBoxText()
        rename_cat_combo = Gtk.ComboBoxText()
        rename_cat_entry = Gtk.Entry()
        merge_cat_combo = Gtk.ComboBoxText()
        merged_cat_combo = Gtk.ComboBoxText()
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        cancel_button = Gtk.Button(label='Cancel', image=Gtk.Image(stock=Gtk.STOCK_CANCEL))
        cancel_button.set_property("width-request", 100)
        cancel_button.set_always_show_image(True)
        cancel_button.connect("clicked", close_action)

        apply_button = Gtk.Button(label='Apply', image=Gtk.Image(stock=Gtk.STOCK_APPLY))
        apply_button.set_property("width-request", 100)
        apply_button.set_always_show_image(True)
        apply_button.connect("clicked", create_easy_cmd)

        mainbox.pack_end(box, False, False, 0)
        box.pack_end(apply_button, False, False, 0)
        box.pack_end(cancel_button, False, False, 0)
        term_combo.append_text('Default')
        for app in self.app_data:
            term_combo.append_text('{}'.format(app[0]))
            hid_app_combo.append_text('{}'.format(app[0]))
        term_combo.set_active(0)
        for name in cat_names:
            hide_cat_combo.append_text(name)
            rename_cat_combo.append_text(name)
            merge_cat_combo.append_text(name)
            merged_cat_combo.append_text(name)
        for lang in locales:
            lang_combo.append_text(lang)
        lang_combo.set_active(0)

        clear_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_DELETE))
        ha_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ADD))
        hc_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ADD))
        rc_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ADD))
        mc_button = Gtk.Button(image=Gtk.Image(stock=Gtk.STOCK_ADD))

        rc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        scroll_rc = Gtk.ScrolledWindow()
        scroll_rc.set_property("height-request", 100)
        scroll_rc.set_property("width-request", 350)
        scroll_rc.add(rc_box)

        mc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        scroll_mc = Gtk.ScrolledWindow()
        scroll_mc.set_property("height-request", 100)
        scroll_mc.set_property("width-request", 350)
        scroll_mc.add(mc_box)

        hc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        scroll_hc = Gtk.ScrolledWindow()
        scroll_hc.set_property("height-request", 100)
        scroll_hc.set_property("width-request", 350)
        scroll_hc.add(hc_box)

        ha_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        scroll_ha = Gtk.ScrolledWindow()
        scroll_ha.set_property("height-request", 100)
        scroll_ha.set_property("width-request", 350)
        scroll_ha.add(ha_box)

        dub_check = Gtk.CheckButton()
        dub_label = Gtk.Label(label='No Duplicates')
        dub_tip = 'Prevent Items fro appearing in multiple menus.\nItems will only appear in the first category listed'
        dub_check.set_tooltip_text(dub_tip)
        dub_label.set_tooltip_text(dub_tip)

        kit_menu_label = Gtk.Label(label='No JWM Kit Menu')
        kit_menu_check = Gtk.CheckButton()
        kit_menu_tip = "Check : JWM Kit Apps appear in settings\nUn-check : JWM Kit has it's own menu"
        kit_menu_check.set_tooltip_text(kit_menu_tip)
        kit_menu_label.set_tooltip_text(kit_menu_tip)

        clear_button.connect('clicked', clear_term)
        ha_button.connect('clicked', add_hide_app)
        hc_button.connect('clicked', add_hide_cat)
        rc_button.connect('clicked', rename_cat)
        mc_button.connect('clicked', merger_cat)

        easy_grid.attach(clear_button, 3, 1, 1, 1)
        easy_grid.attach(ha_button, 3, 2, 1, 1)
        easy_grid.attach(hc_button, 3, 3, 1, 1)
        easy_grid.attach(rc_button, 5, 4, 1, 1)
        easy_grid.attach(mc_button, 5, 5, 1, 1)
        easy_grid.attach(Gtk.Label(label="Terminal", xalign=1), 1, 1, 1, 1)
        easy_grid.attach(term_combo, 2, 1, 1, 1)

        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        box.pack_start(Gtk.Label(label='Language'), False, False, 0)
        box.pack_start(lang_combo, False, False, 0)
        easy_grid.attach(box, 4, 1, 2, 1)

        easy_grid.attach(Gtk.Label(label="Hide Application", xalign=1), 1, 2, 1, 1)
        easy_grid.attach(hid_app_combo, 2, 2, 1, 1)
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        box.pack_end(dub_check, False, False, 0)
        box.pack_end(dub_label, False, False, 0)
        easy_grid.attach(box, 4, 2, 2, 1)
        easy_grid.attach(Gtk.Label(label="Hide Category", xalign=1), 1, 3, 1, 1)
        easy_grid.attach(hide_cat_combo, 2, 3, 1, 1)
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        box.pack_end(kit_menu_check, False, False, 0)
        box.pack_end(kit_menu_label, False, False, 0)
        easy_grid.attach(box, 4, 3, 2, 1)

        easy_grid.attach(Gtk.Label(label="Rename Category", xalign=1), 1, 4, 1, 1)
        easy_grid.attach(rename_cat_combo, 2, 4, 1, 1)
        easy_grid.attach(Gtk.Label(label="to"), 3, 4, 1, 1)
        easy_grid.attach(rename_cat_entry, 4, 4, 1, 1)
        easy_grid.attach(Gtk.Label(label="Merge Category", xalign=1), 1, 5, 1, 1)
        easy_grid.attach(merge_cat_combo, 2, 5, 1, 1)
        easy_grid.attach(Gtk.Label(label="into"), 3, 5, 1, 1)
        easy_grid.attach(merged_cat_combo, 4, 5, 1, 1)

        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        l_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        r_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        s_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        box.pack_start(l_box, False, False, 0)
        s_box.pack_start(Gtk.Separator(orientation=Gtk.Orientation.VERTICAL), True, True, 40)
        box.pack_start(s_box, False, False, 0)
        box.pack_end(r_box, False, False, 0)
        mainbox.pack_start(box, False, False, 0)
        label = Gtk.Label(xalign=1)
        label.set_markup('<big><b>Hidden Categories</b></big>')
        r_box.pack_start(label, False, False, 0)
        label = Gtk.Label(xalign=0)
        label.set_markup('<big><b>Rename Categories</b></big>')
        l_box.pack_start(label, False, False, 0)
        l_box.pack_start(Gtk.Separator(), False, False, 0)
        l_box.pack_start(scroll_rc, False, False, 0)
        r_box.pack_end(scroll_ha, False, False, 0)
        label = Gtk.Label(xalign=1)
        r_box.pack_end(Gtk.Separator(), False, False, 0)
        label.set_markup('<big><b>Hidden Applications</b></big>')
        r_box.pack_end(label, False, False, 0)
        r_box.pack_end(scroll_hc, False, False, 0)
        r_box.pack_end(Gtk.Separator(), False, False, 0)
        label = Gtk.Label(xalign=0)
        label.set_markup('<big><b>Merge Categories</b></big>')
        l_box.pack_end(scroll_mc, False, False, 0)
        l_box.pack_end(Gtk.Separator(), False, False, 0)
        l_box.pack_end(label, False, False, 0)

        for d in data:
            if d == '-nodubs':
                # set switch
                dub_check.set_active(True)
            elif d == '-nokitmenu':
                # set switch
                kit_menu_check.set_active(True)
            elif d == '-nokit':
                hidden_cats.append('JWM Kit')
            elif d[0:3] == '-hc':
                d = d[4:].split(':')
                for h in d:
                    h = h.strip('\"')
                    if h in copy_cat:
                        hidden_cats.append(h)
            elif d[0:3] == '-ha':
                d = d[4:].split(':')
                for h in d:
                    h = h.strip('\"')
                    hidden_apps.append([h, '', h, ''])
            elif d[0:2] == '-t':
                term_combo.get_child().set_text(d[3:].strip('\"'))
            elif d[0:2] == '-m':
                d = d[3:].split(':')
                while '' in d: d.remove('')
                host = d[0].strip('\"')
                d = d[1:]
                if host not in copy_cat:
                    break
                guests = []
                for guest in d:
                    guest = guest.strip('\"')
                    if host != guest and guest in copy_cat:
                            guests.append(guest)
                if guests:
                    merged_cats.append(guests)
                    host_cats.append(host)
            elif d[0:2] == '-r':
                d = d[3:].split(':')
                if len(d) == 2:
                    old = d[0].strip('\"')
                    new = d[1].strip('\"')
                    if old in copy_cat:
                        if old != new:
                            old_cats.append(old)
                            new_cats.append(new)
            elif d[0:3] == '-lt':
                lang_combo.get_child().set_text(d.split(':')[1].strip('"'))
            elif d[0:2] == '-l':
                if lang_combo.get_active() == 0:
                    lang_combo.get_child().set_text(d.split(':')[1].strip('"'))

        set_hc_label()
        set_ha_label()
        set_rc_label()
        set_merge_label()

        dialog.show_all()

    def add_menu(self, button):
        self.dialogs('add_menu')

    def remove_item(self, button):

        def find_parent_child(parent):
            for child in parent:
                if length != len(self.select_menu_data):
                    break
                if child.get('index') == xml_index:
                    parent.remove(child)
                    self.move_index()
                    self.make_buttons()
                    self.select_menu_data = self.get_listbox_items(parent.get('index'))
                    break
                elif len(child) > 0:
                    find_parent_child(child)
        try:
            index = self.listbox_mid_mid.get_selected_rows()[0].get_index()
        except IndexError:
            self.previous_index = -2
            return
        message = self.select_menu_data[index][2]
        xml_index = self.select_menu_data[index][-1]
        confirm = self.confirm_dialog('b1', 'Remove Item', 'Do you want to remove {} ?'.format(message),
                                      'if you delete an item, it will be permanently removed\n')
        if confirm == -5:
            length = len(self.select_menu_data)
            find_parent_child(self.menu_xml[0])
            self.previous_index = -2
            self.listbox_mid_mid.remove(self.listbox_mid_mid.get_selected_row())
            if index != 0: index = index - 1
            if index == 0:
                self.get_selected_menu('', self.selected_menu)
            self.listbox_mid_mid.select_row(self.listbox_mid_mid.get_row_at_index(index))

    def save(self, button):
        filename = self.menu_files[self.menu_combo.get_active()][1]
        if self.previous_index != -2:
            self.update_data(self.listbox_mid_mid.get_selected_rows()[0].get_index())
        self.update_properties()
        xml_copy = copy.deepcopy(self.menu_xml)
        for child in xml_copy.findall('.//'):
            del child.attrib['index']

        xml_copy = b'\n'.join([s.strip() for s in ET.tostring(xml_copy).splitlines() if s.strip()])
        xml_copy = minidom.parseString(xml_copy).toprettyxml(newl='', indent='   ')
        xml_copy = ET.ElementTree(ET.fromstring(xml_copy))
        xml_copy.write(filename, encoding="utf-8", xml_declaration=True)
        os.system('jwm -restart')


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