bigboard r7397 - in trunk/bigboard: . core libgmail libgmail/ClientCookie stocks/files stocks/people stocks/self



Author: otaylor
Date: Mon Jun 23 21:48:48 2008
New Revision: 7397
URL: http://svn.gnome.org/viewvc/bigboard?rev=7397&view=rev

Log:
Shuffle code around:
 Rename Exchange => StockHolder, move to a separate file
 Rename StockManager => Exchange, move to a separate file
 Rename BigBoardPanel => Panel, move to a separate file
 Don't shell out to xdg-user-dir, use g_get_user_special_dir() 
  [bignative addition, not bound in pygobject]


Added:
   trunk/bigboard/core/   (props changed)
   trunk/bigboard/core/__init__.py
   trunk/bigboard/core/exchange.py
   trunk/bigboard/core/panel.py
   trunk/bigboard/core/stock_holder.py
Modified:
   trunk/bigboard/bigboard-native.c
   trunk/bigboard/bigboard-native.h
   trunk/bigboard/bignative.c
   trunk/bigboard/global_mugshot.py
   trunk/bigboard/globals.py
   trunk/bigboard/libgmail/   (props changed)
   trunk/bigboard/libgmail/ClientCookie/   (props changed)
   trunk/bigboard/stocks/files/FilesStock.py
   trunk/bigboard/stocks/files/filebrowser.py
   trunk/bigboard/stocks/people/peoplewidgets.py
   trunk/bigboard/stocks/self/portfoliomanager.py

Modified: trunk/bigboard/bigboard-native.c
==============================================================================
--- trunk/bigboard/bigboard-native.c	(original)
+++ trunk/bigboard/bigboard-native.c	Mon Jun 23 21:48:48 2008
@@ -154,3 +154,17 @@
     return result;
 }
 
+PyObject*
+bigboard_get_desktop_dir(PyObject *self, PyObject *args)
+{
+    PyObject *result = NULL;
+    
+    if (PyArg_ParseTuple(args, ":bigboard_get_desktop_dir")) {
+        const char *desktop_dir = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
+
+        result = PyString_FromString(desktop_dir);
+    }
+    
+    return result;
+}
+

Modified: trunk/bigboard/bigboard-native.h
==============================================================================
--- trunk/bigboard/bigboard-native.h	(original)
+++ trunk/bigboard/bigboard-native.h	Mon Jun 23 21:48:48 2008
@@ -12,7 +12,7 @@
 PyObject*  bigboard_set_program_name                    (PyObject *self, PyObject *args);
 PyObject*  bigboard_install_focus_docks_hack            (PyObject *self, PyObject *args);
 PyObject*  bigboard_utf8_collate                        (PyObject *self, PyObject *args);
-
+PyObject*  bigboard_get_desktop_dir                     (PyObject *self, PyObject *args);
 G_END_DECLS
 
 #endif /* __BIGBOARD_NATIVE_H__ */

Modified: trunk/bigboard/bignative.c
==============================================================================
--- trunk/bigboard/bignative.c	(original)
+++ trunk/bigboard/bignative.c	Mon Jun 23 21:48:48 2008
@@ -22,6 +22,8 @@
      "Focus dock windows when clicking focusable widgets in them."},    
     {"utf8_collate", (PyCFunction) bigboard_utf8_collate, METH_VARARGS,
      "Compare strings in lexical order."},
+    {"get_desktop_dir", (PyCFunction) bigboard_get_desktop_dir, METH_VARARGS,
+     "Get the user desktop directory."},
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 

Added: trunk/bigboard/core/__init__.py
==============================================================================

Added: trunk/bigboard/core/exchange.py
==============================================================================
--- (empty file)
+++ trunk/bigboard/core/exchange.py	Mon Jun 23 21:48:48 2008
@@ -0,0 +1,173 @@
+import logging
+import os
+import sys
+import urllib2
+import urlparse
+
+import gconf
+import gobject
+import pyonlinedesktop
+import pyonlinedesktop.widget
+
+import bigboard
+from bigboard.globals import GCONF_PREFIX
+from bigboard.libbig.gutil import *
+
+from stock_holder import StockHolder
+
+_logger = logging.getLogger("bigboard.Exchange")
+
+class Exchange(gobject.GObject):
+    __gsignals__ = {
+        "listings-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
+    }    
+    def __init__(self, hardcoded_urls):
+        super(Exchange, self).__init__()
+        self.__stockdir = os.path.join(os.path.dirname(bigboard.__file__), 'stocks')
+        self.__widget_environ = widget_environ = pyonlinedesktop.widget.WidgetEnvironment()
+        widget_environ['google_apps_auth_path'] = ''
+        self.__listing_key = GCONF_PREFIX + 'url_listings'
+        gconf.client_get_default().notify_add(self.__listing_key, self.__on_listings_change)
+        self.__metainfo_cache = {}   
+        self.__hardcoded_urls = hardcoded_urls                        
+
+    def set_listed(self, url, dolist):
+        curlist = list(self.get_listed_urls())
+        if (url in curlist) and dolist:
+            _logger.debug("attempting to list currently listed stock %s", url)
+            return
+        elif (url not in curlist) and (not dolist):
+            _logger.debug("attempting to delist currently unlisted stock %s", url)            
+            return
+        elif dolist:
+            _logger.debug("listing %s", url)              
+            curlist.append(url)
+        elif not dolist:
+            _logger.debug("delisting %s", url)               
+            curlist.remove(url)
+        gconf.client_get_default().set_list(self.__listing_key, gconf.VALUE_STRING, curlist)                        
+
+    def move_listing(self, url, isup):
+        curlist = list(self.get_listed_urls())
+        curlen = len(curlist)
+        pos = curlist.index(url)
+        if pos < 0:
+            _logger.debug("couldn't find url in listings: %s", url)
+            return
+        if isup and pos == 0:
+            return
+        elif (not isup) and pos == (curlen-1):
+            return
+        del curlist[pos]        
+        pos += (isup and -1 or 1)
+        curlist.insert(pos, url)
+        gconf.client_get_default().set_list(self.__listing_key, gconf.VALUE_STRING, curlist)        
+
+    def get_all_builtin_urls(self):
+        for fname in os.listdir(self.__stockdir):
+            fpath = os.path.join(self.__stockdir, fname)
+            if fpath.endswith('.xml'):
+                url = 'builtin://' + fname
+                if url not in self.__hardcoded_urls:
+                    yield url
+            
+    def get_hardcoded_urls(self):
+        return self.__hardcoded_urls
+            
+    def get_all_builtin_metadata(self):
+        for url in self.get_all_builtin_urls():
+            yield self.load_metainfo(url)
+            
+    def get_listed_urls(self):
+        for url in gconf.client_get_default().get_list(self.__listing_key, gconf.VALUE_STRING):
+            if url not in self.__hardcoded_urls:
+                yield url
+    
+    def get_listed(self):
+        for url in self.get_listed_urls():
+            yield self.load_metainfo(url)        
+
+    def load_metainfo(self, url):
+        try:
+            return self.__metainfo_cache[url]
+        except KeyError, e:
+            pass        
+        _logger.debug("loading stock url %s", url)
+        builtin_scheme = 'builtin://'
+        srcurl = url
+        if url.startswith(builtin_scheme):
+            srcurl = 'file://' + os.path.join(self.__stockdir, url[len(builtin_scheme):])
+            baseurl = 'file://' + self.__get_moddir_for_builtin(url)
+        else:
+            baseurl = os.path.dirname(url)
+        try:
+            metainfo = pyonlinedesktop.widget.WidgetParser(url, urllib2.urlopen(srcurl), self.__widget_environ, baseurl=baseurl)
+            ## FIXME this is a hack - we need to move async processing into StockHolder probably
+            url_contents = {}
+            for url in metainfo.get_required_urls():
+                url_contents[url] = urllib2.urlopen(url).read()
+            metainfo.process_urls(url_contents)
+        except urllib2.HTTPError, e:
+            _logger.warn("Failed to load %s", url, exc_info=True)
+            
+        self.__metainfo_cache[url] = metainfo
+        return metainfo 
+    
+    def render(self, module, **kwargs):
+        (content_type, content_data) = module.content
+        pymodule = None
+        if content_type == 'online-desktop-builtin':
+            pymodule = self.__load_builtin(module, **kwargs)
+            if not pymodule: 
+                return None
+
+        stylesheet = os.path.join(self.__get_moddir_for_builtin(module.srcurl), 'stock.css')
+        if not os.path.exists(stylesheet):
+            stylesheet = None
+
+        return StockHolder(module, self.__widget_environ, pymodule=pymodule,
+                           is_notitle=(module.srcurl in self.__hardcoded_urls),
+                           panel=kwargs['panel'], stylesheet=stylesheet)
+        
+    def render_url(self, url, **kwargs):
+        return self.render(self.load_metainfo(url), **kwargs)
+        
+    def __get_moddir_for_builtin(self, url):
+        modpath = urlparse.urlparse(url).path
+        modfile = os.path.basename(modpath)
+        dirname = modfile[:modfile.rfind('.')]
+        return os.path.join(self.__stockdir, dirname) + "/"
+                
+    def __load_builtin(self, metainfo, notitle=False, panel=None):
+        dirpath = self.__get_moddir_for_builtin(metainfo.srcurl)
+        modpath = urlparse.urlparse(metainfo.srcurl).path
+        modfile = os.path.basename(modpath)
+        dirname = modfile[:modfile.rfind('.')]        
+        _logger.debug("appending to path: %s", dirpath)
+        sys.path.append(dirpath)
+        pfxidx = modfile.find('_')
+        if pfxidx >= 0:
+            classname = dirname[pfxidx+1:]
+        else:
+            classname = dirname
+        classname = classname[0].upper() + classname[1:] + 'Stock'
+        try:
+            _logger.info("importing module %s (title: %s) from dir %s", classname, metainfo.title, dirpath)
+            pymodule = __import__(classname)
+            class_constructor = getattr(pymodule, classname)
+            _logger.debug("got constructor %s", class_constructor)
+            if notitle:
+                title = ''
+            else:
+                title = metainfo.title
+            stock = class_constructor(metainfo, title=title, panel=panel)
+
+            return stock                  
+        except:
+            _logger.exception("failed to add stock %s", classname)
+            return None
+                
+    @defer_idle_func(timeout=100)     
+    def __on_listings_change(self, *args):
+        _logger.debug("processing listings change")
+        self.emit("listings-changed")

Added: trunk/bigboard/core/panel.py
==============================================================================
--- (empty file)
+++ trunk/bigboard/core/panel.py	Mon Jun 23 21:48:48 2008
@@ -0,0 +1,473 @@
+import logging
+import os
+
+import dbus
+import gconf
+import gobject
+import gtk
+import hippo
+
+from bigboard.big_widgets import Button, Header, Sidebar, ThemeManager
+from bigboard.globals import BUS_NAME_STR, GCONF_PREFIX
+from bigboard.libbig.gutil import *
+import bigboard.keybinder
+from bigboard.libbig.logutil import log_except
+from bigboard.stock import Stock
+
+from exchange import Exchange
+
+_logger = logging.getLogger("bigboard.Panel")
+
+BUS_IFACE=BUS_NAME_STR
+BUS_IFACE_PANEL=BUS_IFACE + ".Panel"
+
+class FirstTimeMinimizeDialog(gtk.Dialog):
+    __gsignals__ = { 'response' : 'override' }
+
+    def __init__(self, show_windows):
+        super(FirstTimeMinimizeDialog, self).__init__("Minimizing Sidebar",
+                                                      None,
+                                                      gtk.DIALOG_MODAL,
+                                                      ('Undo', gtk.RESPONSE_CANCEL,
+                                                       gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+        self.set_has_separator(False)
+        hbox = gtk.HBox(spacing=8)
+        self.vbox.add(hbox)
+        if show_windows:
+            img_filename = 'windows_key.png'
+        else:
+            img_filename = 'ctrl_esc_keys.png'
+        img_filename = bigboard.globals.find_in_datadir(img_filename)
+        _logger.debug("using img %s", img_filename)            
+        img = gtk.Image()
+        img.set_from_file(img_filename)
+        hbox.add(img)
+        hbox.add(gtk.Label('''The sidebar is now hidden; press the key shown on the left or the panel button to pop it
+back up temporarily.'''))
+        
+    def do_response(self, id):
+        if id != gtk.RESPONSE_CANCEL:
+            gconf.client_get_default().set_bool(GCONF_PREFIX + 'first_time_minimize_seen', True)
+        else:
+            # Avoid set of same value on notify receipt
+            gobject.timeout_add(100, self.__idle_undo_visible)
+        self.destroy()
+        
+    def __idle_undo_visible(self):
+        gconf.client_get_default().set_bool(GCONF_PREFIX + 'visible', True)
+        return False        
+    
+class Panel(dbus.service.Object):
+    def __init__(self, bus_name):
+        dbus.service.Object.__init__(self, bus_name, '/bigboard/panel')
+          
+        _logger.info("constructing")
+                
+        self.__popped_out = False
+        self.__shell = None
+        
+        gconf_client = gconf.client_get_default()
+        self._dw = Sidebar(GCONF_PREFIX + 'visible')
+        gconf_client.notify_add(GCONF_PREFIX + 'orientation', self.__sync_orient)        
+        self.__sync_orient()            
+
+        self.__keybinding = gconf_client.get_string('/apps/bigboard/focus_key')
+        if self.__keybinding:
+            bigboard.keybinder.tomboy_keybinder_bind(self.__keybinding, self.__on_focus)
+    
+        self.__autohide_id = 0
+        
+        self._holders = {} ## metainfo.srcurl to StockHolder
+
+        self._canvas = canvas = hippo.Canvas()
+        self._dw.get_content().add(self._canvas)
+        
+        self._main_box = hippo.CanvasBox(border_right=1, border_color=0x999999FF, padding_bottom=4)
+        self._canvas.set_root(self._main_box)
+
+        self._header_box = Header()
+        self._header_box.connect("button-press-event", self.__on_header_buttonpress)             
+
+        self.__unpopout_button = Button(label='Hide', label_ypadding=-2)
+        self.__unpopout_button.set_property('yalign', hippo.ALIGNMENT_CENTER)
+        self.__unpopout_button.connect("activated", lambda button: self.__do_unpopout())
+        self._header_box.append(self.__unpopout_button, hippo.PACK_END)
+     
+        self._title = hippo.CanvasText(classes='header', text="My Desktop", font="Bold", xalign=hippo.ALIGNMENT_START, padding_left=8)
+     
+        self._header_box.append(self._title, hippo.PACK_EXPAND)
+        
+        self._size_button = None
+        
+        self._main_box.append(self._header_box)
+        
+        self._stocks_box = hippo.CanvasBox(spacing=4)
+        
+        self._main_box.append(self._stocks_box)
+        
+        self.__theme_mgr = ThemeManager.getInstance()
+        self.__theme_mgr.connect('theme-changed', self.__sync_theme)
+        self.__sync_theme()    
+
+        self._canvas.get_context().connect('style-changed', self.__sync_opacity)
+        self.__sync_opacity()
+        
+        gconf_client.notify_add(GCONF_PREFIX + 'expand', self._sync_size)
+        self._sync_size()
+        
+        try:
+            self.__screensaver_proxy = dbus.SessionBus().get_object('org.gnome.ScreenSaver', '/org/gnome/ScreenSaver')
+            self.__screensaver_proxy.connect_to_signal('SessionIdleChanged',
+                                                       self.__on_session_idle_changed)
+        except dbus.DBusException, e:
+            _logger.warn("Couldn't find screensaver")
+            pass
+        
+        self.__exchange = Exchange(['builtin://self.xml', 'builtin://search.xml'])
+        self.__exchange.connect("listings-changed", lambda *args: self.__sync_listing())
+        
+        # These are hardcoded as it isn't really sensible to remove them
+        self.__hardcoded_stocks = self.__exchange.get_hardcoded_urls()
+        hardcoded_metas = map(lambda url: self.__exchange.load_metainfo(url), self.__hardcoded_stocks)
+        for metainfo in hardcoded_metas:
+            self.__append_metainfo(metainfo, notitle=True)    
+        self.__self_stock = self._holders[self.__hardcoded_stocks[0]].get_pymodule()
+        self.__search_stock = self._holders[self.__hardcoded_stocks[1]].get_pymodule()
+        gobject.idle_add(self.__sync_listing)
+
+        if self.__self_stock.info_loaded:
+            self.__initial_appearance()
+        else:
+            self.__self_stock.connect('info-loaded', lambda *args: self.__initial_appearance())
+
+        ## visible=True means we never hide, visible=False means we "autohide" and popout
+        ## when the hotkey or applet is used
+        gconf_client.notify_add(GCONF_PREFIX + 'visible', self.__sync_visible_mode)
+        self.__sync_visible_mode()
+        
+    @log_except(_logger)
+    def __initial_appearance(self):
+        ## This function is where we show the canvas internally; we only want this to 
+        ## happen after we've loaded information intially to avoid showing a partially-loaded
+        ## state.
+        self._canvas.show() 
+        self.__queue_strut()
+        self.__idle_show_we_exist()
+        
+    @log_except()
+    def __on_session_idle_changed(self, isidle):
+        if not isidle:
+            self.__idle_show_we_exist()
+
+    def __on_header_buttonpress(self, box, e):
+        _logger.debug("got shell header click: %s %s %s", e, e.button, e.modifiers)
+        if e.button == 2:
+            self.Shell()
+
+    @log_except()
+    def __idle_show_we_exist(self):
+        _logger.debug("showing we exist")
+        self.__enter_popped_out_state()
+        self.__leave_popped_out_state()
+
+    @log_except()
+    def __on_focus(self):
+        _logger.debug("got focus keypress")
+        vis = gconf.client_get_default().get_bool(GCONF_PREFIX + 'visible')
+        ts = bigboard.keybinder.tomboy_keybinder_get_current_event_time()
+        if vis:
+            self.__do_focus_search(ts)
+        else:
+            self.toggle_popout(ts)
+
+    def __append_metainfo(self, metainfo, **kwargs):
+        try:
+            exchange = self._holders[metainfo.srcurl]
+        except KeyError, e:
+            exchange = self.__exchange.render(metainfo, panel=self, **kwargs)
+            _logger.debug("rendered %s: %s", metainfo.srcurl, exchange)
+            if exchange:
+                self._holders[metainfo.srcurl] = exchange
+        if not exchange:
+            _logger.debug("failed to load stock from %s", metainfo.srcurl)
+            return
+        _logger.debug("adding stock %s", exchange)
+        self._stocks_box.append(exchange)
+        
+    @log_except(_logger)
+    def __sync_listing(self):
+        _logger.debug("doing stock listing sync")
+        new_listed = list(self.__exchange.get_listed())
+        new_listed_srcurls = map(lambda mi: mi.srcurl, new_listed)
+        for exchange in list(self._stocks_box.get_children()):
+            if exchange.get_metainfo().srcurl in self.__hardcoded_stocks:
+                continue
+
+            _logger.debug("unrendering %s", exchange)
+            
+            self._stocks_box.remove(exchange)
+
+            if exchange.get_metainfo().srcurl not in new_listed_srcurls:
+                _logger.debug("removing %s", exchange)                
+                del self._holders[exchange.get_metainfo().srcurl]
+                exchange.on_delisted()
+            
+        for metainfo in new_listed:
+            self.__append_metainfo(metainfo)
+        _logger.debug("done with stock load")            
+        
+    def get_exchange(self):
+        return self.__exchange
+        
+    def __get_size(self):
+        return Stock.SIZE_BULL
+
+    ## If the user performs an action such as launching an app,
+    ## that should close a popped-out sidebar, call this
+    def action_taken(self):
+        _logger.debug("action taken")
+        self.__leave_popped_out_state(immediate=True)
+        
+    @log_except()
+    def __sync_orient(self, *args):
+        orient = gconf.client_get_default().get_string(GCONF_PREFIX + 'orientation')
+        if not orient:
+            orient = 'west'
+        if orient.lower() == 'west':
+            gravity = gtk.gdk.GRAVITY_WEST
+        else:
+            gravity = gtk.gdk.GRAVITY_EAST
+        self._dw.set_gravity(gravity)
+        self.__queue_strut()
+        
+    @log_except()
+    def _toggle_size(self):
+        _logger.debug("toggling size")
+        expanded = gconf.client_get_default().get_bool(GCONF_PREFIX + 'expand')
+        gconf.client_get_default().set_bool(GCONF_PREFIX + 'expand', not expanded)
+            
+    def _sync_size(self, *args):
+        # This function should be deleted basically; we no longer support size changes.
+                   
+        self._canvas.set_size_request(Stock.SIZE_BULL_CONTENT_PX, 42)
+        
+        _logger.debug("queuing resize")
+        self._dw.queue_resize()  
+        _logger.debug("queuing strut")
+        self.__queue_strut()
+        _logger.debug("queuing strut complete")
+        
+    def __sync_theme(self, *args):
+        theme = self.__theme_mgr.get_theme()
+        self._canvas.set_theme(theme)
+
+    def __sync_opacity(self, *args):
+        style = self._canvas.get_context().get_style()
+        opacity = style.get_double('opacity', False)
+        if opacity == None:
+            opacity = 1.0
+
+        self._dw.set_opacity(opacity)
+
+    @log_except()
+    def __idle_do_strut(self):
+        _logger.debug("setting strut in idle")
+        self._dw.do_set_wm_strut()
+        return False
+
+    def __queue_strut(self):
+        # TODO - this is kind of gross; we need the strut change to happen after
+        # the resize, but that appears to be an ultra-low priority internally
+        # so we can't easily queue something directly after.
+        call_timeout_once(250, self.__idle_do_strut)
+        
+    ## There are two aspects to the sidebar state:
+    ## the "visible" gconf key is like the old gnome-panel "autohide"
+    ## preference. i.e. if !visible, the sidebar is normally collapsed
+    ## and you have to use a hotkey or the applet to pop it out.
+    ## So the second piece of state is self.__popped_out, which is whether
+    ## the sidebar is currently popped out. If visible=True, the sidebar
+    ## is always popped out, i.e. self.__popped_out should be True always.
+
+    def __notify_stocks_of_popped_out(self):
+        for e in self._holders.values():
+            e.on_popped_out_changed(self.__popped_out)
+
+    ## Shows the sidebar
+    def __enter_popped_out_state(self):
+        if not self.__popped_out:
+            _logger.debug("popping out")
+
+            self._dw.show()
+            # we would prefer to need this, if iconify() worked on dock windows
+            #self._dw.deiconify()
+            self.__queue_strut()
+            self.__popped_out = True
+
+            self.__notify_stocks_of_popped_out()
+
+            self.EmitPoppedOutChanged()
+
+    ## Hides the sidebar, possibly after a delay, only if visible mode is False
+    def __leave_popped_out_state(self, immediate=False):
+        vis = gconf.client_get_default().get_bool(GCONF_PREFIX + 'visible')
+        if self.__popped_out and not vis and self.__autohide_id == 0:
+            _logger.debug("enqueued autohide timeout")            
+            self.__autohide_id = gobject.timeout_add(immediate and 1 or 1500, self.__idle_do_hide) 
+            
+    @log_except()
+    def __idle_do_hide(self):
+        _logger.debug("in idle hide")
+        self.__autohide_id = 0
+        vis = gconf.client_get_default().get_bool(GCONF_PREFIX + 'visible')
+        if vis or not self.__popped_out:
+            return  
+
+        _logger.debug("unpopping out")
+        self.__popped_out = False
+        ## would be better to iconify, not hide - hide withdraws the
+        ## window, iconify should leave bigboard in the Ctrl+Alt+Tab
+        ## order.
+        ## Unfortunately, it appears metacity disallows minimize on
+        ## dock windows.
+        #self._dw.iconify()
+        self._dw.hide()
+        self.__queue_strut()
+
+        self.__notify_stocks_of_popped_out()        
+
+        self.EmitPoppedOutChanged()
+
+    ## syncs our current state to a change in the gconf setting for visible mode
+    @log_except()
+    def __sync_visible_mode(self, *args):
+        ## unpopout button is only visible if unpopout is allowed
+        vis = gconf.client_get_default().get_bool(GCONF_PREFIX + 'visible')
+        self.__unpopout_button.set_visible(not vis)
+        
+        if vis and not self.__popped_out:
+            self.__enter_popped_out_state()
+        elif not vis:
+            self.__leave_popped_out_state()
+            if not gconf.client_get_default().get_bool(GCONF_PREFIX + 'first_time_minimize_seen'):
+                dialog = FirstTimeMinimizeDialog(True)
+                dialog.show_all()
+
+        ## this is needed because the Sidebar widget knows about the 'visible' gconf key,
+        ## and if we're not in visible mode (in autohide mode), it never sets the strut.
+        ## However the Sidebar widget does not itself listen for changes on the gconf key.
+        self.__queue_strut()
+        
+    ## Pops out the sidebar, and focuses it (if the sidebar is in visible mode, only has to focus)
+    def __do_popout(self, xtimestamp):
+        if not self.__popped_out:
+            _logger.debug("popout requested")
+            self.__enter_popped_out_state()
+        self.__do_focus_search(xtimestamp)
+            
+    def __do_focus_search(self, xtimestamp):
+        ## focus even if we were already shown
+        _logger.debug("presenting with ts %s", xtimestamp)
+        self._dw.present_with_time(xtimestamp)
+        self.__search_stock.focus()
+
+    ## Hides the sidebar, only if not in visible mode
+    def __do_unpopout(self):
+        if self.__popped_out:
+            _logger.debug("unpopout requested")
+            self.__leave_popped_out_state(True)
+
+    def toggle_popout(self, xtimestamp):
+        if self.__popped_out:
+            self.__do_unpopout()
+        else:
+            self.__do_popout(xtimestamp)
+
+    def __set_visible_mode(self, setting):
+        vis = gconf.client_get_default().get_bool(GCONF_PREFIX + 'visible')
+        if setting != vis:
+            gconf.client_get_default().set_bool(GCONF_PREFIX + 'visible', setting)
+
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def EmitPoppedOutChanged(self):
+        _logger.debug("got emitPoppedOutChanged method call")        
+        self.PoppedOutChanged(self.__popped_out)
+        
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Popout(self, xtimestamp):
+        _logger.debug("got popout method call")
+        return self.__do_popout(xtimestamp)
+
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Unpopout(self):
+        _logger.debug("got unpopout method call")
+
+        ## force us into autohide mode, since otherwise unpopout would not make sense
+        self.__set_visible_mode(False)
+
+        return self.__do_unpopout()
+
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Reboot(self):
+        import subprocess
+
+        reexec_cmd = os.getenv('BB_REEXEC') or '/usr/bin/bigboard'
+        reexec_cmd = os.path.abspath(REEXEC_CMD)
+        
+        args = [reexec_cmd]
+        args.extend(sys.argv[1:])
+        if not '--replace' in args:
+            args.append('--replace')
+        _logger.debug("Got Reboot, executing %s", args)
+        subprocess.Popen(args)
+
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Logout(self):
+        master = gnome.ui.master_client()
+        master.request_save(gnome.ui.SAVE_GLOBAL,
+                            True,
+                            gnome.ui.INTERACT_ANY,
+                            False,
+                            True)
+
+
+    def __create_scratch_window(self):
+        w = hippo.CanvasWindow(gtk.WINDOW_TOPLEVEL)
+        w.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(65535,65535,65535))
+        w.set_title('Scratch Window')
+        box = CanvasVBox()
+        w.set_root(box)
+        w.connect('delete-event', lambda *args: w.destroy())
+        w.show_all()
+        w.present_with_time(gtk.get_current_event_time())
+        return box
+
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Shell(self):
+        if self.__shell:
+            self.__shell.destroy()
+        import bigboard.pyshell
+        self.__shell = bigboard.pyshell.CommandShell({'panel': self,
+                                     '               scratch_window': self.__create_scratch_window},
+                                                     savepath=os.path.expanduser('~/.bigboard/pyshell.py'))
+        self.__shell.show_all()
+        self.__shell.present_with_time(gtk.get_current_event_time())
+        
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Kill(self):
+        try:
+            bigboard.keybinder.tomboy_keybinder_unbind(self.__keybinding)
+        except KeyError, e:
+            pass   
+        # This is a timeout so we reply to the method call
+        gobject.timeout_add(100, gtk.main_quit)
+        
+    @dbus.service.method(BUS_IFACE_PANEL)
+    def Exit(self):
+        gtk.main_quit()
+
+    @dbus.service.signal(BUS_IFACE_PANEL,
+                         signature='b')
+    def PoppedOutChanged(self, is_popped_out):
+        pass
+

Added: trunk/bigboard/core/stock_holder.py
==============================================================================
--- (empty file)
+++ trunk/bigboard/core/stock_holder.py	Mon Jun 23 21:48:48 2008
@@ -0,0 +1,151 @@
+import gobject
+import hippo
+
+from bigboard.big_widgets import Arrow, Header, ThemeManager
+from bigboard.stock import Stock
+
+class GoogleGadgetContainer(hippo.CanvasWidget):
+    def __init__(self, metainfo, env):
+        super(GoogleGadgetContainer, self).__init__()
+        from pyonlinedesktop import ggadget        
+        self.widget = ggadget.Gadget(metainfo, env)
+        self.widget.show_all() 
+        self.set_property('widget', self.widget)
+
+class HeaderButton(hippo.CanvasBox):
+    def __init__(self):
+        hippo.CanvasBox.__init__(self, box_width=40, xalign=hippo.ALIGNMENT_END,
+                                 background_color=0x00000001)
+        self.set_clickable(True)
+        self.append(hippo.CanvasText(text=" "))
+
+    def do_paint_below_children(self, cr, dmgbox):
+        area = self.get_background_area()
+        self.get_style().paint(cr, 'more-button', area.x, area.y, area.width, area.height)
+        
+gobject.type_register(HeaderButton)
+         
+class Separator(hippo.CanvasBox):
+    def __init__(self):
+        hippo.CanvasBox.__init__(self, border_top=1, border_color=0x999999FF)
+        
+class StockHolder(hippo.CanvasBox):
+    """A renderer for stocks."""
+    
+    def __init__(self, metainfo, env, pymodule=None, is_notitle=False, panel=None, stylesheet=None):
+        hippo.CanvasBox.__init__(self,  
+                                 orientation=hippo.ORIENTATION_VERTICAL,
+                                 spacing=4)
+        self.__size = None
+        self.__metainfo = metainfo
+        self.__env = env
+        self.__pymodule = pymodule
+        self.__panel = panel
+        self.__stylesheet = stylesheet
+        self.__content = None
+        self.__ticker_text = None
+        self.__ticker_container = None
+        self.__mini_more_button = None
+        self.__sep = Separator()
+        self.append(self.__sep)
+        self.__expanded = True
+        if not is_notitle:
+            self.__ticker_container = Header()
+            self.__ticker_text = hippo.CanvasText(classes='header', text=metainfo.title, xalign=hippo.ALIGNMENT_START)
+            self.__ticker_text.set_clickable(True)
+            self.__ticker_text.connect("activated", lambda text: self.__toggle_expanded())  
+            self.__ticker_container.append(self.__ticker_text, hippo.PACK_EXPAND)
+
+            self.__ticker_arrow = Arrow(Arrow.LEFT, padding=4)
+            self.__ticker_arrow.connect("activated", lambda text: self.__toggle_expanded())
+            self.__ticker_container.append(self.__ticker_arrow)
+            
+            if pymodule and pymodule.has_more_button():
+                more_button = HeaderButton()
+                more_button.connect("activated", lambda l: pymodule.on_more_clicked())
+                self.__ticker_container.append(more_button)
+            
+            self.append(self.__ticker_container)
+
+        self.__theme_mgr = ThemeManager.getInstance()
+        self.__theme_mgr.connect('theme-changed', self.__sync_theme)
+
+        self.__stockbox = hippo.CanvasBox()
+        self.append(self.__stockbox)
+        if pymodule:
+            pymodule.connect('visible', self.__render_pymodule)
+            self.__render_pymodule()
+        else:
+            self.__render_google_gadget()    
+
+        self.__sync_visibility()
+
+    def __sync_theme(self, *args):
+        if self.__content:
+            if self.__stylesheet:
+                theme = self.__theme_mgr.make_stock_theme(self.__stylesheet)
+                self.__content.set_theme(theme)
+
+    def on_delisted(self):
+        _logger.debug("on_delisted exchange %s" % (str(self)))
+        self.__unrender_pymodule()
+
+    def on_popped_out_changed(self, popped_out):
+        self.__pymodule.on_popped_out_changed(popped_out)
+
+    def __sync_visibility(self):
+        self.set_child_visible(self.__stockbox, self.__expanded)
+        if self.__ticker_container:
+            self.__ticker_container.set_child_visible(self.__ticker_arrow, not self.__expanded)
+
+    def __toggle_expanded(self):
+        self.__expanded = not self.__expanded
+        self.__sync_visibility()
+    
+    def get_metainfo(self):
+        return self.__metainfo
+    
+    def get_pymodule(self):
+        return self.__pymodule
+    
+    def __render_google_gadget(self):
+        rendered = GoogleGadgetContainer(self.__metainfo, self.__env)
+        self.__stockbox.append(rendered)
+    
+    def __render_pymodule(self, *args):
+        self.__size = size = Stock.SIZE_BULL
+        self.__stockbox.remove_all()
+        self.__pymodule.set_size(size)
+
+        self.__content = self.__pymodule.get_content(size) 
+        self.__sync_theme()
+
+        if self.__ticker_container:
+            self.set_child_visible(self.__ticker_container, not not self.__content)
+        self.set_child_visible(self.__sep,
+                               (not not self.__content) and \
+                               ((self.__ticker_container and size == Stock.SIZE_BEAR) \
+                                or (size == Stock.SIZE_BULL
+                                    and ((not self.__ticker_container) or (self.__pymodule.get_ticker() == "-")))))
+        if self.__mini_more_button:
+            self.set_child_visible(self.__mini_more_button, size == Stock.SIZE_BEAR)
+        self.set_child_visible(self.__stockbox, not not self.__content)
+        if not self.__content:
+            _logger.debug("no content for stock %s", self.__pymodule)
+            return
+        self.__stockbox.append(self.__content)
+        padding = 4
+        self.__stockbox.set_property("padding_left", padding)
+        self.__stockbox.set_property("padding_right", padding)
+        if self.__ticker_text:
+            self.set_child_visible(self.__ticker_container, size == Stock.SIZE_BULL)
+
+    def __unrender_pymodule(self):
+        if not self.__pymodule:
+            _logger.debug("Not a pymodule exchange")
+            return
+
+        _logger.debug("delisting pymodule %s" % (str(self.__pymodule)))
+        self.__pymodule.on_delisted()
+        self.__pymodule = None
+

Modified: trunk/bigboard/global_mugshot.py
==============================================================================
--- trunk/bigboard/global_mugshot.py	(original)
+++ trunk/bigboard/global_mugshot.py	Mon Jun 23 21:48:48 2008
@@ -46,8 +46,8 @@
     def __create_proxy(self):
          try:        
              bus = dbus.SessionBus()
-             self._logger.debug("creating proxy for %s" % globals.bus_name)
-             self.__mugshot_dbus_proxy = bus.get_object(globals.bus_name, '/com/dumbhippo/client')
+             self._logger.debug("creating proxy for %s" % globals.engine_bus_name)
+             self.__mugshot_dbus_proxy = bus.get_object(globals.engine_bus_name, '/com/dumbhippo/client')
              self.__registration_pending = True
              self.__mugshot_dbus_proxy.RegisterEndpoint(reply_handler=self.__on_register_endpoint, error_handler=self.__on_dbus_error)
             
@@ -58,15 +58,15 @@
     def __create_ws_proxy(self):
          try:
              bus = dbus.SessionBus()
-             self.__ws_proxy = bus.get_object(globals.bus_name, '/org/gnome/web_services')
+             self.__ws_proxy = bus.get_object(globals.engine_bus_name, '/org/gnome/web_services')
          except dbus.DBusException:
             self.__ws_proxy = None        
 
     @log_except(_logger)
     def __on_dbus_name_owner_changed(self, name, prev_owner, new_owner):
-        if name == globals.bus_name:
+        if name == globals.engine_bus_name:
             if new_owner != '':
-                self._logger.debug("owner for %s changed, recreating proxies", globals.bus_name)
+                self._logger.debug("owner for %s changed, recreating proxies", globals.engine_bus_name)
                 self.__create_proxy()
             else:
                 self.__mugshot_dbus_proxy = None

Modified: trunk/bigboard/globals.py
==============================================================================
--- trunk/bigboard/globals.py	(original)
+++ trunk/bigboard/globals.py	Mon Jun 23 21:48:48 2008
@@ -1,8 +1,13 @@
+import os
 import re
 
 from ddm import DataModel
+import gtk
 
-bus_name = 'org.freedesktop.od.Engine'
+BUS_NAME_STR='org.gnome.BigBoard'
+GCONF_PREFIX = '/apps/bigboard/'
+
+engine_bus_name = 'org.freedesktop.od.Engine'
 server_name = None
 _do_autolaunch_raw = True
 do_autolaunch = True
@@ -17,7 +22,7 @@
         
     return re.sub(r"[^a-zA-Z0-9]", _escape_byte, server_name.encode("UTF-8"))
 
-def _make_bus_name(server_name):
+def _make_engine_bus_name(server_name):
     if server_name == None:
         return "org.freedesktop.od.Engine";
 
@@ -42,7 +47,7 @@
 
 def set_server_name(value=None):
     global server_name
-    global bus_name
+    global engine_bus_name
     global do_autolaunch
     global _do_autolaunch_raw
     global __the_data_model
@@ -50,7 +55,7 @@
         if __the_data_model:
             raise Exception("We already used the data model before setting server name")
         server_name = value
-        bus_name = _make_bus_name(value)
+        engine_bus_name = _make_engine_bus_name(value)
         do_autolaunch = _do_autolaunch_raw and server_name == None
 
 def set_do_autolaunch(value):
@@ -87,3 +92,37 @@
         url = "http://online.gnome.org";
 
     return url
+
+def init():
+    global BB_DATADIR
+    
+    BB_DATADIR = os.getenv('BB_DATADIR')
+    if BB_DATADIR:
+        BB_DATADIR = os.path.abspath(BB_DATADIR)
+
+    icon_datadir = None
+    for path in _get_datadirs():
+        if os.path.isdir(path):
+            icon_datadir = path
+            break
+    if icon_datadir:
+        gtk.icon_theme_get_default().prepend_search_path(icon_datadir)
+
+def _get_datadirs():
+    datadir_env = os.getenv('XDG_DATA_DIRS')
+    if datadir_env:
+        datadirs = datadir_env.split(':')
+    else:
+        datadirs = ['/usr/share/']
+    return map(lambda x: os.path.join(x, 'bigboard'), datadirs)
+
+def find_in_datadir(fname):
+    if BB_DATADIR:
+        return os.path.join(BB_DATADIR, fname)
+    datadirs = _get_datadirs()
+    for dir in datadirs:
+        fpath = os.path.join(dir, fname)
+        if os.access(fpath, os.R_OK):
+            return fpath
+    return None
+

Modified: trunk/bigboard/stocks/files/FilesStock.py
==============================================================================
--- trunk/bigboard/stocks/files/FilesStock.py	(original)
+++ trunk/bigboard/stocks/files/FilesStock.py	Mon Jun 23 21:48:48 2008
@@ -410,8 +410,6 @@
         self.__slideout_target = None
         self.__last_slideout_event_time = None   
 
-        self.desktop_path = self._panel.get_desktop_path()
-
         self._box = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL, spacing=4, padding_top=2)
         self._recentbox = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL, spacing=4)
         self._box.append(self._recentbox)

Modified: trunk/bigboard/stocks/files/filebrowser.py
==============================================================================
--- trunk/bigboard/stocks/files/filebrowser.py	(original)
+++ trunk/bigboard/stocks/files/filebrowser.py	Mon Jun 23 21:48:48 2008
@@ -3,6 +3,11 @@
 import gobject, gtk
 import hippo
 
+try:
+    import bigboard.bignative as bignative
+except:
+    import bignative
+    
 from bigboard.big_widgets import BigWindow, CanvasMugshotURLImage, CanvasHBox, CanvasVBox, ActionLink, IconLink, PrelightingCanvasBox
 from bigboard.overview_table import OverviewTable
 
@@ -173,7 +178,7 @@
         self.__idle_search_id = 0          
 
     def __on_browse_local_files_clicked(self, canvas_item):
-        subprocess.Popen(['nautilus', '--browser', self.__stock.desktop_path])
+        subprocess.Popen(['nautilus', '--browser', bignative.get_desktop_dir()])
 
     def __on_search_local_files_clicked(self, canvas_item):
         # we don't want to turn "" into None, or change everything to be lowercase

Modified: trunk/bigboard/stocks/people/peoplewidgets.py
==============================================================================
--- trunk/bigboard/stocks/people/peoplewidgets.py	(original)
+++ trunk/bigboard/stocks/people/peoplewidgets.py	Mon Jun 23 21:48:48 2008
@@ -12,6 +12,7 @@
 from bigboard.big_widgets import PhotoContentItem, CanvasHBox, CanvasVBox
 from bigboard.big_widgets import BigWindow
 import bigboard.libbig as libbig
+from bigboard.libbig.logutil import log_except
 import bigboard.globals as globals
 from bigboard.libbig.format_escaped import format_escaped
 
@@ -71,8 +72,11 @@
         'sort-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
         'destroy': 'override',
     }
-    
+
+    @log_except(_logger)
     def __init__(self, person, themed=False, **kwargs):
+        _logger.debug("Initializing %s", self)
+
         PhotoContentItem.__init__(self, **kwargs)
         self.person = person
         
@@ -138,7 +142,10 @@
         self.__update_aim_buddy(self.person)
         self.__update_xmpp_buddy(self.person)
 
+        _logger.debug("Initialized %s", self)
+        
     def do_destroy(self):
+        _logger.debug("Destroying %s", self)
         for handler_id in self.__handlers:
             self.person.disconnect(handler_id)
 

Modified: trunk/bigboard/stocks/self/portfoliomanager.py
==============================================================================
--- trunk/bigboard/stocks/self/portfoliomanager.py	(original)
+++ trunk/bigboard/stocks/self/portfoliomanager.py	Mon Jun 23 21:48:48 2008
@@ -93,8 +93,8 @@
 
         self.__selected_item = None
         self.__search = None
-        self.__mgr = self.__panel.get_stock_manager()
-        self.__mgr.connect('listings-changed', lambda *args: self.__sync())
+        self.__exchange = self.__panel.get_exchange()
+        self.__exchange.connect('listings-changed', lambda *args: self.__sync())
         gobject.idle_add(self.__sync)
 
     def add_stock(self, metainfo, section):
@@ -176,8 +176,8 @@
              
     @log_except(_logger)
     def __sync(self):
-        all = list(self.__mgr.get_all_builtin_metadata())
-        listed = list(self.__mgr.get_listed())
+        all = list(self.__exchange.get_all_builtin_metadata())
+        listed = list(self.__exchange.get_listed())
         itemsections = []
         for section in self.__items:
             for srcurl in self.__items[section]:
@@ -197,8 +197,8 @@
         super(PortfolioManager, self).__init__(themed=False, stylesheet=stock.get_path('portfoliomanager.css'))
         
         self.__panel = stock.get_panel()
-        self.__mgr = self.__panel.get_stock_manager()        
-        self.__mgr.connect('listings-changed', lambda *args: self.__on_listings_change())        
+        self.__exchange = self.__panel.get_exchange()
+        self.__exchange.connect('listings-changed', lambda *args: self.__on_listings_change())        
         self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(65535,65535,65535))        
 
         self.set_title('Sidebar Preferences')
@@ -305,7 +305,7 @@
         except:
             _logger.debug("invalid URL: %s", url)
             return
-        self.__mgr.set_listed(url, True)        
+        self.__exchange.set_listed(url, True)        
 
     def __set_profile_stock(self, url):
         self.__profile_box.clear()
@@ -313,8 +313,8 @@
             self.__profile_box.set_property("box-height", 300)
         else:
             self.__profile_box.set_property("box_height", -1)
-            metainfo = self.__mgr.load_metainfo(url)
-            listed = url in self.__mgr.get_listed_urls()
+            metainfo = self.__exchange.load_metainfo(url)
+            listed = url in self.__exchange.get_listed_urls()
             pv = StockPreview(metainfo, listed)
             self.__preview = pv
             self.__profile_box.append(pv)
@@ -323,11 +323,11 @@
             
     def __on_item_add_remove(self, item):
         _logger.debug("got addremove for item %s", item.metainfo.srcurl)
-        self.__mgr.set_listed(item.metainfo.srcurl, not item.listed)
+        self.__exchange.set_listed(item.metainfo.srcurl, not item.listed)
         
     def __on_item_move(self, item, isup):
         _logger.debug("got move for item %s up: %s", item.metainfo.srcurl, isup)
-        self.__mgr.move_listing(item.metainfo.srcurl, isup)        
+        self.__exchange.move_listing(item.metainfo.srcurl, isup)        
 
     def __reset(self):
         self.__search_input.set_property('text', '')



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]