# USP Tracker plugin ##Description:Tracker Search plugin by Quikee import gtk import gtk.glade import sys import os import gobject import datetime import gconf import fcntl import pango import dbus import gnomevfs import gnome.ui try: import beagle except: print "Beagle not found.." from execute import Execute from easygconf import * from easyfiles import * from easybuttons import * from usp_util import * class Tracker: def __init__(self): self.tracker = None self.services = ['Files','Documents','Images','Music','Text Files','Videos'] def ensureInitialization(self): if self.tracker == None: print "Initializing Tracker..." try: bus = dbus.SessionBus() self.tracker = bus.get_object('org.freedesktop.Tracker','/org/freedesktop/tracker') self.search_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Search') print "Initialization Complete..." except: self.tracker = None print "Initialization Failed..." return self def search(self, text, service='Files', offset=0, max_hits=-1): if self.tracker == None: return None returnedfiles = self.search_iface.TextDetailed(1, service, text, offset, max_hits) if len(returnedfiles) > 0: return returnedfiles else: return None class Beagle: def hits_added_cb (self, query, response): hits = response.get_hits() for hit in hits: hitType = hit.get_type() if hitType == "File": hitUri = hit.get_parent_uri() if hitUri == None: hitUri = hit.get_uri() hitFilePath = gnomevfs.get_local_path_from_uri(hitUri) hitMime = hit.get_mime_type() self.results.append([hitFilePath, hitType, hitMime]) def finished_cb (self, query, response, loop): self.main_loop.quit() def search(self, queryString): self.results = [] client = beagle.Client() self.main_loop = gobject.MainLoop() query = beagle.Query() query.add_text(queryString) query.connect("hits-added", self.hits_added_cb) query.connect("finished", self.finished_cb, self.main_loop) client.send_request_async(query) self.main_loop.run() return self.results class pluginclass: """This is the main class for the plugin""" """It MUST be named pluginclass""" def __init__( self, USPWin ): self.USPWin = USPWin #The Glade file for the plugin self.gladefile = os.path.join( os.path.dirname( __file__ ), "tracker.glade" ) #Read GLADE file self.wTree = gtk.glade.XML( self.gladefile, 'window1' ) self.RecentTips = gtk.Tooltips() #These properties are NECESSARY to maintain consistency #throughout USP #Set 'window' property for the plugin (Must be the root widget) self.window = self.wTree.get_widget( "window1" ) #Set 'heading' property for plugin self.heading = "Search" #This should be the first item added to the window in glade self.content_holder = self.wTree.get_widget( "eventbox1" ) # Items to get custom colors self.itemstocolor = [self.wTree.get_widget( "viewport2" )] #Specify plugin width self.width = 180 #Plugin icon self.icon = 'gnome-folder.png' self.tracker = Tracker() #self.beagle = Beagle() self.searchText = None self.thumb_factory = gnome.ui.ThumbnailFactory("normal") self.filterUsed = self.tracker.services[0] self.gconf_dir = '/apps/usp/plugins/tracker' self.client = gconf.client_get_default() self.client.add_dir( self.gconf_dir, gconf.CLIENT_PRELOAD_NONE ) self.client.notify_add( self.gconf_dir + '/height', self.RegenPlugin ) self.client.notify_add( self.gconf_dir + '/width', self.RegenPlugin ) self.client.notify_add( self.gconf_dir + '/font_size', self.RegenPlugin ) self.client.notify_add( self.gconf_dir + '/max_number_of_search_result', self.RegenPlugin ) self.RegenPlugin() self.wTree.get_widget( "SearchTab" ).set_current_page(1) #Connect event handlers dic = { "on_clearButton_clicked" : self.clearSearchBox, "on_searchEntry_changed" : self.searchEntryChanged } self.wTree.signal_autoconnect(dic) def RegenPlugin( self, *args, **kargs ): self.GetGconfEntries() def GetGconfEntries( self ): self.client = gconf.client_get_default() self.height = SetGconf( self.client, 'int', self.gconf_dir+'/height', 385 ) self.width = SetGconf( self.client, 'int', self.gconf_dir+'/width', 250 ) self.fontsize = SetGconf( self.client, 'int', self.gconf_dir+'/font_size', 10 ) # Hide vertical dotted separator self.hideseparator = SetGconf( self.client, "bool", self.gconf_dir+"/hide_separator", False ) # Plugin icon self.icon = SetGconf( self.client, "string", self.gconf_dir+'/icon', "system-search" ) # Allow plugin to be minimized to the left plugin pane self.sticky = SetGconf( self.client, "bool", self.gconf_dir+"/sticky", False ) self.minimized = SetGconf( self.client, "bool", self.gconf_dir+"/minimized", False ) # Maximum number of results tracker should return self.maximumNumberOfResults = SetGconf( self.client, "int", self.gconf_dir+"/max_number_of_search_result", 10 ) self.RebuildPlugin() def SetHidden( self, state ): result = (state == True) WriteGconf(self.client, "bool", self.gconf_dir+"/minimized", result) def RebuildPlugin(self): self.content_holder.set_size_request(self.width, self.height) self.searchText = None self.updateFileList() self.updateMenuList() def updateMenuList(self): menuBox = self.wTree.get_widget( "MenuBox" ) if len(menuBox.get_children()) > 0: for each in menuBox.get_children(): each.destroy() for eachService in self.tracker.services: self.addButtonToMenuBox(eachService) def addButtonToMenuBox(self, name): menuBox = self.wTree.get_widget( "MenuBox" ) button = gtk.Button( "", "ok", True ) button.remove( button.get_children()[0] ) button.set_size_request( 130-10, -1 ) button.set_relief( gtk.RELIEF_NONE ) button.connect( "clicked", self.changeFilter, name ) button.set_focus_on_click(False) align = gtk.Alignment( 0, 0.5, 0, 0 ) align.set_padding( 0, 0, 0, 0 ) hBox = gtk.HBox( False, 5 ) vBox = gtk.VBox( False, 2 ) vBox.show() label = gtk.Label( name ) label.set_size_request( button.size_request()[0]-10, -1 ) label.set_ellipsize( pango.ELLIPSIZE_END ) label.show() vBox.add( label ) hBox.add( vBox ) hBox.show() align.add( hBox ) align.show() button.add( align ) button.show() menuBox.pack_start( button, False, True, 0 ) def updateFileList( self, *args, **kargs ): # remove file box entries fileBox = self.wTree.get_widget( "SearchBox" ) for each in fileBox.get_children(): each.destroy() #each.remove() self.wTree.get_widget( "vbox1" ).set_size_request( self.width, self.height ) # search box is empty if self.searchText == None or self.searchText == '': return True # search for files.. fileList = self.tracker.ensureInitialization().search(self.searchText, self.filterUsed, 0 ,self.maximumNumberOfResults) # fileList = self.beagle.search(self.searchText) if fileList == None: return True #update search box entries for eachFile in fileList: self.addButtonToSearchBox( eachFile[0], eachFile[1], eachFile[2]) return True def clearSearchBox(self, *args, **kargs): self.searchText = '' self.wTree.get_widget("searchEntry").set_text(self.searchText) self.updateFileList() self.updateMenuList() def addButtonToSearchBox( self, filePath, fileType, fileMime ): icon = gnome.ui.icon_lookup(icon_theme, self.thumb_factory, filePath, fileMime, 0)[0] fileNameOnly=os.path.basename(filePath) button = gtk.Button( "", "ok", True ) button.remove( button.get_children()[0] ) button.set_size_request( self.width-150-24, -1 ) button.set_relief( gtk.RELIEF_NONE ) button.connect( "button_press_event", self.buttonClicked, filePath, fileMime ) align = gtk.Alignment( 0, 0.5, 0, 0 ) align.set_padding( 0, 0, 0, 0 ) hBox = gtk.HBox( False, 5 ) vBox = gtk.VBox( False, 2 ) vBox.show() label = gtk.Label( fileNameOnly ) label.set_size_request( button.size_request()[0]-20, -1 ) label.set_ellipsize( pango.ELLIPSIZE_END ) label.show() vBox.add( label ) buttonIcon = gtk.Image() buttonIcon.set_from_pixbuf(icon_factory.load_icon(icon, gtk.ICON_SIZE_MENU, False)) hBox.add( buttonIcon ) buttonIcon.show() hBox.add( vBox ) hBox.show() align.add( hBox ) align.show() button.add( align ) button.show() self.RecentTips.set_tip( button, filePath, tip_private=None ) self.wTree.get_widget( "SearchBox" ).pack_start( button, False, True, 0 ) def buttonClicked(self, widget, event, fileName, fileMime): if event.button == 1: command = gnomevfs.mime_get_default_application(fileMime)[2].split() command.append(fileName) self.executeCommand(command) elif event.button == 3: self.showMenuFor(widget, event, fileName, fileMime) def executeCommand(self, command): self.USPWin.wTree.get_widget( "window1" ).hide() os.chdir(os.path.expanduser("~")) pid = os.fork() if pid: os.spawnvp(os.P_NOWAIT,command[0], command) os._exit(0) def showMenuFor(self, itemClicked, ev, fileName, fileMime): self.mTree = gtk.glade.XML( self.gladefile, "menu1" ) menu = self.mTree.get_widget("menu1") x = int( ev.x ) y = int( ev.y ) time = ev.time for eachApplication in gnomevfs.mime_get_all_applications(fileMime): command = eachApplication[2].split() command.append(fileName) item = gtk.MenuItem(eachApplication[1], True) item.show() item.connect( "activate", self.menuItemClicked, command) menu.add(item) menu.popup( None, None, None, ev.button, time ) def menuItemClicked(self, widget, command): self.executeCommand(command) def changeFilter(self, widget, filterName): self.filterUsed = filterName for each in self.wTree.get_widget("MenuBox").get_children(): each.set_relief( gtk.RELIEF_NONE ) widget.set_relief( gtk.RELIEF_HALF ) self.updateFileList() def searchEntryChanged(self, *args, **kargs): self.wTree.get_widget("searchEntry").grab_focus() self.searchText = self.wTree.get_widget("searchEntry").get_text() self.updateFileList() def do_plugin(self): self.searchText = None self.updateFileList() self.updateMenuList() #---------------------------------------------------------------------------------------# # USPconfig Section Below #---------------------------------------------------------------------------------------# # This is the Config Class it must be called "cfgpluginclass' class cfgpluginclass: def __init__(self): # The Gladefile for the plugins USPconfig Tab self.gladefile = os.path.join(os.path.dirname(__file__), "tracker.glade") # Read GLADE file self.wTree = gtk.glade.XML(self.gladefile,"config") # Set 'window' property for the plugin (Must be the root widget) self.window = self.wTree.get_widget("config") # Content Place Holder must be eventbox1 self.content_holder = self.wTree.get_widget("eventbox2") # Set Heading, this will be used for the tab label in USPconfig self.heading = "Tracker" # GConf Stuff - This just makes sure a gconf path is there. self.gconf_dir = '/apps/usp/plugins/tracker' self.client = gconf.client_get_default() self.client.add_dir(self.gconf_dir, gconf.CLIENT_PRELOAD_NONE) # Setup the Functions of the Glade files spin controls or entry boxes for Value Changes # Tip: For spinbutton controls use the "_value_changed" event not the "_changed" event. dic = { "on_window1_destroy" : gtk.main_quit, "on_TrackerFontSizeSpin_changed" : self.fontspin, "on_TrackerHSpin_changed" : self.hspin, "on_TrackerWSpin_changed" : self.wspin, "on_TrackerIconEntry_changed" : self.iconchange, "on_StickyChkBtn_toggled" : self.setsticky, "on_MaximumNumberOfResultSpin1_value_changed" : self.maxNumberOfResults } self.wTree.signal_autoconnect(dic) # Read Values from GConf for USPconfig Tab and Set Default Values in GConf if they don't exist. self.wTree.get_widget("FontSizeSpin").set_value(SetGconf(self.client,'int', self.gconf_dir+'/font_size',9)) self.wTree.get_widget("HSpin").set_value(SetGconf(self.client,'int', self.gconf_dir+'/height',200)) self.wTree.get_widget("WSpin").set_value(SetGconf(self.client,'int', self.gconf_dir+'/width',250)) self.wTree.get_widget("IconEntry").set_text(SetGconf(self.client,'string',self.gconf_dir+'/icon','system-search')) self.wTree.get_widget("StickyChkBtn").set_active(SetGconf(self.client,'bool',self.gconf_dir+'/sticky',False)) self.wTree.get_widget("MaximumNumberOfResultSpin1").set_value(SetGconf(self.client,'int', self.gconf_dir+'/max_number_of_search_result',10)) # Functions for Changing Values when items checked or altered Section def fontspin(self, widget, **kargs): self.client.set_int(self.gconf_dir+'/font_size',int(self.wTree.get_widget("FontSizeSpin").get_value())) def hspin(self, widget, **kargs): self.client.set_int(self.gconf_dir+'/height',int(self.wTree.get_widget("HSpin").get_value())) def wspin(self, widget, **kargs): self.client.set_int(self.gconf_dir+'/width',int(self.wTree.get_widget("WSpin").get_value())) def iconchange(self, widget, **kargs): self.icon=self.wTree.get_widget("IconEntry").get_text() self.client.set_string(self.gconf_dir+'/icon',self.wTree.get_widget('IconEntry').get_text()) def setsticky(self, widget, **kargs): result = self.wTree.get_widget("StickyChkBtn").get_active() == True self.client.set_bool(self.gconf_dir+'/sticky',result) def maxNumberOfResults(self, widget, **kargs): self.client.set_int(self.gconf_dir+'/max_number_of_search_result',int(self.wTree.get_widget("MaximumNumberOfResultSpin1").get_value()))