#!/usr/bin/env python

#ToDo add terminal open command if bool = true

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject, GLib, Gio, GdkPixbuf
from xdg.DesktopEntry import DesktopEntry
from xdg.BaseDirectory import xdg_config_home
from xdg.BaseDirectory import xdg_data_home
import xdg.IconTheme
import os
import re
#import subprocess
import getopt
import sys

apps = Gio.app_info_get_all()
#Change below to your favourite terminal if not using antix desktop-defaults
term_app = 'desktop-defaults-run -t '
#Change below to use a different icon size
icon_size = 48

class mainWindow(Gtk.Window):
    
    def refresh_filter(self,widget):
        self.filter.refilter()
        search_query = self.searchentry.get_text()
        if search_query != "":
            self.treeview.set_cursor(0)
            self.filter_message_box.show()
        else:
            self.filter_message_box.hide()

    def visible_cb(self, model, iter, data=None):
        search_query = self.searchentry.get_text().lower()
        active_category = self.searchcombo.get_active()
        search_in_all_columns = active_category == 0

        if search_query == "":
            return True

        if search_in_all_columns:
            for col in range(1,self.treeview.get_n_columns()):
                value = model.get_value(iter, col).lower()
                if search_query in value:
                    return True

            return False
        else: active_category = active_category +1

        value = model.get_value(iter, active_category).lower()
        return True if search_query in value else False
    
    def run_button(self, test):
        self.run(self,"","")
            
    def run(self, test, fill, fill2):
        tree_selection = self.treeview.get_selection()
        (model, pathlist) = tree_selection.get_selected_rows()
        for i, path in enumerate(pathlist) :
            tree_iter = model.get_iter(path)
            appname = model.get_value(tree_iter,1)
            appexec = model.get_value(tree_iter,3)
            appexec = re.sub(r'%.*', '', appexec)
            appterm = model.get_value(tree_iter,4)
            filename = model.get_value(tree_iter,5)
            
            if pselect:
                print str(filename)+"|"+str(appname)+"|"+str(appexec)+"|"+str(appterm)
                Gtk.main_quit()
            else:
                if appterm:
                    os.system(term_app+" "+appexec+" > /dev/null 2>&1 &")
                else:
                    os.system(appexec+" > /dev/null 2>&1 &")
    
    def add_item(self, store, filename, iftype):
        appexec = DesktopEntry(filename).getExec()
        appname = iftype+DesktopEntry(filename).getName()
        appicon = DesktopEntry(filename).getIcon()
        appdesc = DesktopEntry(filename).getComment()
        appterm = DesktopEntry(filename).getTerminal()
        appcomb = appname + "\nDescription: " + appdesc + "\nExec: " + appexec + "\n"
        missing_icon = "gtk-missing-image"
        
        if appdesc == "": appdesc = "    ~~~~~~~~~~~~~~~    "
        if appicon == "":  appicon = missing_icon
        
        if os.path.isfile(appicon):
            icon = appicon
        else:
            icon_theme = Gtk.IconTheme.get_default()
            icon_check = icon_theme.lookup_icon(appicon, icon_size, 0)
            if icon_check:
                icon_info = icon_theme.lookup_icon(appicon, icon_size, 0)
                icon = icon_info.get_filename()
            else:
                if os.path.exists("/usr/share/pixmaps/%s" % appicon):
                    icon = "/usr/share/pixmaps/"+appicon
                else:
                    #p =  subprocess.Popen(["locate "+appicon],stdout=subprocess.PIPE, shell=True)
                    #(output, err) = p.communicate()
                    #last_attempt = output.partition('\n')[0]
                    #if os.path.isfile(last_attempt):
                    #    icon = last_attempt
                    #else:
                        icon = missing_icon
        
        icon = re.sub(r' ','\ ', icon)
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon)
        except:
            icon_info = icon_theme.lookup_icon(missing_icon, icon_size, 0)
            icon = icon_info.get_filename()
            pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon)
            
        pixbuf = GdkPixbuf.Pixbuf.scale_simple(pixbuf, icon_size, icon_size,0)
        store.append([pixbuf, appcomb, appname, appdesc, appexec, appterm, filename])
        store.set_sort_column_id(1,0)
    
    def make_list(self):
        count = 0
        store = Gtk.ListStore(GdkPixbuf.Pixbuf,str,str,str,str,bool,str)
        
        #Disabled for now:
        #Can test / preview by uncommenting the below lines / for statements
              
        #for item in os.walk(xdg_config_home+"/autostart/"):
        #    if item[2]:
        #        filename = item[0]+"/"+"".join(item[2])
        #        self.add_item(store, filename, 'Autostart: ')
        
        #for item in os.walk(xdg_data_home+"/applications/"):
        #    if item[2]:
        #        filename = item[0]+"/"+"".join(item[2])
        #        self.add_item(store, filename, 'Personal: ')
        
        
        for name in apps:
            filename = name.get_filename()
            self.add_item(store, filename, '')

        
        self.filter = store.filter_new()
        self.filter.set_visible_func(self.visible_cb)
        self.searchentry.connect("changed", self.refresh_filter)
        self.searchentry.connect("activate", self.run_button)
        self.searchcombo.connect("changed", self.refresh_filter)
        
        self.treeview = Gtk.TreeView.new_with_model(self.filter)
        self.treeview.connect("row-activated", self.run)
        self.treeview.set_headers_visible(False)
        self.treeview.set_enable_search(False)
        
        renderer = Gtk.CellRendererPixbuf()
        column = Gtk.TreeViewColumn("", renderer, pixbuf=0)
        column.set_resizable(True)
        self.treeview.append_column(column)
        for i, column_title in enumerate(["Info", "Name", "Description", "Exec"]):
            renderer = Gtk.CellRendererText()
            column = Gtk.TreeViewColumn(column_title, renderer, text=i+1)
            column.set_resizable(True)
            if i >= 1: column.set_visible(False)
            self.treeview.append_column(column)

        self.sw.add(self.treeview)
        self.treeview.show()


    def __init__(self):
        Gtk.Window.__init__(self)
        self.set_size_request(640,480)
        self.set_border_width(10)
        self.set_title(" App Select ")
        self.show()
    
        grid = Gtk.Grid()
        self.add(grid)
        grid.show()
        
        label = Gtk.Label("Search / Filter: ")
        grid.attach(label, 1, 1, 1, 1)
        label.show()
        
        # Search EntryEntry
        self.searchentry = Gtk.Entry()
        self.searchentry.set_placeholder_text("Type to filter...")
        grid.attach(self.searchentry, 2, 1, 1, 1)
        self.searchentry.set_hexpand(True)
        self.searchentry.grab_focus()
        self.searchentry.show()
        
        # Search Combo
        categories = ["All",  "Name Only", "Description Only", "Exec Only"]
        self.searchcombo = Gtk.ComboBoxText()
        self.searchcombo.set_entry_text_column(0)
        grid.attach(self.searchcombo, 3, 1, 1, 1)
        for category in categories:
            self.searchcombo.append_text(category)
        self.searchcombo.set_active(0)
        self.searchcombo.show()

        self.filter_message_box = Gtk.EventBox() 
        grid.attach(self.filter_message_box, 1, 2, 3, 1)       
        self.filter_message_box.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(1,0.5,0.5,0.5))
        self.filter_message_box.hide()
        
        filter_message = Gtk.Label("\nDisplaying filtered results\n")
        filter_message.set_hexpand(True)
        self.filter_message_box.add(filter_message)
        filter_message.show()
        
        self.sw= Gtk.ScrolledWindow()
        grid.attach(self.sw, 1, 3, 3, 1)
        self.sw.set_hexpand(True)
        self.sw.set_vexpand(True)
        self.sw.show()
        
        self.make_list()

        buttonbox = Gtk.HButtonBox()
        grid.attach(buttonbox, 3, 4, 1, 1)
        buttonbox.show()
        
        select = Gtk.Button(stock=Gtk.STOCK_APPLY)
        select.connect("clicked", self.run_button)
        buttonbox.pack_start(select,0,0,0) 
        select.set_can_default(True)
        select.grab_default()

        run = Gtk.Button(stock=Gtk.STOCK_EXECUTE)
        run.connect("clicked", self.run_button)
        buttonbox.pack_start(run,0,0,0) 
        run.set_can_default(True)
        run.grab_default()

        
        if pselect:
            select.show()
            run.hide()
        else:
            run.show()
            select.hide()
        
        close = Gtk.Button(stock=Gtk.STOCK_CLOSE)
        close.connect("clicked", lambda w: Gtk.main_quit())
        buttonbox.add(close)
        close.show()

def print_usage(exit_code = 1):
  print """Usage: %s [options]
Options:        
  --help (--h | --H | --?)                       print this help and exit
  --select (--s | --S)                          makes changes for program selection vs execution
""" % sys.argv[0]
  sys.exit(exit_code)

try: opts, args = getopt.getopt(sys.argv[1:], "", 
  ("help", "select"))
except getopt.GetoptError: print_usage()

pselect = False

for o, v in opts:
    if o == "--select": pselect = True 
    elif o in ("-h", "-H", "-?", "--help"): print_usage(0)


win = mainWindow()
win.connect("delete-event", Gtk.main_quit)
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL) # without this, Ctrl+C from parent term is ineffectual
Gtk.main()
