mintmenu/usr/lib/linuxmint/mintMenu/plugins/applications.py
hordepfo b5845b0676 Fixes search entry losing typing focus
When the search entry was out of focus and types were redirected to it,
if the current selected application was hidden by the filtering, both
the holder and entry lost focus. This stopped the typing event
redirection. Now the entry is always focused when typing.
2014-01-22 03:20:56 +00:00

1822 lines
76 KiB
Python
Executable File

#!/usr/bin/env python
import gi
gi.require_version("Gtk", "2.0")
from gi.repository import Gtk, Pango, Gdk, Gio, GLib
import os
#import mateconf
import fnmatch
import time
import string
import gettext
import threading
import commands
import subprocess
import filecmp
import ctypes
import capi
from ctypes import *
from easybuttons import *
from execute import Execute
from easygsettings import EasyGSettings
from easyfiles import *
gtk = CDLL("libgtk-x11-2.0.so.0")
from filemonitor import monitor as filemonitor
#import xdg.Menu
import matemenu
from user import home
# i18n
gettext.install("mintmenu", "/usr/share/linuxmint/locale")
class PackageDescriptor():
def __init__(self, name, summary, description):
self.name = name
self.summary = summary
self.description = description
def print_timing(func):
def wrapper(*arg):
t1 = time.time()
res = func(*arg)
t2 = time.time()
print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
return res
return wrapper
# Evil patching
#def xdgParsePatched(filename=None):
# # conver to absolute path
# if filename and not os.path.isabs(filename):
# filename = xdg.Menu.__getFileName(filename)
#
# # use default if no filename given
# if not filename:
# filename = xdg.Menu.__getFileName("applications.menu")
#
# if not filename:
# raise xdg.Menu.ParsingError(_("File not found"), "/etc/xdg/menus/applications.menu")
#
# # check if it is a .menu file
# if not os.path.splitext(filename)[1] == ".menu":
# raise xdg.Menu.ParsingError(_("Not a .menu file"), filename)
#
# # create xml parser
# try:
# doc = xdg.Menu.xml.dom.minidom.parse(filename)
# except xdg.Menu.xml.parsers.expat.ExpatError:
# raise xdg.Menu.ParsingError(_("Not a valid .menu file"), filename)
#
# # parse menufile
# xdg.Menu.tmp["Root"] = ""
# xdg.Menu.tmp["mergeFiles"] = []
# xdg.Menu.tmp["DirectoryDirs"] = []
# xdg.Menu.tmp["cache"] = xdg.Menu.MenuEntryCache()
#
# xdg.Menu.__parse(doc, filename, xdg.Menu.tmp["Root"])
# xdg.Menu.__parsemove(xdg.Menu.tmp["Root"])
# xdg.Menu.__postparse(xdg.Menu.tmp["Root"])
#
# xdg.Menu.tmp["Root"].Doc = doc
# xdg.Menu.tmp["Root"].Filename = filename
#
# # generate the menu
# xdg.Menu.__genmenuNotOnlyAllocated(xdg.Menu.tmp["Root"])
# xdg.Menu.__genmenuOnlyAllocated(xdg.Menu.tmp["Root"])
#
# # and finally sort
# xdg.Menu.sort(xdg.Menu.tmp["Root"])
# xdg.Menu.tmp["Root"].Files = xdg.Menu.tmp["mergeFiles"] + [ xdg.Menu.tmp["Root"].Filename ]
# return xdg.Menu.tmp["Root"]
#
#xdg.Menu.parse = xdgParsePatched
# Helper function for retrieving the user's location for storing new or modified menu items
def get_user_item_path():
item_dir = None
if os.environ.has_key('XDG_DATA_HOME'):
item_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'applications')
else:
item_dir = os.path.join(os.environ['HOME'], '.local', 'share', 'applications')
if not os.path.isdir(item_dir):
os.makedirs(item_dir)
return item_dir
def get_system_item_paths():
item_dir = None
if os.environ.has_key('XDG_DATA_DIRS'):
item_dirs = os.environ['XDG_DATA_DIRS'].split(":")
else:
item_dirs = [os.path.join('usr', 'share')]
return item_dirs
def rel_path(target, base=os.curdir):
if not os.path.exists(target):
raise OSError, 'Target does not exist: '+target
if not os.path.isdir(base):
raise OSError, 'Base is not a directory or does not exist: '+base
base_list = (os.path.abspath(base)).split(os.sep)
target_list = (os.path.abspath(target)).split(os.sep)
for i in range(min(len(base_list), len(target_list))):
if base_list[i] <> target_list[i]: break
else:
i += 1
rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:]
return os.path.join(*rel_list)
class Menu:
def __init__( self, MenuToLookup ):
self.tree = matemenu.lookup_tree( MenuToLookup )
self.directory = self.tree.get_root_directory()
def getMenus( self, parent=None ):
if parent == None:
#gives top-level "Applications" item
yield self.tree.root
else:
for menu in parent.get_contents():
if menu.get_type() == matemenu.TYPE_DIRECTORY and self.__isVisible( menu ):
yield menu
def getItems( self, menu ):
for item in menu.get_contents():
if item.get_type() == matemenu.TYPE_ENTRY and item.get_desktop_file_id()[-19:] != '-usercustom.desktop' and self.__isVisible( item ):
yield item
def __isVisible( self, item ):
if item.get_type() == matemenu.TYPE_ENTRY:
return not ( item.get_is_excluded() or item.get_is_nodisplay() )
if item.get_type() == matemenu.TYPE_DIRECTORY and len( item.get_contents() ):
return True
class SuggestionButton ( Gtk.Button ):
def __init__( self, iconName, iconSize, label ):
Gtk.Button.__init__( self )
self.iconName = iconName
self.set_relief( Gtk.ReliefStyle.NONE )
self.set_size_request( -1, -1 )
Align1 = Gtk.Alignment()
Align1.set( 0, 0.5, 1.0, 0 )
HBox1 = Gtk.HBox()
labelBox = Gtk.VBox( False, 2 )
self.image = Gtk.Image()
self.image.set_from_stock( self.iconName, iconSize )
self.image.show()
HBox1.pack_start( self.image, False, False, 5 )
self.label = Gtk.Label()
self.label.set_ellipsize( Pango.EllipsizeMode.END )
self.label.set_alignment( 0.0, 1.0 )
self.label.show()
labelBox.pack_start( self.label, True, True, 2 )
labelBox.show()
HBox1.pack_start( labelBox, True, True, 2 )
HBox1.show()
Align1.add( HBox1 )
Align1.show()
self.add( Align1 )
self.show()
def set_image(self, path):
self.image.set_from_file(path)
def set_text( self, text):
self.label.set_markup(text)
def set_icon_size (self, size):
self.image.set_from_stock( self.iconName, size )
class TargetEntry(Structure):
_fields_ = [("target", c_char_p),
("flags", c_int),
("info", c_int)]
class pluginclass( object ):
TARGET_TYPE_TEXT = 80
array2 = TargetEntry * 2
toButton = array2( ("text/uri-list", 0, TARGET_TYPE_TEXT), ("text/uri-list", 0, TARGET_TYPE_TEXT) )
TARGET_TYPE_FAV = 81
array = TargetEntry * 3
toFav = array( ( "FAVORITES", Gtk.TargetFlags.SAME_APP, 81 ), ( "text/plain", 0, 100 ), ( "text/uri-list", 0, 101 ) )
array1 = TargetEntry * 2
fromFav = array1( ("FAVORITES", Gtk.TargetFlags.SAME_APP, 81), ("FAVORITES", Gtk.TargetFlags.SAME_APP, 81) )
@print_timing
def __init__( self, mintMenuWin, toggleButton, de ):
self.mintMenuWin = mintMenuWin
self.mainMenus = [ ]
self.toggleButton = toggleButton
self.de = de
self.builder = Gtk.Builder()
# The Glade file for the plugin
self.builder.add_from_file (os.path.join( os.path.dirname( __file__ ), "applications.glade" ))
# Read GLADE file
self.searchEntry =self.builder.get_object( "searchEntry" )
self.searchButton =self.builder.get_object( "searchButton" )
self.showAllAppsButton =self.builder.get_object( "showAllAppsButton" )
self.showFavoritesButton =self.builder.get_object( "showFavoritesButton" )
self.applicationsBox =self.builder.get_object( "applicationsBox" )
self.categoriesBox =self.builder.get_object( "categoriesBox" )
self.favoritesBox =self.builder.get_object( "favoritesBox" )
self.applicationsScrolledWindow =self.builder.get_object( "applicationsScrolledWindow" )
#i18n
self.builder.get_object("searchLabel").set_text("<span weight='bold'>" + _("Search:") + "</span>")
self.builder.get_object("searchLabel").set_use_markup(True)
self.builder.get_object("label6").set_text(_("Favorites"))
self.builder.get_object("label3").set_text(_("Favorites"))
self.builder.get_object("label7").set_text(_("All applications"))
self.builder.get_object("label2").set_text(_("Applications"))
self.mintMenuWin.SetHeadingStyle( [self.builder.get_object("label6"),self.builder.get_object("label2")] )
self.numApps = 0
# These properties are NECESSARY to maintain consistency
# Set 'window' property for the plugin (Must be the root widget)
self.window =self.builder.get_object( "mainWindow" )
# Set 'heading' property for plugin
self.heading = ""#_("Applications")
# This should be the first item added to the window in glade
self.content_holder =self.builder.get_object( "Applications" )
# Items to get custom colors
self.itemstocolor = [self.builder.get_object( "viewport1" ),self.builder.get_object( "viewport2" ),self.builder.get_object( "viewport3" ),self.builder.get_object( "notebook2" ) ]
# Unset all timers
self.filterTimer = None
self.menuChangedTimer = None
# Hookup for text input
self.content_holder.connect( "key-press-event", self.keyPress )
self.favoritesBox.connect( "drag-data-received", self.ReceiveCallback )
gtk.gtk_drag_dest_set ( hash(self.favoritesBox), Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP, self.toButton, 2, Gdk.DragAction.COPY )
self.showFavoritesButton.connect( "drag-data-received", self.ReceiveCallback )
gtk.gtk_drag_dest_set ( hash(self.showFavoritesButton), Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP, self.toButton, 2, Gdk.DragAction.COPY )
# self.searchButton.connect( "button_release_event", self.SearchWithButton )
try:
# GSettings stuff
self.settings = EasyGSettings( "com.linuxmint.mintmenu.plugins.applications" )
self.GetGSettingsEntries()
self.settings.notifyAdd( "icon-size", self.changeIconSize )
self.settings.notifyAdd( "favicon-size", self.changeFavIconSize )
self.settings.notifyAdd( "height", self.changePluginSize )
self.settings.notifyAdd( "width", self.changePluginSize )
self.settings.notifyAdd( "categories-mouse-over", self.changeCategoriesMouseOver )
self.settings.notifyAdd( "swap-generic-name", self.changeSwapGenericName )
self.settings.notifyAdd( "show-category-icons", self.changeShowCategoryIcons )
self.settings.notifyAdd( "show-application-comments", self.changeShowApplicationComments )
self.settings.notifyAdd( "use-apt", self.switchAPTUsage)
self.settings.notifyAdd( "fav-cols", self.changeFavCols )
self.settings.notifyAdd( "remember-filter", self.changeRememberFilter)
self.settings.bindGSettingsEntryToVar( "int", "category-hover-delay", self, "categoryhoverdelay" )
self.settings.bindGSettingsEntryToVar( "bool", "do-not-filter", self, "donotfilterapps" )
self.settings.bindGSettingsEntryToVar( "string", "search-command", self, "searchtool" )
self.settings.bindGSettingsEntryToVar( "int", "default-tab", self, "defaultTab" )
except Exception, detail:
print detail
self.currentFavCol = 0
self.favorites = []
self.content_holder.set_size_request( self.width, self.height )
self.categoriesBox.set_size_request( self.width / 3, -1 )
self.applicationsBox.set_size_request( self.width / 2, -1 )
self.buildingButtonList = False
self.stopBuildingButtonList = False
self.categoryList = []
self.applicationList = []
#self.menuFileMonitors = []
#dirty ugly hack, to get favorites drag origin position
self.drag_origin = None
self.rebuildLock = False
self.activeFilter = (1, "", self.searchEntry)
self.adminMenu = None
for mainitems in [ "mate-applications.menu", "mate-settings.menu" ]:
mymenu = Menu( mainitems )
mymenu.tree.add_monitor( self.menuChanged, None )
#for f in mymenu.directory.Files:
# self.menuFileMonitors.append( filemonitor.addMonitor(f, self.onMenuChanged, mymenu.directory.Filename ) )
#for f in mymenu.directory.AppDirs:
# self.menuFileMonitors.append( filemonitor.addMonitor(f, self.onMenuChanged, mymenu.directory.Filename ) )
self.refresh_apt_cache()
self.suggestions = []
self.current_suggestion = None
self.panel = "top"
self.panel_position = -1
self.builder.get_object("searchButton").connect( "button-press-event", self.searchPopup )
def refresh_apt_cache(self):
if self.useAPT:
os.system("mkdir -p %s/.linuxmint/mintMenu/" % home)
os.system("/usr/lib/linuxmint/mintMenu/plugins/get_apt_cache.py > %s/.linuxmint/mintMenu/apt.cache &" % home)
def get_panel(self):
panelsettings = Gio.Settings.new("org.mate.panel")
applet_list = panelsettings.get_strv("object-id-list")
for applet in applet_list:
object_schema = Gio.Settings.new_with_path("org.mate.panel.object", "/org/mate/panel/objects/%s/" % (applet))
keys = object_schema.list_keys()
if "applet-iid" in keys:
iid = object_schema.get_string("applet-iid")
if iid is not None and iid.find("MintMenu") != -1:
self.panel = object_schema.get_string("toplevel-id")
self.panel_position = object_schema.get_int("position") + 1
def apturl_install(self, widget, pkg_name):
if os.path.exists("/usr/bin/apturl"):
os.system("/usr/bin/apturl apt://%s &" % pkg_name)
else:
os.system("xdg-open apt://" + pkg_name + " &")
self.mintMenuWin.hide()
def __del__( self ):
print u"Applications plugin deleted"
def wake (self) :
pass
def destroy( self ):
self.content_holder.destroy()
self.searchEntry.destroy()
self.searchButton.destroy()
self.showAllAppsButton.destroy()
self.showFavoritesButton.destroy()
self.applicationsBox.destroy()
self.categoriesBox.destroy()
self.favoritesBox.destroy()
self.settings.notifyRemoveAll()
#for mId in self.menuFileMonitors:
# filemonitor.removeMonitor( mId )
def changePluginSize( self, settings, key, args ):
if key == "width":
self.width = settings.get_int(key)
self.categoriesBox.set_size_request( self.width / 3, -1 )
self.applicationsBox.set_size_request( self.width / 2, -1 )
elif key == "height":
self.heigth = settings.get_int(key)
self.content_holder.set_size_request( self.width, self.height )
def changeSwapGenericName( self, settings, key, args ):
self.swapgeneric = settings.get_boolean(key)
for child in self.favoritesBox:
if isinstance( child, FavApplicationLauncher):
child.setSwapGeneric( self.swapgeneric )
def changeShowCategoryIcons( self, settings, key, args ):
self.showcategoryicons = settings.get_boolean(key)
if self.showcategoryicons:
categoryIconSize = self.iconSize
else:
categoryIconSize = 0
for child in self.categoriesBox:
child.setIconSize( categoryIconSize )
def changeIconSize( self, settings, key, args ):
self.iconSize = settings.get_int(key)
if self.showcategoryicons:
categoryIconSize = self.iconSize
else:
categoryIconSize = 0
for child in self.categoriesBox:
child.setIconSize( categoryIconSize )
for child in self.applicationsBox:
try:
child.setIconSize( self.iconSize )
except:
pass
def changeFavIconSize( self, settings, key, args ):
self.faviconsize = settings.get_int(key)
for child in self.favoritesBox:
if isinstance( child, FavApplicationLauncher):
child.setIconSize( self.faviconsize )
def switchAPTUsage( self, settings, key, args ):
self.useAPT = settings.get_boolean(key)
self.refresh_apt_cache()
def changeRememberFilter( self, settings, key, args):
self.rememberFilter = settings.get_boolean(key)
def changeShowApplicationComments( self, settings, key, args ):
self.showapplicationcomments = settings.get_boolean(key)
for child in self.applicationsBox:
child.setShowComment( self.showapplicationcomments )
def changeCategoriesMouseOver( self, settings, key, args ):
self.categories_mouse_over = settings.get_boolean(key)
for child in self.categoriesBox:
if self.categories_mouse_over and not child.mouseOverHandlerIds:
startId = child.connect( "enter", self.StartFilter, child.filter )
stopId = child.connect( "leave", self.StopFilter )
child.mouseOverHandlerIds = ( startId, stopId )
elif not self.categories_mouse_over and child.mouseOverHandlerIds:
child.disconnect( child.mouseOverHandlerIds[0] )
child.disconnect( child.mouseOverHandlerIds[1] )
child.mouseOverHandlerIds = None
def changeFavCols(self, settings, key, args):
self.favCols = settings.get_int(key)
for fav in self.favorites:
self.favoritesBox.remove( fav )
self.favoritesPositionOnGrid( fav )
def RegenPlugin( self, *args, **kargs ):
self.refresh_apt_cache()
# save old config - this is necessary because the app will notified when it sets the default values and you don't want the to reload itself several times
oldcategories_mouse_over = self.categories_mouse_over
oldtotalrecent = self.totalrecent
oldsticky = self.sticky
oldminimized = self.minimized
oldicon = self.icon
oldhideseparator = self.hideseparator
oldshowapplicationcomments = self.showapplicationcomments
self.GetGSettingsEntries()
# if the config hasn't changed return
if oldcategories_mouse_over == self.categories_mouse_over and oldiconsize == self.iconSize and oldfaviconsize == self.faviconsize and oldtotalrecent == self.totalrecent and oldswapgeneric == self.swapgeneric and oldshowcategoryicons == self.showcategoryicons and oldcategoryhoverdelay == self.categoryhoverdelay and oldsticky == self.sticky and oldminimized == self.minimized and oldicon == self.icon and oldhideseparator == self.hideseparator and oldshowapplicationcomments == self.showapplicationcomments:
return
self.Todos()
self.buildFavorites()
self.RebuildPlugin()
def GetGSettingsEntries( self ):
self.categories_mouse_over = self.settings.get( "bool", "categories-mouse-over")
self.width = self.settings.get( "int", "width")
self.height = self.settings.get( "int", "height")
self.donotfilterapps = self.settings.get( "bool", "do-not-filter")
self.iconSize = self.settings.get( "int", "icon-size")
self.faviconsize = self.settings.get( "int", "favicon-size")
self.favCols = self.settings.get( "int", "fav-cols")
self.swapgeneric = self.settings.get( "bool", "swap-generic-name")
self.showcategoryicons = self.settings.get( "bool", "show-category-icons")
self.categoryhoverdelay = self.settings.get( "int", "category-hover-delay")
self.showapplicationcomments = self.settings.get( "bool", "show-application-comments")
self.useAPT = self.settings.get( "bool", "use-apt")
self.rememberFilter = self.settings.get( "bool", "remember-filter")
self.lastActiveTab = self.settings.get( "int", "last-active-tab")
self.defaultTab = self.settings.get( "int", "default-tab")
# Allow plugin to be minimized to the left plugin pane
self.sticky = self.settings.get( "bool", "sticky")
self.minimized = self.settings.get( "bool", "minimized")
# Search tool
self.searchtool = self.settings.get( "string", "search-command")
if self.searchtool == "beagle-search SEARCH_STRING":
self.searchtool = "mate-search-tool --named \"%s\" --start"
self.settings.set( "string", "search-command", "mate-search-tool --named \"%s\" --start" )
# Plugin icon
self.icon = self.settings.get( "string", "icon" )
# Hide vertical dotted separator
self.hideseparator = self.settings.get( "bool", "hide-separator")
def SetHidden( self, state ):
if state == True:
self.settings.set( "bool", "minimized", True )
else:
self.settings.set( "bool", "minimized", False )
def RebuildPlugin(self):
self.content_holder.set_size_request( self.width, self.height )
def checkMintMenuFolder( self ):
if os.path.exists( os.path.join( os.path.expanduser( "~" ), ".linuxmint", "mintMenu", "applications" ) ):
return True
try:
os.makedirs( os.path.join( os.path.expanduser( "~" ), ".linuxmint", "mintMenu", "applications" ) )
return True
except:
pass
return False
def onShowMenu( self ):
if len( self.favorites ):
if self.defaultTab == -1:
self.changeTab( self.lastActiveTab)
else:
self.changeTab( (self.defaultTab - 1) * -1 )
else:
self.changeTab( 1 )
self.searchEntry.select_region( 0, -1 )
if self.rememberFilter and self.searchEntry.get_text().strip() != "":
self.Filter(self.activeFilter[2], self.activeFilter[1])
def onHideMenu( self ):
self.settings.set( "int", "last-active-tab", self.lastActiveTab )
def changeTab( self, tabNum ):
notebook = self.builder.get_object( "notebook2" )
if tabNum == 0:
notebook.set_current_page( 0 )
elif tabNum == 1:
notebook.set_current_page( 1 )
self.lastActiveTab = tabNum
self.focusSearchEntry()
def Todos( self ):
self.searchEntry.connect( "changed", self.Filter )
self.searchEntry.connect( "activate", self.Search )
self.showAllAppsButton.connect( "clicked", lambda widget: self.changeTab( 1 ) )
self.showFavoritesButton.connect( "clicked", lambda widget: self.changeTab( 0 ) )
self.buildButtonList()
def focusSearchEntry( self ):
# grab_focus() does select all text,
# restoring the original selection is somehow broken, so just select the end
# of the existing text, that's the most likely candidate anyhow
self.searchEntry.grab_focus()
if self.rememberFilter:
gtk.gtk_editable_set_position(hash(self.searchEntry), -1)
else:
self.searchEntry.set_text("")
def buildButtonList( self ):
if self.buildingButtonList:
self.stopBuildingButtonList = True
GLib.timeout_add( 100, self.buildButtonList )
return
self.stopBuildingButtonList = False
self.updateBoxes(False)
def categoryBtnFocus( self, widget, event, category ):
self.scrollItemIntoView( widget )
self.StartFilter( widget, category )
def StartFilter( self, widget, category ):
# if there is a timer for a different category running stop it
if self.filterTimer:
GLib.source_remove( self.filterTimer )
self.filterTimer = GLib.timeout_add( self.categoryhoverdelay, self.Filter, widget, category )
def StopFilter( self, widget ):
if self.filterTimer:
GLib.source_remove( self.filterTimer )
self.filterTimer = None
def add_search_suggestions(self, text):
text = "<b>%s</b>" % text
suggestionButton = SuggestionButton(Gtk.STOCK_ADD, self.iconSize, "")
suggestionButton.connect("clicked", self.search_google)
suggestionButton.set_text(_("Search Google for %s") % text)
suggestionButton.set_image("/usr/lib/linuxmint/mintMenu/search_engines/google.ico")
self.applicationsBox.add(suggestionButton)
self.suggestions.append(suggestionButton)
suggestionButton = SuggestionButton(Gtk.STOCK_ADD, self.iconSize, "")
suggestionButton.connect("clicked", self.search_wikipedia)
suggestionButton.set_text(_("Search Wikipedia for %s") % text)
suggestionButton.set_image("/usr/lib/linuxmint/mintMenu/search_engines/wikipedia.ico")
self.applicationsBox.add(suggestionButton)
self.suggestions.append(suggestionButton)
separator = Gtk.EventBox()
separator.add(Gtk.HSeparator())
separator.set_visible_window(False)
separator.set_size_request(-1, 20)
separator.type = "separator"
self.mintMenuWin.SetPaneColors( [ separator ] )
separator.show_all()
self.applicationsBox.add(separator)
self.suggestions.append(separator)
suggestionButton = SuggestionButton(Gtk.STOCK_ADD, self.iconSize, "")
suggestionButton.connect("clicked", self.search_dictionary)
suggestionButton.set_text(_("Lookup %s in Dictionary") % text)
suggestionButton.set_image("/usr/lib/linuxmint/mintMenu/search_engines/dictionary.png")
self.applicationsBox.add(suggestionButton)
self.suggestions.append(suggestionButton)
suggestionButton = SuggestionButton(Gtk.STOCK_FIND, self.iconSize, "")
suggestionButton.connect("clicked", self.Search)
suggestionButton.set_text(_("Search Computer for %s") % text)
self.applicationsBox.add(suggestionButton)
self.suggestions.append(suggestionButton)
#self.last_separator = gtk.EventBox()
#self.last_separator.add(gtk.HSeparator())
#self.last_separator.set_size_request(-1, 20)
#self.last_separator.type = "separator"
#self.mintMenuWin.SetPaneColors( [ self.last_separator ] )
#self.last_separator.show_all()
#self.applicationsBox.add(self.last_separator)
#self.suggestions.append(self.last_separator)
def add_apt_filter_results(self, keyword):
try:
# Wait to see if the keyword has changed.. before doing anything
current_keyword = keyword
current_keyword = self.searchEntry.get_text()
if keyword != current_keyword:
return
found_packages = []
found_in_name = []
found_elsewhere = []
keywords = keyword.split(" ")
command = "cat %(home)s/.linuxmint/mintMenu/apt.cache" % {'home':home}
for word in keywords:
command = "%(command)s | grep %(word)s" % {'command':command, 'word':word}
pkgs = commands.getoutput(command)
pkgs = pkgs.split("\n")
num_pkg_found = 0
for pkg in pkgs:
values = string.split(pkg, "###")
if len(values) == 4:
status = values[0]
if (status == "ERROR"):
print "Could not refresh APT cache"
elif (status == "CACHE"):
name = values[1]
summary = values[2]
description = values[3].replace("~~~", "\n")
package = PackageDescriptor(name, summary, description)
#See if all keywords are in the name (so we put these results at the top of the list)
some_found = False
some_not_found = False
for word in keywords:
if word in package.name:
some_found = True
else:
some_not_found = True
if some_found and not some_not_found:
found_in_name.append(package)
else:
found_elsewhere.append(package)
num_pkg_found+=1
else:
print "Invalid status code: " + status
found_packages.extend(found_in_name)
found_packages.extend(found_elsewhere)
if keyword == self.searchEntry.get_text() and len(found_packages) > 0:
last_separator = Gtk.EventBox()
last_separator.add(Gtk.HSeparator())
last_separator.set_visible_window(False)
last_separator.set_size_request(-1, 20)
last_separator.type = "separator"
self.mintMenuWin.SetPaneColors( [ last_separator ] )
last_separator.show_all()
self.applicationsBox.add(last_separator)
self.suggestions.append(last_separator)
#Reduce the number of results to 10 max... it takes a HUGE amount of time to add the GTK box in the menu otherwise..
if len(found_packages) > 10:
found_packages = found_packages[:10]
for pkg in found_packages:
name = pkg.name
for word in keywords:
if word != "":
name = name.replace(word, "<b>%s</b>" % word);
suggestionButton = SuggestionButton(Gtk.STOCK_ADD, self.iconSize, "")
suggestionButton.connect("clicked", self.apturl_install, pkg.name)
suggestionButton.set_text(_("Install package '%s'") % name)
suggestionButton.set_tooltip_text("%s\n\n%s\n\n%s" % (pkg.name, pkg.summary, pkg.description))
suggestionButton.set_icon_size(self.iconSize)
self.applicationsBox.add(suggestionButton)
self.suggestions.append(suggestionButton)
#if cache != self.current_results:
# self.current_results.append(pkg)
#if len(found_packages) == 0:
# gtk.gdk.threads_enter()
# try:
# self.applicationsBox.remove(self.last_separator)
# self.suggestions.remove(self.last_separator)
# finally:
# gtk.gdk.threads_leave()
except Exception, detail:
print detail
def add_apt_filter_results_sync(self, cache, keyword):
try:
found_packages = []
keywords = keyword.split(" ")
if cache is not None:
for pkg in cache:
some_found = False
some_not_found = False
for word in keywords:
if word in pkg.name:
some_found = True
else:
some_not_found = True
if some_found and not some_not_found:
found_packages.append(pkg)
if len(found_packages) > 0:
last_separator = Gtk.EventBox()
last_separator.add(Gtk.HSeparator())
last_separator.set_visible_window(False)
last_separator.set_size_request(-1, 20)
last_separator.type = "separator"
self.mintMenuWin.SetPaneColors( [ last_separator ] )
last_separator.show_all()
self.applicationsBox.add(last_separator)
self.suggestions.append(last_separator)
for pkg in found_packages:
name = pkg.name
for word in keywords:
if word != "":
name = name.replace(word, "<b>%s</b>" % word);
suggestionButton = SuggestionButton(Gtk.STOCK_ADD, self.iconSize, "")
suggestionButton.connect("clicked", self.apturl_install, pkg.name)
suggestionButton.set_text(_("Install package '%s'") % name)
suggestionButton.set_tooltip_text("%s\n\n%s\n\n%s" % (pkg.name, pkg.summary.capitalize(), pkg.description))
suggestionButton.set_icon_size(self.iconSize)
self.applicationsBox.add(suggestionButton)
self.suggestions.append(suggestionButton)
#if len(found_packages) == 0:
# self.applicationsBox.remove(self.last_separator)
# self.suggestions.remove(self.last_separator)
except Exception, detail:
print detail
def Filter( self, widget, category = None ):
self.filterTimer = None
for suggestion in self.suggestions:
self.applicationsBox.remove(suggestion)
self.suggestions = []
if widget == self.searchEntry:
if self.donotfilterapps:
widget.set_text( "" )
else:
text = widget.get_text()
if self.lastActiveTab != 1:
self.changeTab( 1 )
widget.set_text( text )
text = widget.get_text()
showns = False # Are any app shown?
shownList = []
for i in self.applicationsBox.get_children():
shown = i.filterText( text )
if (shown):
dupe = False
for item in shownList:
if i.desktopFile == item.desktopFile:
dupe = True
if dupe:
i.hide()
else:
shownList.append(i)
showns = True
if (not showns and os.path.exists("/usr/lib/linuxmint/mintInstall/icon.svg")):
if len(text) >= 3:
if self.current_suggestion is not None and self.current_suggestion in text:
# We're restricting our search...
self.add_search_suggestions(text)
#if (len(self.current_results) > 0):
#self.add_apt_filter_results_sync(self.current_results, text)
#else:
GLib.timeout_add (300, self.add_apt_filter_results, text)
else:
self.current_results = []
self.add_search_suggestions(text)
GLib.timeout_add (300, self.add_apt_filter_results, text)
self.current_suggestion = text
else:
self.current_suggestion = None
self.current_results = []
else:
self.current_suggestion = None
self.current_results = []
for i in self.categoriesBox.get_children():
i.released()
i.set_relief( Gtk.ReliefStyle.NONE )
allButton = self.categoriesBox.get_children()[0];
allButton.set_relief( Gtk.ReliefStyle.HALF )
self.activeFilter = (0, text, widget)
else:
#print "CATFILTER"
self.activeFilter = (1, category, widget)
if category == "":
listedDesktopFiles = []
for i in self.applicationsBox.get_children():
if not i.desktop_file_path in listedDesktopFiles:
listedDesktopFiles.append( i.desktop_file_path )
i.show_all()
else:
i.hide()
else:
for i in self.applicationsBox.get_children():
i.filterCategory( category )
for i in self.categoriesBox.get_children():
i.released()
i.set_relief( Gtk.ReliefStyle.NONE )
widget.set_relief( Gtk.ReliefStyle.HALF )
self.applicationsScrolledWindow.get_vadjustment().set_value( 0 )
def FilterAndClear( self, widget, category = None ):
self.searchEntry.set_text( "" )
self.Filter( widget, category )
# Forward all text to the search box
def keyPress( self, widget, event ):
if event.string.strip() != "" or event.keyval == Gdk.KEY_BackSpace:
self.searchEntry.grab_focus()
gtk.gtk_editable_set_position(hash(self.searchEntry), -1)
self.searchEntry.event( event )
return True
if event.keyval == Gdk.KEY_Down and self.searchEntry.is_focus():
self.applicationsBox.get_children()[0].grab_focus()
return False
def favPopup( self, widget, ev ):
if ev.button == 3:
if ev.y > widget.get_allocation().height / 2:
insertBefore = False
else:
insertBefore = True
if widget.type == "location":
mTree = Gtk.Menu()
mTree.set_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_HINT_MASK |
Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
#i18n
desktopMenuItem = Gtk.MenuItem(_("Add to desktop"))
panelMenuItem = Gtk.MenuItem(_("Add to panel"))
separator1 = Gtk.SeparatorMenuItem()
insertSpaceMenuItem = Gtk.MenuItem(_("Insert space"))
insertSeparatorMenuItem = Gtk.MenuItem(_("Insert separator"))
separator2 = Gtk.SeparatorMenuItem()
startupMenuItem = Gtk.CheckMenuItem(_("Launch when I log in"))
separator3 = Gtk.SeparatorMenuItem()
launchMenuItem = Gtk.MenuItem(_("Launch"))
removeFromFavMenuItem = Gtk.MenuItem(_("Remove from favorites"))
separator4 = Gtk.SeparatorMenuItem()
propsMenuItem = Gtk.MenuItem(_("Edit properties"))
desktopMenuItem.connect("activate", self.add_to_desktop, widget)
panelMenuItem.connect("activate", self.add_to_panel, widget)
insertSpaceMenuItem.connect( "activate", self.onFavoritesInsertSpace, widget, insertBefore )
insertSeparatorMenuItem.connect( "activate", self.onFavoritesInsertSeparator, widget, insertBefore )
if widget.isInStartup():
startupMenuItem.set_active( True )
startupMenuItem.connect( "toggled", self.onRemoveFromStartup, widget )
else:
startupMenuItem.set_active( False )
startupMenuItem.connect( "toggled", self.onAddToStartup, widget )
launchMenuItem.connect( "activate", self.onLaunchApp, widget)
removeFromFavMenuItem.connect( "activate", self.onFavoritesRemove, widget )
propsMenuItem.connect( "activate", self.onPropsApp, widget)
if self.de == "mate":
mTree.append(desktopMenuItem)
mTree.append(panelMenuItem)
mTree.append(separator1)
mTree.append(insertSpaceMenuItem)
mTree.append(insertSeparatorMenuItem)
mTree.append(separator2)
mTree.append(startupMenuItem)
mTree.append(separator3)
mTree.append(launchMenuItem)
mTree.append(removeFromFavMenuItem)
mTree.append(separator4)
mTree.append(propsMenuItem)
mTree.show_all()
gtk.gtk_menu_popup(hash(mTree), None, None, None, None, ev.button, ev.time)
#self.mintMenuWin.grab()
mTree.connect( 'deactivate', self.onMenuPopupDeactivate)
else:
mTree = Gtk.Menu()
mTree.set_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_HINT_MASK |
Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
#i18n
removeMenuItem = Gtk.MenuItem(_("Remove"))
insertSpaceMenuItem = Gtk.MenuItem(_("Insert space"))
insertSeparatorMenuItem = Gtk.MenuItem(_("Insert separator"))
mTree.append(removeMenuItem)
mTree.append(insertSpaceMenuItem)
mTree.append(insertSeparatorMenuItem)
mTree.show_all()
removeMenuItem.connect( "activate", self.onFavoritesRemove, widget )
insertSpaceMenuItem.connect( "activate", self.onFavoritesInsertSpace, widget, insertBefore )
insertSeparatorMenuItem.connect( "activate", self.onFavoritesInsertSeparator, widget, insertBefore )
gtk.gtk_menu_popup(hash(mTree), None, None, None, None, ev.button, ev.time)
#self.mintMenuWin.grab()
mTree.connect( 'deactivate', self.onMenuPopupDeactivate)
def menuPopup( self, widget, event ):
if event.button == 3:
mTree = Gtk.Menu()
#i18n
desktopMenuItem = Gtk.MenuItem(_("Add to desktop"))
panelMenuItem = Gtk.MenuItem(_("Add to panel"))
separator1 = Gtk.SeparatorMenuItem()
favoriteMenuItem = Gtk.CheckMenuItem(_("Show in my favorites"))
startupMenuItem = Gtk.CheckMenuItem(_("Launch when I log in"))
separator2 = Gtk.SeparatorMenuItem()
launchMenuItem = Gtk.MenuItem(_("Launch"))
uninstallMenuItem = Gtk.MenuItem(_("Uninstall"))
deleteMenuItem = Gtk.MenuItem(_("Delete from menu"))
separator3 = Gtk.SeparatorMenuItem()
propsMenuItem = Gtk.MenuItem(_("Edit properties"))
if self.de == "mate":
mTree.append(desktopMenuItem)
mTree.append(panelMenuItem)
mTree.append(separator1)
mTree.append(favoriteMenuItem)
mTree.append(startupMenuItem)
mTree.append(separator2)
mTree.append(launchMenuItem)
mTree.append(uninstallMenuItem)
if home in widget.desktopFile:
mTree.append(deleteMenuItem)
deleteMenuItem.connect("activate", self.delete_from_menu, widget)
mTree.append(separator3)
mTree.append(propsMenuItem)
mTree.show_all()
desktopMenuItem.connect("activate", self.add_to_desktop, widget)
panelMenuItem.connect("activate", self.add_to_panel, widget)
launchMenuItem.connect( "activate", self.onLaunchApp, widget )
propsMenuItem.connect( "activate", self.onPropsApp, widget)
uninstallMenuItem.connect ( "activate", self.onUninstallApp, widget )
if self.isLocationInFavorites( widget.desktopFile ):
favoriteMenuItem.set_active( True )
favoriteMenuItem.connect( "toggled", self.onRemoveFromFavorites, widget )
else:
favoriteMenuItem.set_active( False )
favoriteMenuItem.connect( "toggled", self.onAddToFavorites, widget )
if widget.isInStartup():
startupMenuItem.set_active( True )
startupMenuItem.connect( "toggled", self.onRemoveFromStartup, widget )
else:
startupMenuItem.set_active( False )
startupMenuItem.connect( "toggled", self.onAddToStartup, widget )
mTree.connect( 'deactivate', self.onMenuPopupDeactivate)
gtk.gtk_menu_popup(hash(mTree), None, None, None, None, event.button, event.time)
def onMenuPopupDeactivate( self, widget):
self.mintMenuWin.grab()
def searchPopup( self, widget=None, event=None ):
menu = Gtk.Menu()
menuItem = Gtk.ImageMenuItem(_("Search Google"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/google.ico')
menuItem.set_image(img)
menuItem.connect("activate", self.search_google)
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Search Wikipedia"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/wikipedia.ico')
menuItem.set_image(img)
menuItem.connect("activate", self.search_wikipedia)
menu.append(menuItem)
menuItem = Gtk.SeparatorMenuItem()
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Lookup Dictionary"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/dictionary.png')
menuItem.set_image(img)
menuItem.connect("activate", self.search_dictionary)
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Search Computer"))
img = Gtk.Image()
img.set_from_stock(Gtk.STOCK_FIND, self.iconSize)
menuItem.set_image(img)
menuItem.connect("activate", self.Search)
menu.append(menuItem)
menuItem = Gtk.SeparatorMenuItem()
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Find Software"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/software.png')
menuItem.set_image(img)
menuItem.connect("activate", self.search_mint_software)
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Find Tutorials"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/tutorials.png')
menuItem.set_image(img)
menuItem.connect("activate", self.search_mint_tutorials)
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Find Hardware"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/hardware.png')
menuItem.set_image(img)
menuItem.connect("activate", self.search_mint_hardware)
menu.append(menuItem)
menuItem =Gtk.ImageMenuItem(_("Find Ideas"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/ideas.png')
menuItem.set_image(img)
menuItem.connect("activate", self.search_mint_ideas)
menu.append(menuItem)
menuItem = Gtk.ImageMenuItem(_("Find Users"))
img = Gtk.Image()
img.set_from_file('/usr/lib/linuxmint/mintMenu/search_engines/users.png')
menuItem.set_image(img)
menuItem.connect("activate", self.search_mint_users)
menu.append(menuItem)
menu.show_all()
gtk.gtk_menu_popup(hash(menu), None, None, None, None, event.button, event.time)
#menu.attach_to_widget(self.searchButton, None)
#menu.reposition()
#menu.reposition()
#self.mintMenuWin.grab()
menu.connect( 'deactivate', self.onMenuPopupDeactivate)
return True
def pos_func(self, menu=None):
rect = self.searchButton.get_allocation()
x = rect.x + rect.width
y = rect.y + rect.height
return (x, y, False)
def search_google(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "+")
os.system("xdg-open \"http://www.google.com/cse?cx=002683415331144861350%3Atsq8didf9x0&ie=utf-8&sa=Search&q=" + text + "\" &")
self.mintMenuWin.hide()
def search_wikipedia(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "+")
os.system("xdg-open \"http://en.wikipedia.org/wiki/Special:Search?search=" + text + "\" &")
self.mintMenuWin.hide()
def search_dictionary(self, widget):
text = self.searchEntry.get_text()
os.system("mate-dictionary \"" + text + "\" &")
self.mintMenuWin.hide()
def search_mint_tutorials(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "%20")
os.system("xdg-open \"http://community.linuxmint.com/index.php/tutorial/search/0/" + text + "\" &")
self.mintMenuWin.hide()
def search_mint_ideas(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "%20")
os.system("xdg-open \"http://community.linuxmint.com/index.php/idea/search/0/" + text + "\" &")
self.mintMenuWin.hide()
def search_mint_users(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "%20")
os.system("xdg-open \"http://community.linuxmint.com/index.php/user/search/0/" + text + "\" &")
self.mintMenuWin.hide()
def search_mint_hardware(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "%20")
os.system("xdg-open \"http://community.linuxmint.com/index.php/hardware/search/0/" + text + "\" &")
self.mintMenuWin.hide()
def search_mint_software(self, widget):
text = self.searchEntry.get_text()
text = text.replace(" ", "%20")
os.system("xdg-open \"http://community.linuxmint.com/index.php/software/search/0/" + text + "\" &")
self.mintMenuWin.hide()
def add_to_desktop(self, widget, desktopEntry):
try:
# Determine where the Desktop folder is (could be localized)
import sys, commands
sys.path.append('/usr/lib/linuxmint/common')
from configobj import ConfigObj
config = ConfigObj(home + "/.config/user-dirs.dirs")
desktopDir = home + "/Desktop"
tmpdesktopDir = config['XDG_DESKTOP_DIR']
tmpdesktopDir = commands.getoutput("echo " + tmpdesktopDir)
if os.path.exists(tmpdesktopDir):
desktopDir = tmpdesktopDir
# Copy the desktop file to the desktop
os.system("cp \"%s\" \"%s/\"" % (desktopEntry.desktopFile, desktopDir))
os.system("chmod a+rx %s/*.desktop" % (desktopDir))
except Exception, detail:
print detail
def add_to_panel(self, widget, desktopEntry):
self.get_panel()
i = 0
panel_schema = Gio.Settings.new("org.mate.panel")
applet_list = panel_schema.get_strv("object-id-list")
while True:
test_obj = "object_%d" % (i)
if test_obj in applet_list:
i += 1
else:
break
path = "/org/mate/panel/objects/%s/" % (test_obj)
new_schema = Gio.Settings.new_with_path("org.mate.panel.object", path)
new_schema.set_string("launcher-location", desktopEntry.desktopFile)
new_schema.set_string("object-type", "launcher")
new_schema.set_string("toplevel-id", self.panel)
new_schema.set_int("position", self.panel_position)
applet_list.append(test_obj)
panel_schema.set_strv("object-id-list", applet_list)
def delete_from_menu(self, widget, desktopEntry):
try:
os.system("rm \"%s\" &" % desktopEntry.desktopFile)
except Exception, detail:
print detail
def onLaunchApp( self, menu, widget ):
widget.execute()
self.mintMenuWin.hide()
def onPropsApp( self, menu, widget ):
newFileFlag = False
sysPaths = get_system_item_paths()
for path in sysPaths:
path += "applications"
relPath = os.path.relpath(widget.desktopFile, path)
if widget.desktopFile == os.path.join(path, relPath):
filePath = os.path.join(get_user_item_path(), relPath)
(head,tail) = os.path.split(filePath)
if not os.path.isdir(head):
os.makedirs(head)
if not os.path.isfile(filePath):
data = open(widget.desktopFile).read()
open(filePath, 'w').write(data)
newFileFlag = True
break
else:
filePath = widget.desktopFile
self.mintMenuWin.hide()
Gdk.flush()
editProcess = subprocess.Popen(["/usr/bin/mate-desktop-item-edit", filePath])
subprocess.Popen.communicate(editProcess)
if newFileFlag:
if filecmp.cmp(widget.desktopFile, filePath):
os.remove(filePath)
else:
favoriteChange = 0
for favorite in self.favorites:
if favorite.type == "location":
if favorite.desktopFile == widget.desktopFile:
favorite.desktopFile = filePath
favoriteChange = 1
if favoriteChange == 1:
self.favoritesSave()
self.buildFavorites()
else:
self.buildFavorites()
def onUninstallApp( self, menu, widget ):
widget.uninstall()
self.mintMenuWin.hide()
def onFavoritesInsertSpace( self, menu, widget, insertBefore ):
if insertBefore:
self.favoritesAdd( self.favoritesBuildSpace(), widget.position )
else:
self.favoritesAdd( self.favoritesBuildSpace(), widget.position + 1 )
def onFavoritesInsertSeparator( self, menu, widget, insertBefore ):
if insertBefore:
self.favoritesAdd( self.favoritesBuildSeparator(), widget.position )
else:
self.favoritesAdd( self.favoritesBuildSeparator(), widget.position + 1 )
def onFavoritesRemove( self, menu, widget ):
self.favoritesRemove( widget.position )
def onAddToStartup( self, menu, widget ):
widget.addToStartup()
def onRemoveFromStartup( self, menu, widget ):
widget.removeFromStartup()
def onAddToFavorites( self, menu, widget ):
self.favoritesAdd( self.favoritesBuildLauncher( widget.desktopFile ) )
def onRemoveFromFavorites( self, menu, widget ):
self.favoritesRemoveLocation( widget.desktopFile )
def ReceiveCallback( self, widget, context, x, y, selection, targetType, time ):
if targetType == self.TARGET_TYPE_TEXT:
for uri in selection.get_uris():
self.favoritesAdd( self.favoritesBuildLauncher( uri ) )
def Search( self, widget ):
text = self.searchEntry.get_text().strip()
if text != "":
self.mintMenuWin.hide()
fullstring = self.searchtool.replace( "%s", text )
os.system(fullstring + " &")
def SearchWithButton( self, widget, event ):
self.Search( widget )
def do_plugin( self ):
self.Todos()
self.buildFavorites()
# Scroll button into view
def scrollItemIntoView( self, widget, event = None ):
viewport = widget.parent
while not isinstance( viewport, Gtk.Viewport ):
if not viewport.parent:
return
viewport = viewport.parent
aloc = widget.get_allocation()
viewport.get_vadjustment().clamp_page(aloc.y, aloc.y + aloc.height)
def favoritesBuildSpace( self ):
space = Gtk.EventBox()
space.set_size_request( -1, 20 )
space.set_visible_window(False)
space.connect( "button-press-event", self.favPopup )
space.type = "space"
self.mintMenuWin.SetPaneColors( [ space ] )
space.show()
return space
def favoritesBuildSeparator( self ):
separator = Gtk.HSeparator()
separator.set_size_request( -1, 20 )
separator.type = "separator"
self.mintMenuWin.SetPaneColors( [ separator ] )
separator.show_all()
box = Gtk.EventBox()
box.type = "separator"
box.add(separator)
box.set_visible_window(False)
box.connect( "button-press-event", self.favPopup )
box.show_all()
return box
def favoritesBuildLauncher( self, location ):
try:
ButtonIcon = None
# For Folders and Network Shares
location = string.join( location.split( "%20" ) )
if location.startswith( "file" ):
ButtonIcon = "mate-fs-directory"
if location.startswith( "smb" ) or location.startswith( "ssh" ) or location.startswith( "network" ):
ButtonIcon = "mate-fs-network"
#For Special locations
if location == "x-nautilus-desktop:///computer":
location = "/usr/share/applications/nautilus-computer.desktop"
elif location == "x-nautilus-desktop:///home":
location = "/usr/share/applications/nautilus-home.desktop"
elif location == "x-nautilus-desktop:///network":
location = "/usr/share/applications/network-scheme.desktop"
elif location.startswith( "x-nautilus-desktop:///" ):
location = "/usr/share/applications/nautilus-computer.desktop"
if location.startswith( "file://" ):
location = location[7:]
# Don't add a location twice
for fav in self.favorites:
if fav.type == "location" and fav.desktopFile == location:
return None
favButton = FavApplicationLauncher( location, self.faviconsize, self.swapgeneric )
if favButton.appExec:
favButton.show()
favButton.connect( "popup-menu", self.favPopup )
favButton.connect( "button-press-event", self.favPopup )
favButton.connect( "focus-in-event", self.scrollItemIntoView )
favButton.connect( "clicked", lambda w: self.mintMenuWin.hide() )
self.mintMenuWin.setTooltip( favButton, favButton.getTooltip() )
favButton.type = "location"
return favButton
except Exception, e:
print u"File in favorites not found: '" + location + "'", e
return None
def buildFavorites( self ):
try:
from user import home
if (not os.path.exists(home + "/.linuxmint/mintMenu/applications.list")):
os.system("mkdir -p " + home + "/.linuxmint/mintMenu/applications")
os.system("cp /usr/lib/linuxmint/mintMenu/applications.list " + home + "/.linuxmint/mintMenu/applications.list")
applicationsFile = open ( os.path.join( os.path.expanduser( "~" ), ".linuxmint", "mintMenu", "applications.list" ), "r" )
applicationsList = applicationsFile.readlines()
self.favorites = []
for child in self.favoritesBox:
child.destroy()
position = 0
for app in applicationsList :
app = app.strip()
if app[0:9] == "location:":
favButton = self.favoritesBuildLauncher( app[9:] )
elif app == "space":
favButton = self.favoritesBuildSpace()
elif app == "separator":
favButton = self.favoritesBuildSeparator()
else:
if ( app.endswith( ".desktop" ) ):
favButton = self.favoritesBuildLauncher( app )
else:
favButton = None
if favButton:
favButton.position = position
self.favorites.append( favButton )
self.favoritesPositionOnGrid( favButton )
favButton.connect( "drag-data-received", self.onFavButtonDragReorder )
gtk.gtk_drag_dest_set( hash(favButton), Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP, self.fromFav, 2, Gdk.DragAction.COPY )
favButton.connect( "drag-data-get", self.onFavButtonDragReorderGet )
gtk.gtk_drag_source_set( hash(favButton), Gdk.ModifierType.BUTTON1_MASK, self.toFav, 3, Gdk.DragAction.COPY )
position += 1
self.favoritesSave()
except Exception, e:
print e
def favoritesGetNumRows( self ):
rows = 0
col = 0
for fav in self.favorites:
if ( fav.type == "separator" or fav.type == "space" ) and col != 0:
rows += 1
col = 0
col += 1
if fav.type == "separator" or fav.type == "space":
rows += 1
col = 0
if col >= self.favCols:
rows += 1
col = 0
return rows
def favoritesPositionOnGrid( self, favorite ):
row = 0
col = 0
for fav in self.favorites:
if ( fav.type == "separator" or fav.type == "space" ) and col != 0:
row += 1
col = 0
if fav.position == favorite.position:
break
col += 1
if fav.type == "separator" or fav.type == "space":
row += 1
col = 0
if col >= self.favCols:
row += 1
col = 0
if favorite.type == "separator" or favorite.type == "space":
self.favoritesBox.attach( favorite, col, col + self.favCols, row, row + 1, yoptions = 0 )
else:
self.favoritesBox.attach( favorite, col, col + 1, row, row + 1, yoptions = 0 )
def favoritesReorder( self, oldposition, newposition ):
if oldposition == newposition:
return
tmp = self.favorites[ oldposition ]
if newposition > oldposition:
if ( self.favorites[ newposition - 1 ].type == "space" or self.favorites[ newposition - 1 ].type == "separator" ) and self.favCols > 1:
newposition = newposition - 1
for i in range( oldposition, newposition ):
self.favorites[ i ] = self.favorites[ i + 1 ]
self.favorites[ i ].position = i
elif newposition < oldposition:
for i in range( 0, oldposition - newposition ):
self.favorites[ oldposition - i ] = self.favorites[ oldposition - i - 1 ]
self.favorites[ oldposition - i ] .position = oldposition - i
self.favorites[ newposition ] = tmp
self.favorites[ newposition ].position = newposition
for fav in self.favorites:
self.favoritesBox.remove( fav )
self.favoritesPositionOnGrid( fav )
self.favoritesSave()
self.favoritesBox.resize( self.favoritesGetNumRows(), self.favCols )
def favoritesAdd( self, favButton, position = -1 ):
if favButton:
favButton.position = len( self.favorites )
self.favorites.append( favButton )
self.favoritesPositionOnGrid( favButton )
favButton.connect( "drag-data-received", self.onFavButtonDragReorder )
gtk.gtk_drag_dest_set( hash(favButton), Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP, self.toFav, 3, Gdk.DragAction.COPY )
favButton.connect( "drag-data-get", self.onFavButtonDragReorderGet )
gtk.gtk_drag_source_set ( hash(favButton), Gdk.ModifierType.BUTTON1_MASK, self.toFav, 3, Gdk.DragAction.COPY )
if position >= 0:
self.favoritesReorder( favButton.position, position )
self.favoritesSave()
def favoritesRemove( self, position ):
tmp = self.favorites[ position ]
self.favorites.remove( self.favorites[ position ] )
tmp.destroy()
for i in range( position, len( self.favorites ) ):
self.favorites[ i ].position = i
self.favoritesBox.remove( self.favorites[ i ] )
self.favoritesPositionOnGrid( self.favorites[ i ] )
self.favoritesSave()
self.favoritesBox.resize( self.favoritesGetNumRows(), self.favCols )
def favoritesRemoveLocation( self, location ):
for fav in self.favorites:
if fav.type == "location" and fav.desktopFile == location:
self.favoritesRemove( fav.position )
def favoritesSave( self ):
try:
self.checkMintMenuFolder()
appListFile = open( os.path.join( os.path.expanduser( "~"), ".linuxmint", "mintMenu", "applications.list" ) , "w" )
for favorite in self.favorites:
if favorite.type == "location":
appListFile.write( "location:" + favorite.desktopFile + "\n" )
else:
appListFile.write( favorite.type + "\n" )
appListFile.close( )
except Exception, e:
msgDlg = Gtk.MessageDialog( None, gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, _("Couldn't save favorites. Check if you have write access to ~/.linuxmint/mintMenu")+"\n(" + e.__str__() + ")" )
msgDlg.run();
msgDlg.destroy();
def isLocationInFavorites( self, location ):
for fav in self.favorites:
if fav.type == "location" and fav.desktopFile == location:
return True
return False
def onFavButtonDragReorderGet( self, widget, context, selection, targetType, eventTime ):
if targetType == self.TARGET_TYPE_FAV:
self.drag_origin = widget.position
selection.set( selection.target, 8, str(widget.position))
def onFavButtonDragReorder( self, widget, context, x, y, selection, targetType, time ):
if targetType == self.TARGET_TYPE_FAV:
#self.favoritesReorder( int(selection.data), widget.position )
self.favoritesReorder( self.drag_origin, widget.position )
def menuChanged( self, x, y ):
# wait some miliseconds because there a multiple events send at the same time and we don't want to rebuild the menu for each
if self.menuChangedTimer:
GLib.source_remove( self.menuChangedTimer )
self.menuChangedTimer = GLib.timeout_add( 100, self.updateBoxes, True )
def updateBoxes( self, menu_has_changed ):
# FIXME: This is really bad!
if self.rebuildLock:
return
self.rebuildLock = True
self.menuChangedTimer = None
self.loadMenuFiles()
# Find added and removed categories than update the category list
newCategoryList = self.buildCategoryList()
addedCategories = []
removedCategories = []
# TODO: optimize this!!!
if not self.categoryList:
addedCategories = newCategoryList
else:
for item in newCategoryList:
found = False
for item2 in self.categoryList:
pass
if item["name"] == item2["name"] and item["icon"] == item2["icon"] and item["tooltip"] == item2["tooltip"] and item["index"] == item2["index"]:
found = True
break
if not found:
addedCategories.append(item)
for item in self.categoryList:
found = False
for item2 in newCategoryList:
if item["name"] == item2["name"] and item["icon"] == item2["icon"] and item["tooltip"] == item2["tooltip"] and item["index"] == item2["index"]:
found = True
break
if not found:
removedCategories.append( item )
if self.showcategoryicons == True:
categoryIconSize = self.iconSize
else:
categoryIconSize = 0
for item in removedCategories:
try:
button = item["button"]
self.categoryList.remove(item)
button.destroy()
del item
except Exception, e:
print e
if addedCategories:
sortedCategoryList = []
for item in self.categoryList:
try:
self.categoriesBox.remove( item["button"] )
sortedCategoryList.append( ( str(item["index"]) + item["name"], item["button"] ) )
except Exception, e:
print e
# Create new category buttons and add the to the list
for item in addedCategories:
try:
item["button"] = CategoryButton( item["icon"], categoryIconSize, [ item["name"] ], item["filter"] )
self.mintMenuWin.setTooltip( item["button"], item["tooltip"] )
if self.categories_mouse_over:
startId = item["button"].connect( "enter", self.StartFilter, item["filter"] )
stopId = item["button"].connect( "leave", self.StopFilter )
item["button"].mouseOverHandlerIds = ( startId, stopId )
else:
item["button"].mouseOverHandlerIds = None
item["button"].connect( "clicked", self.FilterAndClear, item["filter"] )
item["button"].connect( "focus-in-event", self.categoryBtnFocus, item["filter"] )
item["button"].show()
self.categoryList.append( item )
sortedCategoryList.append( ( str(item["index"]) + item["name"], item["button"] ) )
except Exception, e:
print e
sortedCategoryList.sort()
for item in sortedCategoryList:
try:
self.categoriesBox.pack_start( item[1], False, False, 0 )
except Exception, e:
print e
# Find added and removed applications add update the application list
newApplicationList = self.buildApplicationList()
addedApplications = []
removedApplications = []
# TODO: optimize this!!!
if not self.applicationList:
addedApplications = newApplicationList
else:
for item in newApplicationList:
found = False
for item2 in self.applicationList:
if item["entry"].get_desktop_file_path() == item2["entry"].get_desktop_file_path():
found = True
break
if not found:
addedApplications.append(item)
key = 0
for item in self.applicationList:
found = False
for item2 in newApplicationList:
if item["entry"].get_desktop_file_path() == item2["entry"].get_desktop_file_path():
found = True
break
if not found:
removedApplications.append(key)
else:
# don't increment the key if this item is going to be removed
# because when it is removed the index of all later items is
# going to be decreased
key += 1
for key in removedApplications:
self.applicationList[key]["button"].destroy()
del self.applicationList[key]
if addedApplications:
sortedApplicationList = []
for item in self.applicationList:
self.applicationsBox.remove( item["button"] )
sortedApplicationList.append( ( item["button"].appName, item["button"] ) )
for item in addedApplications:
item["button"] = MenuApplicationLauncher( item["entry"].get_desktop_file_path(), self.iconSize, item["category"], self.showapplicationcomments, highlight=(True and menu_has_changed) )
if item["button"].appExec:
self.mintMenuWin.setTooltip( item["button"], item["button"].getTooltip() )
item["button"].connect( "button-press-event", self.menuPopup )
item["button"].connect( "focus-in-event", self.scrollItemIntoView )
item["button"].connect( "clicked", lambda w: self.mintMenuWin.hide() )
if self.activeFilter[0] == 0:
item["button"].filterText( self.activeFilter[1] )
else:
item["button"].filterCategory( self.activeFilter[1] )
item["button"].desktop_file_path = item["entry"].get_desktop_file_path()
sortedApplicationList.append( ( item["button"].appName.upper(), item["button"] ) )
self.applicationList.append( item )
else:
item["button"].destroy()
sortedApplicationList.sort()
for item in sortedApplicationList:
self.applicationsBox.pack_start( item[1], False, False, 0 )
self.rebuildLock = False
# Reload the menufiles from the filesystem
def loadMenuFiles( self ):
self.menuFiles = []
for mainitems in [ "mate-applications.menu", "mate-settings.menu" ]:
self.menuFiles.append( Menu( mainitems) )
# Build a list of all categories in the menu ( [ { "name", "icon", tooltip" } ]
def buildCategoryList( self ):
newCategoryList = [ { "name": _("All"), "icon": "stock_select-all", "tooltip": _("Show all applications"), "filter":"", "index": 0 } ]
num = 1
for menu in self.menuFiles:
for child in menu.directory.get_contents():
if child.get_type() == matemenu.TYPE_DIRECTORY:
icon = str(child.icon)
#if (icon == "preferences-system"):
# self.adminMenu = child.name
#if (icon != "applications-system" and icon != "applications-other"):
newCategoryList.append( { "name": child.name, "icon": child.icon, "tooltip": child.name, "filter": child.name, "index": num } )
num += 1
return newCategoryList
# Build a list containing the DesktopEntry object and the category of each application in the menu
def buildApplicationList( self ):
newApplicationsList = []
def find_applications_recursively(app_list, directory, catName):
for item in directory.get_contents():
if item.get_type() == matemenu.TYPE_ENTRY:
print "=======>>> " + str(item.name) + " = " + str(catName)
app_list.append( { "entry": item, "category": catName } )
elif item.get_type() == matemenu.TYPE_DIRECTORY:
find_applications_recursively(app_list, item, catName)
for menu in self.menuFiles:
directory = menu.directory
for entry in directory.get_contents():
if entry.get_type() == matemenu.TYPE_DIRECTORY and len(entry.get_contents()):
#Entry is a top-level category
#catName = entry.name
#icon = str(entry.icon)
#if (icon == "applications-system" or icon == "applications-other"):
# catName = self.adminMenu
for item in entry.get_contents():
if item.get_type() == matemenu.TYPE_DIRECTORY:
find_applications_recursively(newApplicationsList, item, entry.name)
elif item.get_type() == matemenu.TYPE_ENTRY:
newApplicationsList.append( { "entry": item, "category": entry.name } )
#elif entry.get_type() == matemenu.TYPE_ENTRY:
# if not (entry.get_is_excluded() or entry.get_is_nodisplay()):
# print "=======>>> " + item.name + " = top level"
# newApplicationsList.append( { "entry": item, "category": "" } )
return newApplicationsList