home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / pycentral / deskbar-applet / site-packages / deskbar / DeskbarApplet.py < prev    next >
Encoding:
Python Source  |  2006-08-29  |  12.6 KB  |  373 lines

  1. import os, time
  2. from os.path import *
  3. import gnomeapplet, gtk, gtk.gdk, gconf, gobject
  4. from gettext import gettext as _
  5.  
  6. import deskbar, deskbar.ui
  7. from deskbar.DeskbarHistory import get_deskbar_history
  8. from deskbar.ModuleList import ModuleList
  9. from deskbar.ModuleLoader import ModuleLoader
  10. from deskbar.ui.About import show_about
  11. from deskbar.ui.DeskbarPreferencesUI import show_preferences
  12. from deskbar.DeskbarAppletPreferences import DeskbarAppletPreferences
  13. from deskbar.Keybinder import get_deskbar_keybinder
  14. from deskbar.ui.cuemiac.CuemiacButtonUI import CuemiacButtonUI
  15. from deskbar.ui.entriac.CuemiacEntryUI import CuemiacEntryUI
  16. from deskbar.ui.window.CuemiacWindowUI import CuemiacWindowUI
  17.  
  18.  
  19. class DeskbarApplet:
  20.     def __init__(self, applet):
  21.         self.applet = applet
  22.         
  23.         self.start_query_id = 0
  24.             
  25.         self.prefs = DeskbarAppletPreferences(applet)
  26.         
  27.         self._inited_modules = 0
  28.         self._loaded_modules = 0
  29.         
  30.         self._match_hashes = {}
  31.         self.middle_click = None
  32.         
  33.         self.loader = ModuleLoader (deskbar.MODULES_DIRS)
  34.         self.loader.connect ("modules-loaded", self.on_modules_loaded)
  35.                 
  36.         self.module_list = ModuleList ()
  37.         self.loader.connect ("module-loaded", self.module_list.update_row_cb)
  38.         self.loader.connect ("module-initialized", self.module_list.module_toggled_cb)
  39.         self.loader.connect ("module-initialized", self.on_module_initialized)
  40.         self.loader.connect ("module-not-initialized", self.on_module_initialized)
  41.         self.loader.connect ("module-stopped", self.module_list.module_toggled_cb)
  42.         self.loader.connect ("module-initialized", self._connect_if_async)
  43.  
  44.         gtk.window_set_default_icon_name("deskbar-applet")
  45.  
  46.         self.minchars = deskbar.GCONF_CLIENT.get_int(self.prefs.GCONF_MINCHARS)
  47.         if self.minchars == None:
  48.             self.minchars = 1
  49.         deskbar.GCONF_CLIENT.notify_add(self.prefs.GCONF_MINCHARS, lambda x, y, z, a: self.on_minchars_changed (z.value))
  50.  
  51.         self.typingdelay = deskbar.GCONF_CLIENT.get_int(self.prefs.GCONF_TYPINGDELAY)
  52.         if self.typingdelay == None:
  53.             self.typingdelay = 250
  54.         deskbar.GCONF_CLIENT.notify_add(self.prefs.GCONF_TYPINGDELAY, lambda x, y, z, a: self.on_typingdelay_changed (z.value))
  55.  
  56.         self.clear_entry = deskbar.GCONF_CLIENT.get_bool(self.prefs.GCONF_CLEAR_ENTRY)
  57.         if self.clear_entry == None:
  58.             self.clear_entry = False
  59.         deskbar.GCONF_CLIENT.notify_add(self.prefs.GCONF_CLEAR_ENTRY, lambda x, y, z, a: self.on_clear_entry_changed (z.value))
  60.         
  61.         # Watch out for UI override from command line
  62.         if deskbar.UI_OVERRIDE:
  63.             ui_name = deskbar.UI_OVERRIDE
  64.             deskbar.GCONF_CLIENT.set_string(self.prefs.GCONF_UI_NAME, ui_name)
  65.         else:
  66.             # Set and retrieve the UI to be used
  67.             ui_name = deskbar.GCONF_CLIENT.get_string(self.prefs.GCONF_UI_NAME)
  68.             if ui_name == None:
  69.                 ui_name = deskbar.ENTRIAC_UI_NAME
  70.         
  71.         if ui_name == deskbar.CUEMIAC_UI_NAME:
  72.             self.ui = CuemiacButtonUI (applet, self.prefs)
  73.         elif ui_name == deskbar.ENTRIAC_UI_NAME:
  74.             self.ui = CuemiacEntryUI(applet, self.prefs)
  75.         elif ui_name == deskbar.WINDOW_UI_NAME:
  76.             self.ui = CuemiacWindowUI(applet, self.prefs)
  77.             self.ui.connect('show-preferences', self.on_preferences, None)
  78.             self.ui.connect('show-about', self.on_about, None)
  79.             self.ui.connect('clear-history', self.on_clear_history, None)
  80.         
  81.         # Set up the chosen UI
  82.         self.set_up_ui_signals ()
  83.         self.ui.set_sensitive (False)
  84.         self.applet.add(self.ui.get_view ())
  85.                 
  86.         deskbar.GCONF_CLIENT.notify_add (self.prefs.GCONF_UI_NAME, lambda x, y, z, a: self.on_ui_changed (z.value))
  87.         
  88.         # Set and retreive enabled handler list from gconf
  89.         deskbar.GCONF_CLIENT.notify_add(deskbar.GCONF_ENABLED_HANDLERS, lambda x, y, z, a: self.on_config_handlers(z.value))
  90.         
  91.         # Set and retreive use selection settings
  92.         self.use_selection = deskbar.GCONF_CLIENT.get_bool(self.prefs.GCONF_USE_SELECTION)
  93.         if self.use_selection == None:
  94.             self.use_selection = True
  95.         deskbar.GCONF_CLIENT.notify_add(self.prefs.GCONF_USE_SELECTION, lambda x, y, z, a: self.on_use_selection(z.value))        
  96.  
  97.         # Monitor global shortcut binding
  98.         get_deskbar_keybinder().connect('activated', self.on_keybinding_button_press)
  99.         
  100.         self.applet.connect("button-press-event", self.on_applet_button_press)
  101.         self.applet.connect("button-release-event", self.on_applet_button_release)
  102.         self.applet.connect('destroy', lambda x: get_deskbar_history().save())
  103.         self.applet.setup_menu_from_file (
  104.             deskbar.SHARED_DATA_DIR, "Deskbar_Applet.xml",
  105.             None, [
  106.             ("About", self.on_about),
  107.             ("Prefs", self.on_preferences),
  108.             ("Clear", self.on_clear_history),
  109.             ])
  110.         self.applet.show_all()
  111.         
  112.         self.loader.load_all_async()
  113.         
  114.     def _connect_if_async (self, sender, context):
  115.         if context.module.is_async():
  116.             context.module.connect ('query-ready', lambda sender, qstring, matches: self.dispatch_matches([(qstring, match) for match in matches]))    
  117.     
  118.     def on_match_selected (self, sender, text, match):
  119.         print "Match selected: ",match
  120.         self.on_stop_query()
  121.         match.action(text)
  122.         get_deskbar_history().add(text, match)
  123.         if self.clear_entry:
  124.             gobject.idle_add(self.clear_entry)
  125.     
  126.     def clear_entry(self):
  127.         entry = self.ui.get_entry()
  128.         if entry != None:
  129.             entry.set_text("")
  130.             
  131.     def on_start_query (self, sender, qstring):
  132.         if len(qstring) < self.minchars:
  133.             return
  134.         if self.start_query_id != 0:
  135.             gobject.source_remove(self.start_query_id)
  136.             
  137.         self.start_query_id = gobject.timeout_add(self.typingdelay, self.on_start_query_real, sender, qstring)
  138.         
  139.     def on_start_query_real (self, sender, qstring):
  140.         self._match_hashes = {}
  141.         results = []
  142.         for modctx in self.module_list:
  143.             if not modctx.enabled:
  144.                 continue
  145.             if modctx.module.is_async():
  146.                 modctx.module.query_async(qstring)
  147.             else:
  148.             
  149.                 try:
  150.                     matches = modctx.module.query(qstring)
  151.                 except TypeError:
  152.                     matches = modctx.module.query(qstring, deskbar.DEFAULT_RESULTS_PER_HANDLER)
  153.                     
  154.                 for match in matches:
  155.                     text, match = qstring, match
  156.                     if type(match) is tuple:
  157.                         text, match = match
  158.  
  159.                     hsh = match.get_hash(text)
  160.                     if hsh != None:
  161.                         if hsh in self._match_hashes:
  162.                             continue
  163.                             
  164.                         self._match_hashes[hsh] = True
  165.                         results.append((text,match))
  166.                     else:
  167.                         results.append((text,match))
  168.  
  169.         if len(results) != 0:
  170.             self.ui.append_matches (results)
  171.     
  172.     def dispatch_matches (self, matches):
  173.         results = []
  174.         for text, match in matches:
  175.             hsh = match.get_hash(text)
  176.             if hsh != None:
  177.                 if hsh in self._match_hashes:
  178.                     continue
  179.                     
  180.                 self._match_hashes[hsh] = True
  181.                 results.append((text,match))
  182.             else:
  183.                 results.append((text,match))
  184.                         
  185.         self.ui.append_matches (results)
  186.         
  187.     def on_stop_query (self, sender=None):
  188.         get_deskbar_history().reset()
  189.         if self.start_query_id != 0:
  190.             gobject.source_remove(self.start_query_id)
  191.                 
  192.         for modctx in self.module_list:
  193.             if modctx.module.is_async() and modctx.enabled:
  194.                 #print "DeskbarApplet: Stopping", modctx.module,"by", sender # DEBUG
  195.                 modctx.module.stop_query()
  196.                 
  197.     def on_request_keybinding (self, sender, match, keybinding):
  198.         print "keybind request:", match, keybinding
  199.         
  200.     def on_keyboard_shortcut (self, sender, qstring, shortcut):
  201.         for modctx in self.module_list:
  202.             if not modctx.enabled:
  203.                 continue
  204.                 
  205.             match = modctx.module.on_key_press(qstring, shortcut)
  206.             if match != None:
  207.                 self.on_match_selected(sender, qstring, match)
  208.                 break
  209.                     
  210.     def on_about (self, component, verb):
  211.         show_about()
  212.     
  213.     def on_preferences (self, component, verb):
  214.         show_preferences(self, self.loader, self.module_list)
  215.     
  216.     def on_clear_history (self, component, verb):
  217.         get_deskbar_history().clear()
  218.     
  219.     def on_config_handlers (self, value):
  220.         if value != None and value.type == gconf.VALUE_LIST:
  221.             enabled_modules = [h.get_string() for h in value.get_list()]
  222.             
  223.             # Stop all unneeded modules
  224.             for modctx in self.module_list:
  225.                 if modctx.enabled and not modctx.handler in enabled_modules:
  226.                     self.loader.stop_module (modctx)
  227.             
  228.             # Load all new modules            
  229.             self.update_modules_priority(enabled_modules, lambda modctx: self.loader.initialize_module_async(modctx))
  230.     
  231.     def update_modules_priority(self, enabled_modules, callback=None):
  232.         """
  233.         module_list is a module_loader.ModuleList() with loaded modules
  234.         enabled_modules is a list of exported classnames.
  235.         
  236.         Update the module priority present in both module_list and enabled_modules according
  237.         to the ordering of enabled_modules. Optionally calls callback when != None on each
  238.         module context, in the correct order (from important to less important)
  239.         """
  240.         # Compute the highest priority
  241.         high_prio = (len(enabled_modules)-1)*100
  242.         
  243.         # Now we enable each gconf-enabled handler, and set it's priority according to gconf ordering
  244.         for i, mod in enumerate(enabled_modules):
  245.             modctx = [modctx for modctx in self.module_list if modctx.handler == mod]
  246.             if len(modctx) != 1:
  247.                 # We have a gconf handler not on disk anymore..
  248.                 continue
  249.                 
  250.             modctx = modctx[0]
  251.             modctx.module.set_priority(high_prio-i*100)
  252.             
  253.             # Call the optional callback
  254.             if callback != None:
  255.                 callback(modctx)
  256.         
  257.         self.module_list.reorder_with_priority(enabled_modules)
  258.         
  259.     def on_modules_loaded(self, loader):
  260.         # Fetch the sorted handlers list from gconf
  261.         enabled_list = deskbar.GCONF_CLIENT.get_list(deskbar.GCONF_ENABLED_HANDLERS, gconf.VALUE_STRING)
  262.         
  263.         def foreach_enabled(modctx):
  264.             self.loader.initialize_module_async(modctx)
  265.             self._loaded_modules = self._loaded_modules + 1
  266.         
  267.         # Update live priorities
  268.         self.update_modules_priority(enabled_list, foreach_enabled)
  269.         
  270.         if self._loaded_modules == 0:
  271.             self.ui.set_sensitive (True)
  272.         
  273.     def on_module_initialized(self, loader, modctx):
  274.         self._inited_modules = self._inited_modules + 1
  275.         if self._inited_modules == self._loaded_modules:
  276.             self.ui.set_sensitive (True)
  277.             get_deskbar_history().load(self.module_list)
  278.                             
  279.     def on_applet_button_press(self, widget, event):
  280.         # Left-Mouse-Button should focus the GtkEntry widget (for Fitt's Law
  281.         # - so that a click on applet border on edge of screen activates the
  282.         # most important widget).
  283.         if event.button == 1:
  284.             self.ui.receive_focus(event.time)
  285.             return True
  286.         
  287.         # Middle click handling, we need this in the cuemiac
  288.         if event.button == 2:
  289.             self.middle_click = (event.x_root, event.y_root)
  290.             
  291.         return False
  292.     
  293.     def on_applet_button_release(self, widget, event):
  294.         if event.button == 2:
  295.             x, y = self.middle_click
  296.             diffx, diffy = abs(x-event.x_root), abs(y-event.y_root)
  297.             if diffx <= 3 and diffy <=3:
  298.                 self.ui.middle_click()
  299.             
  300.             self.middle_click = None
  301.             
  302.     def on_keybinding_button_press(self, widget, time):
  303.         print 'Keybinding activated, focusing UI'
  304.         if self.use_selection:
  305.             clipboard = gtk.clipboard_get(selection="PRIMARY")
  306.             text = clipboard.wait_for_text()
  307.             if text:
  308.                 self.ui.get_entry().set_text(text)
  309.                 
  310.         self.ui.receive_focus(time)
  311.         self.ui.get_entry().select_region(0, -1)
  312.         
  313.     def on_history_item_selection (self, item, match, text):
  314.         pass
  315.             
  316.     def on_keybinding_changed(self, binder, bound):
  317.         # FIXME: provide visual clue when not bound
  318.         # FIXME: should be used in the pref window
  319.         pass
  320.  
  321.     def set_up_ui_signals (self):
  322.         self.ui.connect ("match-selected", self.on_match_selected)
  323.         self.ui.connect ("start-query", self.on_start_query)
  324.         self.ui.connect ("stop-query", self.on_stop_query)
  325.         self.ui.connect ("request-keybinding", self.on_request_keybinding)
  326.         self.ui.connect ("keyboard-shortcut", self.on_keyboard_shortcut)
  327.         self.applet.connect('change-orient', lambda applet, orient: self.ui.on_change_orient(applet))
  328.         self.applet.connect('change-size', lambda applet, orient: self.ui.on_change_size(applet))
  329.  
  330.     def on_minchars_changed (self, value):
  331.         if value is None or value.type != gconf.VALUE_INT:
  332.             return
  333.         self.minchars = value.get_int()
  334.     
  335.     def on_typingdelay_changed (self, value):
  336.         if value is None or value.type != gconf.VALUE_INT:
  337.             return
  338.         self.typingdelay = value.get_int()
  339.  
  340.     def on_ui_changed (self, value):
  341.         if value is None or value.type != gconf.VALUE_STRING:
  342.             return
  343.         
  344.         ui_name = value.get_string()
  345.         if ui_name == deskbar.WINDOW_UI_NAME:
  346.             # You cannot switch to or from a window ui
  347.             return
  348.  
  349.         self.ui.close_view()
  350.         self.applet.remove (self.ui.get_view())
  351.         #FIXME: Should we clean up signals and stuff on the old UI?
  352.  
  353.         if ui_name == deskbar.CUEMIAC_UI_NAME:
  354.             self.ui = CuemiacButtonUI (self.applet, self.prefs)
  355.         elif ui_name == deskbar.ENTRIAC_UI_NAME:
  356.             self.ui = CuemiacEntryUI(self.applet, self.prefs)
  357.         
  358.         self.set_up_ui_signals ()
  359.         self.applet.add (self.ui.get_view())
  360.         self.applet.show_all ()
  361.         self.ui.set_sensitive(True)
  362.         print "Changing UI to:", value.get_string ()
  363.  
  364.     def on_clear_entry_changed(self, value):
  365.         if value is None or value.type != gconf.VALUE_BOOL:
  366.             return
  367.         self.clear_entry = value.get_bool()
  368.     
  369.     def on_use_selection(self, value=None):
  370.         if value != None and value.type == gconf.VALUE_BOOL:
  371.             self.use_selection = value.get_bool()
  372.     
  373.