bigboard r7274 - trunk/bigboard



Author: marinaz
Date: Wed Apr  2 00:42:51 2008
New Revision: 7274
URL: http://svn.gnome.org/viewvc/bigboard?rev=7274&view=rev

Log:
Change the layout of the accounts dialog to contain two tabs -- one for existing accounts and one for adding new accounts.

Enable adding and removing accounts that are not supplied by the server in the dialog. 

Enable a link to the accounts page on the server when an account that is supplied by the server is being viewed. 


Modified:
   trunk/bigboard/accounts.py
   trunk/bigboard/accounts_dialog.py

Modified: trunk/bigboard/accounts.py
==============================================================================
--- trunk/bigboard/accounts.py	(original)
+++ trunk/bigboard/accounts.py	Wed Apr  2 00:42:51 2008
@@ -43,9 +43,12 @@
 KIND_GOOGLE = AccountKind("google", "Google", True)
 KIND_TWITTER = AccountKind("twitter", "Twitter", True)
 KIND_RTM = AccountKind("rtm", "Remember The Milk", False)
+KIND_LIBRARY = AccountKind("library", "LibraryThing", False)
+
+ALL_ACCOUNT_KINDS = [KIND_GOOGLE, KIND_TWITTER, KIND_RTM, KIND_LIBRARY]
 
 def kind_from_string(s):
-    for kind in [KIND_GOOGLE, KIND_TWITTER, KIND_RTM]:
+    for kind in ALL_ACCOUNT_KINDS:
         if s == kind.get_id():
             return kind
     return None
@@ -557,6 +560,12 @@
             else:
                 i = i + 1
 
+    def __find_account_in_gconf(self, kind, username, url):
+        for a in self.__gconf_accounts:
+            if a.get_kind() == kind and a.get_username() == username and a.get_url() == url:  
+                return a
+        return None 
+
     # new_properties is optional, it should be passed in if there are changes
     # to an existing account and we will update other data constructs that contain
     # this account based on the information from gconf
@@ -566,19 +575,17 @@
 
         # first see if an account with the same credentials exists in GConf
         if not gconf_dir:
-            for a in self.__gconf_accounts:
-                if a.get_kind() == account.get_kind() and a.get_username() == account.get_username() and \
-                   a.get_url() == account.get_url():
-                    gconf_dir = a._get_gconf_dir()
-                    account._set_gconf_dir(gconf_dir)
-                    account._set_enabled(a.get_enabled())
-                    self.__gconf_accounts.remove(a)
-                    if a in self.__enabled_accounts:
-                        self.__enabled_accounts.remove(a)
-                        self.emit('account-removed', a)
-                    self.__gconf_accounts.add(account)
-                    break
-        
+            gconf_account = self.__find_account_in_gconf(account.get_kind(), account.get_username(), account.get_url())
+            if gconf_account: 
+                gconf_dir = gconf_account._get_gconf_dir()
+                account._set_gconf_dir(gconf_dir)
+                account._set_enabled(gconf_account.get_enabled())
+                self.__gconf_accounts.remove(gconf_account)
+                if gconf_account in self.__enabled_accounts:
+                    self.__enabled_accounts.remove(gconf_account)
+                    self.emit('account-removed', gconf_account)
+                self.__gconf_accounts.add(account)
+                     
         # create a new GConf dir if it is a completely new account    
         if not gconf_dir:
             gconf_dir = self.__find_unused_gconf_dir(account.get_kind())
@@ -615,6 +622,7 @@
   
         ## enable it last, so we ignore the other settings until we do this
         if 'enabled' in new_properties:
+            _logger.debug("setting new enabled property to be %s" % new_properties['enabled'])
             set_account_prop(self.__gconf, base_key, 'enabled', new_properties['enabled'])
         elif new_gconf_dir:
              set_account_prop(self.__gconf, base_key, 'enabled', account.get_enabled())
@@ -660,16 +668,27 @@
             ## this should notice a new password
             self.__update_account(account)
 
-    def create_account(self, kind):
-        gconf_dir = self.__find_unused_gconf_dir(kind)
-        
-        base_key = '/apps/bigboard/accounts/' + gconf_dir
-        self.__gconf.set_string(base_key + '/kind', kind.get_id())
-        self.__gconf.set_bool(base_key + '/enabled', True)
+    # return a tuple with an account as the first element, and a boolean indicating if a new account was created
+    def get_or_create_account(self, kind, username):        
+        account = self.__find_account_in_gconf(kind, username, "")
+        if account:         
+            return (account, False)
+          
+        account = Account(kind, username=username)
+        self.__ensure_account_in_gconf(account)        
+        return (account, True)
+
+    def remove_account(self, account):
+        _logger.debug("will remove account with gconf_dir %s" % account._get_gconf_dir())  
+        self.__remove_gconf_dir(account._get_gconf_dir())
+        self.__update_account(account)
 
-    def get_accounts(self):
+    def get_enabled_accounts(self):
         return self.__enabled_accounts
 
+    def get_all_accounts(self):
+        return self.__gconf_accounts
+
     def get_accounts_with_kind(self, kind):
         accounts = set()
         for a in self.__enabled_accounts:

Modified: trunk/bigboard/accounts_dialog.py
==============================================================================
--- trunk/bigboard/accounts_dialog.py	(original)
+++ trunk/bigboard/accounts_dialog.py	Wed Apr  2 00:42:51 2008
@@ -1,4 +1,4 @@
-import sys, logging
+import sys, logging, urlparse
 
 import gobject, gtk
 import bigboard.accounts as accounts
@@ -70,48 +70,158 @@
         accounts.get_accounts().save_account_changes(self.__account,
                                                      { 'password' : text })
 
-class Dialog(gtk.Dialog):
+class Dialog(gtk.Window):
     @log_except(_logger)      
     def __init__(self, *args, **kwargs):
         super(Dialog, self).__init__(*args, **kwargs)        
         
         self.set_title('Accounts')
+        self.set_position(gtk.WIN_POS_CENTER)
 
+        self.__notebook = gtk.Notebook()
+        self.__notebook.set_border_width(5)
+
+        self.__outer_existing_accounts_vbox = gtk.VBox() 
+        self.__outer_existing_accounts_vbox.set_border_width(5)
+
+        self.__outer_new_account_vbox = gtk.VBox() 
+        self.__outer_new_account_vbox.set_border_width(5)
+
+        # make tabs take an equal amount of space
+        self.__notebook.set_property("homogeneous", True)
+        self.__notebook.append_page(self.__outer_existing_accounts_vbox, gtk.Label("Existing Accounts"))
+        self.__notebook.append_page(self.__outer_new_account_vbox, gtk.Label("Add Account"))
+        # make tabs expand horizontally
+        self.__notebook.set_tab_label_packing(self.__outer_new_account_vbox, True, True, gtk.PACK_START)
+
+        self.__existing_accounts_vbox = gtk.VBox()
+        self.__outer_existing_accounts_vbox.pack_start(self.__existing_accounts_vbox, False, False) 
+        self.__new_account_vbox = gtk.VBox() 
+        self.__outer_new_account_vbox.pack_start(self.__new_account_vbox, False, False) 
+
+        self.add(self.__notebook)
         self.connect('delete-event', self.__on_delete_event)
-        self.connect('response', self.__on_response)
 
-        self.add_button(gtk.STOCK_CLOSE,
-                        gtk.RESPONSE_OK)
-        self.set_default_response(gtk.RESPONSE_OK)
+        # stuff below gets added to the "Existing Accounts" tab
+
+        self.__model = gtk.ListStore(gobject.TYPE_STRING)
+        self.__accounts_combo = gtk.ComboBox(self.__model)
+        self.__existing_accounts_vbox.pack_start(self.__accounts_combo, True, False)
+        textrender = gtk.CellRendererText()
+        self.__accounts_combo.pack_start(textrender, True)
+        self.__accounts_combo.add_attribute(textrender, 'text', 0)
+        self.__accounts_combo.connect('notify::active', self.__on_edited_account_changed)
 
         # TODO: don't display the dropdown and password entry box if there are no accounts to edit 
         self.__password_entry = gtk.Entry()
         self.__password_entry.set_visibility(False) # this sets a password mode
+        self.__password_entry.connect('changed',
+                                      self.__on_account_settings_changed)
         self.__password_entry.connect('activate',
-                                      self.__on_password_entry_changed)
+                                      self.__on_account_settings_applied)
 
         password_vbox = gtk.VBox(spacing=2)
         label = gtk.Label("Password:")
         label.set_alignment(0.0, 0.5)
-        password_vbox.pack_start(label)    
-        password_vbox.pack_end(self.__password_entry, False)
-        self.vbox.pack_end(password_vbox, padding=5)
-
-        self.__model = gtk.ListStore(gobject.TYPE_STRING)
-        self.__accounts_combo = gtk.ComboBox(self.__model)
-        self.vbox.pack_end(self.__accounts_combo)
-        textrender = gtk.CellRendererText()
-        self.__accounts_combo.pack_start(textrender, True)
-        self.__accounts_combo.add_attribute(textrender, 'text', 0)
-        self.__accounts_combo.connect('notify::active', self.__on_edited_account_changed)
+        password_vbox.pack_start(label, True, False)    
+        password_vbox.pack_end(self.__password_entry, False, False)
+        self.__existing_accounts_vbox.pack_start(password_vbox, padding=5)
+
+        box_with_buttons = gtk.HBox()         
+        self.__check_box = gtk.CheckButton(label="Enabled")
+        box_with_buttons.pack_start(self.__check_box, False, False, padding=5)  
+        self.__existing_accounts_vbox.pack_start(box_with_buttons, False, False, padding=5)
+
+        self.__check_box.connect('toggled',
+                                 self.__on_account_settings_changed)
+
+        self.__undo_button = gtk.Button(stock=gtk.STOCK_UNDO)
+        self.__undo_button.connect('clicked',
+                                   self.__on_account_settings_reset)
+        self.__undo_button.set_sensitive(False)                     
+        self.__undo_button.size_allocate(gtk.gdk.Rectangle(width=100))               
+
+        self.__apply_button = gtk.Button(stock=gtk.STOCK_APPLY)
+        self.__apply_button.connect('clicked',
+                                   self.__on_account_settings_applied)
+        self.__apply_button.set_sensitive(False)
+
+        box_with_buttons.set_spacing(5)
+        box_with_buttons.set_homogeneous(False)
+        box_with_buttons.pack_end(self.__apply_button, expand=False, fill=False)
+        box_with_buttons.pack_end(self.__undo_button, expand=False, fill=False)
+
+        remove_button_box = gtk.HBox()
+        self.__remove_button = gtk.Button(label="Remove Account")
+        remove_image = gtk.Image()
+        remove_image.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON)
+        self.__remove_button.set_image(remove_image) 
+        self.__remove_button.set_sensitive(False)
+        self.__remove_button.connect('clicked',
+                                   self.__on_account_remove_clicked)
+        remove_button_box.pack_end(self.__remove_button, expand=False, fill=False)
+
+        self.__remove_link_box = gtk.HBox()
+        self.__remove_link = Link()
+        self.__remove_link.set_text("Remove account online")
+        self.__remove_link.set_enabled(False)
+        self.__remove_link.connect("clicked", self.__open_account_page)
+        self.__remove_link_box.pack_end(self.__remove_link, expand=False, fill=False)
+
+        self.__existing_accounts_vbox.pack_start(remove_button_box, False, False, padding=5)
+        self.__existing_accounts_vbox.pack_start(self.__remove_link_box, False, False)
+
+        # stuff below gets added to the "Add Account" tab
+
+        self.__account_kinds_model = gtk.ListStore(gobject.TYPE_STRING)
+        self.__account_kinds_combo = gtk.ComboBox(self.__account_kinds_model)
+        self.__new_account_vbox.pack_start(self.__account_kinds_combo, True, False)
+        account_kinds_textrender = gtk.CellRendererText()
+        self.__account_kinds_combo.pack_start(account_kinds_textrender, True)
+        self.__account_kinds_combo.add_attribute(account_kinds_textrender, 'text', 0)
+        for kind in accounts.ALL_ACCOUNT_KINDS:
+            if not kind.get_provided_by_server():
+                self.__account_kinds_model.append([kind.get_name()])
+            
+        if len(self.__account_kinds_model) > 0:
+            self.__account_kinds_combo.set_active(0) 
 
+        self.__username_entry = gtk.Entry()
+        self.__username_entry.connect('changed',
+                                      self.__on_new_username_changed)
+        self.__username_entry.connect('activate',
+                                      self.__on_new_username_added)
+
+        username_vbox = gtk.VBox(spacing=2)
+        username_label = gtk.Label("Username:")
+        username_label.set_alignment(0.0, 0.5)
+        username_vbox.pack_start(username_label, False, False)    
+        username_vbox.pack_end(self.__username_entry, False, False)
+        self.__new_account_vbox.pack_start(username_vbox, padding=5)
+
+        self.__add_button_box = gtk.HBox()
+        self.__add_button = gtk.Button(label="Add Account")
+        add_image = gtk.Image()
+        add_image.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
+        self.__add_button.set_image(add_image) 
+        self.__add_button.set_sensitive(False)
+        self.__add_button.connect('clicked',
+                                   self.__on_new_username_added)
+        self.__add_button_box.pack_end(self.__add_button, expand=False, fill=False)
+        self.__new_account_vbox.pack_start(self.__add_button_box, False, False, padding=5)
+
+        self.__add_link_box = gtk.HBox()
+        self.__add_link = Link()
+        self.__add_link.set_text("Add other accounts online")
+        self.__add_link.connect("clicked", self.__open_account_page)
+        self.__add_link_box.pack_end(self.__add_link, expand=False, fill=False)
+        self.__outer_new_account_vbox.pack_end(self.__add_link_box, False, False)
+        
         self.__model_tree_iter_by_account = {}
         self.__current_account = None
 
         self.show_all()
 
-        self.__password_entry.set_activates_default(True)
-
         self.__connections = gutil.DisconnectSet()
 
         accts = accounts.get_accounts()
@@ -121,7 +231,7 @@
         self.__connections.add(accts, id)
 
         # google_accounts = accts.get_accounts_with_kind(accounts.KIND_GOOGLE)
-        all_accounts = accts.get_accounts()
+        all_accounts = accts.get_all_accounts()
         if len(all_accounts) == 0:
             # do something else
             pass
@@ -131,6 +241,9 @@
 
     ## should be a destroy() that disconnects connections, but we never destroy anyway
 
+    def __open_account_page(self, l):
+        libbig.show_url(urlparse.urljoin(globals.get_baseurl(), "/account"))
+   
     @log_except(_logger)      
     def __on_account_added(self, accts, a):
         # TODO: check for account kind when we have a per-account dialog
@@ -155,9 +268,10 @@
             _logger.debug("will remove")
             self.__model.remove(self.__model_tree_iter_by_account[a])
             del self.__model_tree_iter_by_account[a]
-            #TODO: figure out how we update the current account here, 
-            #      possibly calling __on_edited_account_changed will do, but then
-            #      but than it needs to check if self.__model_tree_iter_by_account is empty
+            # TODO: possibly can get the index of the deleted selection, and move to the next one 
+            if self.__current_account == a and len(self.__model_tree_iter_by_account) > 0:                
+                self.__current_account = self.__model_tree_iter_by_account.keys()[0]
+                self.__accounts_combo.set_active_iter(self.__model_tree_iter_by_account.values()[0]) 
 
     def __on_edited_account_changed(self, *args):
         new_iter = self.__accounts_combo.get_active_iter()
@@ -168,22 +282,133 @@
                 self.__current_account = a
                 # TODO: this will trigger __on_password_entry_changed, make sure that is harmless
                 self.__password_entry.set_text(a.get_password())
+                self.__check_box.set_active(a.get_enabled())
+                self.__remove_button.set_sensitive(not a.get_kind().get_provided_by_server()) 
+                self.__remove_link.set_enabled(a.get_kind().get_provided_by_server())
                 return
         _logger.error("new edited account was not found in self.__model_tree_iter_by_account")
 
-    def __on_password_entry_changed(self, entry):
-        text = entry.get_text()
+    def __on_account_settings_changed(self, widget):
+        if self.__password_entry.get_text().strip() != self.__current_account.get_password() or \
+           self.__check_box.get_active() != self.__current_account.get_enabled():
+            self.__undo_button.set_sensitive(True)  
+            self.__apply_button.set_sensitive(True)  
+        else:
+            self.__undo_button.set_sensitive(False)  
+            self.__apply_button.set_sensitive(False)  
+
+    def __on_account_settings_applied(self, widget):
+        text = self.__password_entry.get_text()
+        enabled = self.__check_box.get_active()
         accounts.get_accounts().save_account_changes(self.__current_account,
-                                                     { 'password' : text })
+                                                     { 'password' : text, 'enabled' : enabled })
+        self.__undo_button.set_sensitive(False)  
+        self.__apply_button.set_sensitive(False)  
+
+    def __on_account_settings_reset(self, widget):
+        self.__password_entry.set_text(self.__current_account.get_password())
+        self.__check_box.set_active(self.__current_account.get_enabled())
+  
+    def __on_account_remove_clicked(self, widget):
+        accounts.get_accounts().remove_account(self.__current_account)
+
+    def __on_new_username_changed(self, widget):
+        # in the future can check if the input is of the desired form here
+        username_entered = (len(self.__username_entry.get_text().strip()) > 0)  
+        self.__add_button.set_sensitive(username_entered)        
+
+    def __on_new_username_added(self, widget):
+        text = self.__username_entry.get_text()
+        username_entered = (len(text.strip()) > 0)
+        # don't do anything if the user pressed enter in the username textbox while it is empty 
+        if not username_entered:
+            return
+        
+        current_iter = self.__account_kinds_combo.get_active_iter()
+        for kind in accounts.ALL_ACCOUNT_KINDS:
+            if not kind.get_provided_by_server() and self.__account_kinds_model.get_value(current_iter, 0) == kind.get_name():
+                account_tuple = accounts.get_accounts().get_or_create_account(kind, text)
+                self.__username_entry.set_text("")
+                self.__notebook.set_current_page(0)
+                # TODO: Display a special message if the account aready existed (account_tuple[1] is False), also
+                # the key should be self.__model_tree_iter_by_account only in that case
+                if self.__model_tree_iter_by_account.has_key(account_tuple[0]):
+                    account_iter = self.__model_tree_iter_by_account[account_tuple[0]]                
+                    self.__accounts_combo.set_active_iter(account_iter)
+                else:
+                    # acounts system will emit a signal that will cause __on_account_added to be called again, 
+                    # but it's ok to call this from here so that we can switch to the new account in the combo box right away
+                    self.__on_account_added(None, account_tuple[0])
+                    account_iter = self.__model_tree_iter_by_account[account_tuple[0]]   
+                    self.__accounts_combo.set_active_iter(account_iter)
+                return 
+                
+        _logger.warn("Did not find an account kind which is not provided by the server that matched the account kind in the dropdown %s" % self.__account_kinds_model.get_value(current_iter, 0))
 
     def __on_delete_event(self, dialog, event):
         self.hide()
         return True
+        
+class Link(gtk.EventBox):
+    __gsignals__ = {
+        "clicked" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+    }
+    
+    def __init__(self,**kwargs):
+        super(Link, self).__init__(**kwargs)
+        self.__text = None
+        self.__enabled = True
+        self.__label = gtk.Label()
+        self.add(self.__label)
+        self.connect("button-press-event", self.__on_button_press)
+        self.connect("enter_notify_event", self.__on_enter) 
+        self.connect("leave_notify_event", self.__on_leave) 
+        self.add_events(gtk.gdk.BUTTON_PRESS_MASK
+                        & gtk.gdk.ENTER_NOTIFY_MASK
+                        & gtk.gdk.LEAVE_NOTIFY_MASK)
 
-    def __on_response(self, dialog, response_id):
-        _logger.debug("response = %d" % response_id)
-        self.hide()
+    def set_alignment(self, x, y):
+        self.__label.set_alignment(x, y)
         
+    def set_ellipsize(self, do_ellipsize):
+        self.__label.set_ellipsize(do_ellipsize)
+
+    def __on_button_press(self, self2, e):
+        if e.button == 1 and self.__enabled:
+            self.emit("clicked")
+            return True
+        return False
+
+    def get_text(self):
+        return self.__text
+    
+    def set_text(self, text):
+        self.__text = text
+        self.set_markup(gobject.markup_escape_text(text))
+    
+    def set_enabled(self, enabled):        
+        self.__enabled = enabled
+        self.set_markup(gobject.markup_escape_text(self.__text))
+
+    def set_markup(self, text):
+        if  self.__enabled: 
+            self.__label.set_markup('<span foreground="blue">%s</span>' % (text,))
+        else:
+            self.__label.set_markup('<span foreground="#666666">%s</span>' % (text,))
+
+    def __on_enter(self, w, c):
+        self.__talk_to_the_hand(True)
+
+    def __on_leave(self, w, c):
+        self.__talk_to_the_hand(False)
+
+    def __talk_to_the_hand(self, hand):
+        display = self.get_display()
+        cursor = None
+        if hand and self.__enabled:
+            cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
+        self.window.set_cursor(cursor)
+
 __dialog = None
 
 @log_except(_logger)      



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