def __init__(self): import gtk.glade import Paths import Signals root = 'first-time' self.__xml = gtk.glade.XML(Paths.glade, root) self.__dialog = self.__get_widget(root) Signals.autoconnect(self, self.__xml) # hook up GConf configuration monitoring import gconf from GConfDir import GConfDir self.__client = gconf.client_get_default() self.__dir = GConfDir(self.__client, Keys.root, gconf.CLIENT_PRELOAD_NONE) # hook up state-linked icons from StatusIcon import StatusIcon from WindowIcon import WindowIcon image = self.__get_widget('image') self.__image_updater = StatusIcon(self.__client, image, gtk.ICON_SIZE_DIALOG) self.__icon_updater = WindowIcon(self.__client, self.__dialog) # hook up state-linked radio buttons from MasterNotifier import MasterNotifier self.__notifier = MasterNotifier(self.__client, self.__enabled_refresh)
def create_status_icon(self): if not self.has_status_icon: #create the statusicon self.statusicon = StatusIcon() self.statusicon.connect('activate', self.status_clicked ) self.statusicon.connect('quit-selected',self.quit_app) self.statusicon.set_icon( self.standard_icon_path ) self.statusicon.set_property("visible",True) self.has_status_icon=True
class application : def __init__(self): #init threading gobject.threads_init() #keep track of the window size self.window_height=0 self.window_width=0 self.window_is_hidden = False self.has_status_icon = False #keep track of the initial conversation id so that conversations don't colide self.conversation_id="0" #keep track of the filters self.filters ={'users':[],'strings':[]} self.options={'run_as_tray_app':False,'context_backwards':False,'no_avatars':False,'notifications':True,'notify_replies':False} #keep track of the direct_message requests self.last_direct_message_time=0 #something something direct message self.is_direct_message_mode=False self.direct_message_to=None self.waiting_requests=0 self.is_first_dents = True #keep track of the respond to id self.respond_to_id=0 self.pre_group_page=None self.pre_user_page=None #keep track of the last time statuses where pulled self.last_get_statuses = 0 #what are the assets? asset_dir = 'assets' heybuddy_dir = os.path.dirname( os.path.realpath( __file__ ) ) self.readme_file = os.path.join(heybuddy_dir,'README.txt') self.standard_icon_path = os.path.join(heybuddy_dir,asset_dir,'icon.png') self.direct_icon_path = os.path.join(heybuddy_dir,asset_dir,'direct_icon.png') self.networking_icon_path = os.path.join(heybuddy_dir,asset_dir,'icon1.png') self.throbber_icon_path = os.path.join(heybuddy_dir,asset_dir,'throbber.gif') self.default_icon_path = self.standard_icon_path self.conf = Configuration(app_name) #has the account info been authenticated? self.credentials_verified = self.conf.get_bool('access', 'credentials_verified') self.xmlprocessor = XMLProcessor() #create a regex to replace parts of a dent self.regex_tag = re.compile("(^| )#([\w-]+)", re.UNICODE) self.regex_group = re.compile("(^| )!([\w-]+)") self.regex_user=re.compile("(^|[^A-z0-9])@(\w+)") self.regex_url=re.compile("(http[s]?://.*?)(\.$|\. |\s|$)",re.IGNORECASE) #get the initial dents self.initial_dents = self.conf.get('settings','initial_dents',default='20' ) self.dent_limit = int(self.initial_dents)*2 #get the pull time self.pull_time = self.conf.get('settings','pull_time',default='60') self.pull_time_changed_bool = False self.pull_time_mentions = False #build the gui self.build_gui() #where is the certs file? ca_certs_files = [ "/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/certs/ca-bundle.crt", ] #what if there isn't a cert_file cert_file=None #determine the certs_file for f in ca_certs_files: if os.path.exists(f): cert_file=f break #create the communicator self.comm = Communicator(app_name, cert_file) self.comm.connect('statusesXML',self.process_statusesXML,self.dentspage) self.comm.connect('mentionsXML',self.process_statusesXML,self.mentionspage) self.comm.connect('favoritesXML', self.process_statusesXML,self.favoritespage) self.comm.connect('group-statusesXML',self.process_statusesXML,self.grouppage) self.comm.connect('user-statusesXML',self.process_statusesXML,self.userpage) self.comm.connect('direct_messagesXML',self.process_statusesXML,self.directspage,True) self.comm.connect('conversationXML',self.process_conversationXML) self.comm.connect('userXML',self.process_userXML) self.comm.connect('groupXML',self.process_groupXML) self.comm.connect('new-statusXML',self.process_new_statusXML) self.comm.connect('redent-statusXML',self.process_new_statusXML) self.comm.connect('user_is_friendXML',self.process_user_is_friendXML) self.comm.connect('user_is_memberXML',self.process_user_is_memberXML) self.comm.connect('friendshipXML',self.process_friendshipXML) self.comm.connect('exception-caught',self.process_communication_exception) self.comm.connect('widget-image',self.process_widget_image) self.comm.connect('direct-messageXML',self.process_new_directXML) self.comm.connect('verify_credentialsXML',self.process_verifycredentialsXML) self.comm.connect('configXML',self.process_configXML) #create an image cacher thingy self.imagecache = ImageCache() self.imagecache.set_disabled( self.conf.get_bool_option('no_avatars') ) self.imagecache.connect('get-widget-image', self.get_widget_image) #Create notify-er if has pynotify if has_pynotify: self.notify = Notify() #align the window self.align_window() # do we need to create the status icon if self.conf.get_bool_option('run_as_tray_app'): self.create_status_icon() def build_gui(self): #build the GUI self.mainwindow=MainWindow.MainWindow(app_name,version,branch) try: self.mainwindow.set_icon_from_file(self.default_icon_path) except: pass self.mainwindow.set_textlimit( self.conf.textlimit() ) self.mainwindow.set_ctrl_enter( self.conf.get_bool_option('ctrl_enter') ) self.mainwindow.connect('quit', self.quit_triggered ) self.mainwindow.connect('window-to-tray', self.window_to_tray ) self.mainwindow.connect('update-status',self.update_status) self.mainwindow.connect('get-conversation',self.get_conversation) self.mainwindow.connect('show-user',self.get_user_info) self.mainwindow.connect('show-group',self.get_group_info) self.mainwindow.connect('notebook-page-change',self.page_change) self.mainwindow.connect('follow-user',self.follow_user) self.mainwindow.connect('join-group',self.join_group) self.mainwindow.connect('clear-respond-to-id',self.clear_respond_to_id) #keep track of the window size self.mainwindow.connect('size-allocate', self.window_size_allocate) #self.mainwindow.connect('window-state-event', self.mainwindow_state_event) self.mainwindow.connect('delete-event', self.mainwindow_delete_event) # local function to create a closeable tab label for closeable tabs def closeable_tab_label(caption, tab): tablabel = gtk.HBox(False,2) tablabel.pack_start(gtk.Label(caption),False,False,0) closebutton = gtk.Button() closeicon = gtk.Image() closeicon.set_from_stock(gtk.STOCK_CLOSE,gtk.ICON_SIZE_MENU) closebutton.set_image(closeicon) closebutton.set_relief(gtk.RELIEF_NONE) tinybutton_style = gtk.RcStyle() tinybutton_style.xthickness = 0 tinybutton_style.ythickness = 0 closebutton.modify_style(tinybutton_style) if tab != None: # if this isn't a mock-add closebutton.connect('clicked',tab.close) #don't show a tooltip on maemo if not has_hildon: closebutton.set_tooltip_text(_("Close")) tablabel.pack_start(closebutton,False,False,0) tablabel.show_all() return tablabel # do a mock add of dentspage, with a close label, so as to determine height needed for uncloseable tabs' labels, then break it all down again # this is ridiculously hacky, but it works, and doesn't leave anything behind self.dentspage = ScrollPage() self.mock_label = closeable_tab_label(_("Dents"),None) self.mainwindow.notebook.append_page(self.dentspage,self.mock_label) self.mainwindow.show_all() # we have to do this so the tab gets actualised, and thus gets a height min_tab_height = self.mock_label.allocation.height self.mainwindow.hide_all() self.mainwindow.notebook.remove_page(-1) del self.mock_label # local function to create a label the same height as the closeable tabs' labels def uncloseable_tab_label(caption): tablabel = gtk.Label(caption) tablabel.set_size_request(-1,min_tab_height) tablabel.show() return tablabel # create and add all of the pages self.dentspage = ScrollPage() self.mainwindow.notebook.append_page(self.dentspage,uncloseable_tab_label(_("Dents") ) ) self.mentionspage = ScrollPage() self.mainwindow.notebook.append_page(self.mentionspage,uncloseable_tab_label(_("Mentions")) ) self.favoritespage = ScrollPage() self.mainwindow.notebook.append_page(self.favoritespage,uncloseable_tab_label(_("Favorites")) ) self.directspage = ScrollPage() self.mainwindow.notebook.append_page(self.directspage,uncloseable_tab_label(_("Directs")) ) #make the conversation page self.contextpage=ContextPage() self.contextpage.connect('context-page-hide',self.hide_contextpage) #add the contextpage context_label = closeable_tab_label(_("Context"), self.contextpage) self.mainwindow.notebook.append_page(self.contextpage, context_label) #create a user page self.userpage=UserPage() self.userpage.connect('user-page-hide',self.hide_userpage) self.userpage.connect('follow-user',self.follow_user) self.userpage.connect('direct-clicked',self.direct_clicked) self.userpage.connect('open-link',self.open_link) self.userpage.connect('block-create',self.block_create) self.userpage.connect('block-destroy',self.block_destroy) #add the userpage user_label = closeable_tab_label(_("User"),self.userpage ) self.mainwindow.notebook.append_page(self.userpage, user_label) #create a Group page self.grouppage=GroupPage() self.grouppage.connect('group-page-hide',self.hide_grouppage) self.grouppage.connect('join-group',self.join_group) self.grouppage.connect('open-link',self.open_link) #add the Grouppage group_label = closeable_tab_label(_("Group"),self.grouppage ) self.mainwindow.notebook.append_page(self.grouppage, group_label) #create and add the account page self.settingspage = SettingsPage(has_hildon,has_pynotify) self.settingspage.set_initial_dents( self.initial_dents ) self.settingspage.set_pull_time(self.pull_time) #update the configuration of the settings self.settingspage.connect('update-account',self.update_account) self.options['ctrl_enter'] = self.conf.get_bool_option('ctrl_enter') self.settingspage.set_ctrl_enter( self.options['ctrl_enter'] ) self.options['run_as_tray_app'] = self.conf.get_bool_option('run_as_tray_app') self.settingspage.set_run_as_tray_app( self.options['run_as_tray_app'] ) self.options['context_backwards'] = self.conf.get_bool_option('context_backwards') self.settingspage.set_context_backwards( self.options['context_backwards'] ) self.options['no_avatar']= self.conf.get_bool_option('no_avatars') self.settingspage.set_no_avatars( self.options['no_avatar'] ) self.options['api_retweet'] = self.conf.get_bool_option('api_retweet') self.settingspage.set_api_retweet( self.options['api_retweet'] ) self.options['notifications']= self.conf.get_bool_option('notifications') self.settingspage.set_notifications( self.options['notifications'] ) self.options['notify_replies']= self.conf.get_bool_option('notify_replies') self.settingspage.set_notify_replies( self.options['notify_replies'] ) link_color = self.conf.get('settings','link_color',default='blue') self.settingspage.set_link_color( link_color ) self.theme_link_color(link_color) #connect the setting signals self.settingspage.connect('option-run-as-tray-app', self.option_changed, 'run_as_tray_app') self.settingspage.connect('option-ctrl-enter', self.option_changed, 'ctrl_enter') self.settingspage.connect('option-context-backwards',self.option_changed, 'context_backwards') self.settingspage.connect('option-no-avatars',self.option_changed, 'no_avatars') self.settingspage.connect('option-api-retweet', self.option_changed, 'api_retweet') self.settingspage.connect('option-notifications',self.option_changed, 'notifications') self.settingspage.connect('option-notify-replies',self.option_changed, 'notify_replies') self.settingspage.connect('initial-dents',self.set_initial_dents) self.settingspage.connect('pull-time',self.set_pull_time) self.settingspage.connect('link-color',self.set_link_color) self.settingspage.connect('add-string-filter', self.add_string_filter ) self.settingspage.connect('remove-string-filter', self.remove_string_filter ) self.settingspage.connect('add-user-filter', self.add_user_filter ) self.settingspage.connect('remove-user-filter', self.remove_user_filter ) #add the settings to the mainwindow self.mainwindow.add_notebook_page(self.settingspage,uncloseable_tab_label(_("Settings") ) ) #create and add the about page about = About(version,branch,self.standard_icon_path,self.readme_file) about.connect('open-link',self.open_link) self.mainwindow.add_notebook_page( about, uncloseable_tab_label(_("About") ) ) self.mainwindow.show_some() #hide some stuff self.grouppage.hide_all() self.userpage.hide_all() self.contextpage.hide_all() def align_window(self): #try to set the mainwindows size based on conf info try: w = int( self.conf.get('window_info','width') ) h = int( self.conf.get('window_info','height') ) self.mainwindow.resize(w,h) except: pass try: x = int( self.conf.get('window_info','x') ) y = int( self.conf.get('window_info','y') ) self.mainwindow.move(x,y) except: pass #get the filters try: #read the filters filters = self.conf.get('settings','filters',True) #the filters should be an array if len(filters): #self.filters = filters self.filters['users'] = filters['users'] self.filters['strings'] = filters['strings'] #set the filters self.settingspage.set_string_filters( self.filters['strings'] ) self.settingspage.set_user_filters( self.filters['users'] ) except: pass def create_status_icon(self): if not self.has_status_icon: #create the statusicon self.statusicon = StatusIcon() self.statusicon.connect('activate', self.status_clicked ) self.statusicon.connect('quit-selected',self.quit_app) self.statusicon.set_icon( self.standard_icon_path ) self.statusicon.set_property("visible",True) self.has_status_icon=True def destroy_status_icon(self): self.statusicon.set_property("visible",False) self.has_status_icon=False def update_account(self, widget, n, p, s): #check if these are valid self.mainwindow.set_message(_("Authenticating account...")) self.increment_requests() self.comm.verify_credentials(n, p, s) def increment_requests(self): self.waiting_requests+=1 if self.waiting_requests==1: try: self.mainwindow.set_icon_from_file(self.networking_icon_path) except: pass try: self.mainwindow.set_throbber(self.throbber_icon_path) except: pass if self.has_status_icon: self.statusicon.set_icon( self.networking_icon_path) def decrement_requests(self): self.waiting_requests-=1 if self.waiting_requests==0: try: self.mainwindow.set_icon_from_file(self.default_icon_path) except: pass try: self.mainwindow.set_throbber(self.default_icon_path) except: pass if self.has_status_icon: self.statusicon.set_icon( self.default_icon_path ) if self.waiting_requests<0: self.waiting_requests=0 def valid_account_info(self, n, p, s): self.conf.name( n ) self.conf.password( p ) self.conf.service( s ) self.conf.save() #update the comm self.comm.set_name_and_password( n,p ) self.comm.set_service( s ) def get_statuses(self,count="20"): if self.credentials_verified: #do some time handling for the good doctor now = time.time() if now - self.last_get_statuses > 2*self.pull_time: count = self.initial_dents self.last_get_statuses = now self.increment_requests() self.comm.get_statuses(count=count, since=highest_id['dent_previous']) #clean up the garbage gc.collect() def get_mentions(self,count="20"): if self.credentials_verified: self.increment_requests() self.comm.get_mentions(count=count,since=highest_id['mention_previous']) def get_favorites(self): if self.credentials_verified: self.increment_requests() self.comm.get_favorites() def get_direct_messages(self): if self.credentials_verified: now = time.time() #NOTE this could be changed to 3 minutes just setting it #this way for now #has it been 3 times the pull time? if now - (3 * int(self.pull_time) ) > self.last_direct_message_time: self.increment_requests() self.comm.get_direct_messages(highest_id['direct_previous']) self.last_direct_message_time=now def run(self, enable_logging=False): self.logging = enable_logging #start the communicator self.comm.start() self.main_loop = gobject.MainLoop() #we have to temporarily show the various pages or nothing works ''' why the f**k do I need to do this? ''' self.mainwindow.set_notebook_page(DIRECT) self.mainwindow.set_notebook_page(MENTION) self.mainwindow.set_notebook_page(FAVORITE) self.mainwindow.set_notebook_page(DENT) #send the service to the settings page self.settingspage.set_service(self.conf.service() ) #did the conf read a name and password? if( self.conf.name() !="" and self.conf.password()!=""): if self.credentials_verified: self.comm.set_name_and_password( self.conf.name(),self.conf.password() ) self.comm.set_service( self.conf.service() ) #fill the Account tab name/pw fields to show the user that they're logged in self.settingspage.set_name(self.conf.name()) self.settingspage.set_password(self.conf.password()) #add a function to the main loop gobject.timeout_add(int(self.pull_time)*1000, self.update_statuses ) gobject.timeout_add(int(self.pull_time)*1500, self.update_mentions ) #add a timout to get dents gobject.timeout_add(500,self.get_statuses,self.initial_dents ) gobject.timeout_add(600,self.get_mentions,self.initial_dents ) #gobject.timeout_add(1000,self.get_direct_messages ) else: #set the focus on the account page; the last page self.mainwindow.set_notebook_page(ACCOUNT) self.mainwindow.run() self.main_loop.run() #if we ever get here, we should quit def update_statuses(self): self.get_statuses() if(self.pull_time_changed_bool): self.pull_time_changed_bool= False gobject.timeout_add(int(self.pull_time)*1000, self.update_statuses) return False return True def update_mentions(self): self.get_mentions() if(self.pull_time_mentions): self.pull_time_mentions=False gobject.timeout_add(int(self.pull_time)*1500, self.update_mentions) return False return True def update_direct_messages(self): self.get_direct_messages() return True def update_status(self,widget,text): self.increment_requests() #remove newlines from text text=text.replace("\n","") #is this direct message mode? if self.is_direct_message_mode: self.comm.send_direct_message(text,self.direct_message_to) self.set_is_direct_message_mode(False) else: self.comm.send_update_status(text,self.respond_to_id) self.clear_respond_to_id() def quit_app(self,widget=None): #quit the communicator loop self.comm.quit() #quit the main loop self.main_loop.quit() def get_widget_image(self,imagecache,image): self.comm.get_widget_image(image) def get_conversation(self,id,conversation_id): if self.credentials_verified: self.increment_requests() self.comm.get_conversation(id,conversation_id) def parse_profile(self, profile=None, name=None ): #is this a remote user? remote_user = True service = '' #did we get a name? if profile!=None: bits = profile.rsplit("/") service = bits[2] if name==None: name = bits[3] #if there is no name, use the first subdomain as a name if name==None: dot_split = service.split(".") name = dot_split[0] if service==self.conf.service(): remote_user = False else: remote_user = False return {'service':service, 'remote':remote_user,'name':name} def get_user_info(self, profile=None, name=None): #parse the info result = self.parse_profile( profile, name ) #is this a remote user? remote_user = result['remote'] name = result['name'] service = result['service'] #is this not a remote user? if not remote_user: if self.credentials_verified: self.increment_requests() self.comm.get_user_info(name) self.increment_requests() self.comm.get_user_statuses(name) return self.increment_requests() self.comm.get_remote_user_info(service,name) self.increment_requests() self.comm.get_remote_user_statuses(service,name) def get_group_info(self,name): if self.credentials_verified: self.increment_requests() self.comm.get_group_info(name) def follow_user(self,widget,name,bool): if self.credentials_verified: if bool: self.comm.friendship_create(name) else: self.comm.friendship_destroy(name) def join_group(self,widget,name,bool): if self.credentials_verified: if bool: self.comm.group_join(name) else: self.comm.group_leave(name) def process_friendshipXML(self,widget,text): pass def page_change(self,widget,old_id,new_id): if new_id==MainWindow.DIRECT: self.get_direct_messages() elif new_id==MainWindow.FAVORITE: self.get_favorites() else: if self.is_direct_message_mode: self.set_is_direct_message_mode(False) #should we clear any warning message? self.mainwindow.clear_message() def process_userXML(self,comm,text): self.decrement_requests() data = self.xmlprocessor.get_user_info(text) if data['profile_image_url']!=None: self.imagecache.add_image_to_widget(data['profile_image_url'],self.userpage) self.userpage.set_user_data(data) def process_groupXML(self,comm,text): self.decrement_requests() data = self.xmlprocessor.get_group_info(text) if data['stream_logo']!=None: self.imagecache.add_image_to_widget(data['stream_logo'],self.grouppage) '''#is this user a member of this group self.increment_requests() self.comm.get_user_is_member(data['id'])''' self.increment_requests() self.comm.get_group_statuses(data['id']) self.grouppage.set_group_data(data) def process_user_is_friendXML(self,comm,text): self.decrement_requests() is_friend = self.xmlprocessor.get_user_is_friend(text) self.mainwindow.display_user_is_friend( is_friend ) def process_user_is_memberXML(self,comm,text): self.decrement_requests() is_member = self.xmlprocessor.get_user_is_member(text) self.mainwindow.display_user_is_member( is_member ) def process_new_directXML(self,comm,text): #a update status was sent self.decrement_requests() #clear the textview thing self.mainwindow.emit_update_textview_responsed() def process_new_statusXML(self,comm,text): #a update status was sent self.decrement_requests() #clear the textview thing self.mainwindow.emit_update_textview_responsed() #there is one status and it is the DOM status = self.xmlprocessor.get_dom(text) data = self.xmlprocessor.get_dent_data(status) data['markup'] = self.markup_dent_text(data['text']) #add the dent dent = self.connect_dent(data,self.dentspage) def process_verifycredentialsXML(self, object, text, data): #actually, if we are here, the authorization worked! self.conf.set('access', 'credentials_verified', True) self.credentials_verified = True self.mainwindow.message_label.hide() (n, p, s) = data self.valid_account_info(n, p, s) #get the config self.comm.get_config() #switch to the dents page self.mainwindow.set_notebook_page(DENT) self.get_statuses() self.get_mentions() def process_conversationXML(self,object,text,conversation_id): self.decrement_requests() #is this the current conversation Id? if not, then do nothing #convert to int because there is a problem with string comparison '''is one of the strings unicode?''' if int(self.conversation_id)==int(conversation_id): #get the status status = self.xmlprocessor.get_dom(text) data = self.xmlprocessor.get_dent_data(status) data['markup']=self.markup_dent_text(data['text']) #since this is a conversation, we can get rid of the in_reply_to_screen_name data['in_reply_to_screen_name']=None #tell the mainWindow to add the dent dent = self.connect_dent(data,self.contextpage,True, self.options['context_backwards'] ) if data['in_reply_to_id']!=None: #recursively get in_reply_to_ids self.get_conversation(id=data['in_reply_to_id'],conversation_id=conversation_id) def process_configXML(self, object, text): self.decrement_requests() server = self.xmlprocessor.get_server_config(text) print server self.conf.textlimit( server['textlimit'] ) self.conf.save() self.mainwindow.set_textlimit( server['textlimit'] ) def connect_dent(self,data,target_page,is_conv=False,conv_backwards=False,is_direct_dent=False): #make the dent dent = Dent(data,is_direct=is_direct_dent) if target_page.dentScroller.add_dent( dent, is_conv, conv_backwards ): dent.connect('group-clicked', self.view_group) dent.connect('reply-clicked', self.reply_clicked) dent.connect('direct-clicked', self.direct_clicked) dent.connect('view-conversation-clicked', self.view_conversation) dent.connect('user-clicked', self.view_user_name) dent.connect('profile-clicked', self.view_user_profile) dent.connect('id-clicked', self.view_id) dent.connect('text-label-clicked',self.dent_text_clicked) dent.connect('redent-clicked',self.redent_clicked) dent.connect('favorite-clicked',self.favorite_clicked) dent.connect('unfavorite-clicked',self.unfavorite_clicked) dent.connect('open-link',self.open_link) if target_page!=self.userpage: #get the image for this dent self.imagecache.add_image_to_widget(data['profile_image_url'],dent) return True else: dent.destroy() del dent return False def reply_clicked(self,dent,name): #set the text buffer self.mainwindow.update_textbuffer.set_text("@%s " % (name) ) self.mainwindow.update_textview.grab_focus() #set the respond_to_id self.respond_to_id=dent.id def favorite_clicked(self,dent): id=dent.id self.comm.favorite(id) def unfavorite_clicked(self,dent): id=dent.id self.comm.unfavorite(id) def direct_clicked(self,widget,name): self.direct_message_to = name if type(widget).__name__=="Dent": self.respond_to_id=widget.id else: self.respond_to_id=None self.set_is_direct_message_mode(True,name) #we should be on the directs page self.mainwindow.set_notebook_page(DIRECT) #set the text buffer self.mainwindow.update_textbuffer.set_text("") self.mainwindow.update_textview.grab_focus() def view_conversation(self,dent,id): self.conversation_id=id self.pre_context_page=self.mainwindow.notebook_current_page self.contextpage.dentScroller.clear() self.contextpage.show_all() #get conversation starting with id self.get_conversation(id,id) self.mainwindow.notebook.set_current_page(CONTEXT) def view_user_profile(self, widget, profile_url, screen_name): self.get_user_info(profile=profile_url, name=screen_name) #self.get_user_info(screen_name) self.pre_user_page=self.mainwindow.notebook_current_page #make the user page checkbox insensitive self.userpage.disable() #show the page self.userpage.show_all() #rehide its collapsed widgetbox, that doesn't need to be visible yet self.userpage.widgetbox_collapsed.hide() #clear the userpage stuff self.userpage.clear() #change to the user page self.mainwindow.set_notebook_page(USER) def view_id(self, widget, id): url = 'http://%s/notice/%s' % (self.conf.service(), id) self.open_link(None, url) def view_user_name(self, widget, screen_name): #TODO: merge this function with view_user_profile self.get_user_info(name=screen_name) #self.get_user_info(screen_name) self.pre_user_page=self.mainwindow.notebook_current_page #make the user page checkbox insensitive self.userpage.disable() #show the page self.userpage.show_all() #rehide its collapsed widgetbox, that doesn't need to be visible yet self.userpage.widgetbox_collapsed.hide() #clear the userpage stuff self.userpage.clear() #change to the user page self.mainwindow.set_notebook_page(USER) #does this function even get called? get rid of it def get_dent_time(self,text): #print text pass def markup_dent_text(self,text,is_notification=False): #process the text to markup #xmlencode the string text = self.xmlprocessor.xmlentities(text) #regex find the highlights markup = self.regex_tag.sub(r'\1#<b>\2</b>',text) #regex find users if has_hildon or links_unavailable or is_notification: markup = self.regex_group.sub(r'\1!<b>\2</b>',markup) markup = self.regex_user.sub(r'\1@<b>\2</b>',markup) else: #find urls markup = self.regex_url.sub(r'<a href="\1">\1</a>\2',markup) markup = self.regex_user.sub(r'\1@<a href="@\2">\2</a>',markup) markup = self.regex_group.sub(r'\1!<a href="!\2">\2</a>',markup) return markup def process_statusesXML(self,object,text,target_page,is_direct=False): #based on the target, what is the counting thingy? count_ref=None if target_page==self.dentspage: count_ref = "dent" elif target_page==self.mentionspage: count_ref = "mention" elif target_page==self.directspage: count_ref = "direct" self.decrement_requests() #set the "previous" count ref, do this now and get data twice if count_ref!=None: highest_id[count_ref+"_previous"] = highest_id[count_ref] #get a list of the statuses statuses = self.xmlprocessor.get_statuses(text,is_direct) #if there aren't any statuses, return if len(statuses)==0: return #reverse the statuses list statuses.reverse() dent_count=0 reply_count=0 #what is the highest id of the target index? for status in statuses: filtered_status = False data = self.xmlprocessor.get_dent_data(status) if target_page==self.dentspage: #we should check for filtration filtered = self.check_filtered( data ) filtered_status=filtered[0] if not filtered_status: #get the markup data['markup'] = self.markup_dent_text(data['text']) #did this dent connect if not self.connect_dent(data,target_page,is_direct_dent=is_direct): continue #if the target_page = 0 and not first_dents and not is_conf if target_page==self.dentspage and not self.is_first_dents: if "@"+self.conf.name() in data['markup']: dent=self.connect_dent(data, self.mentionspage ) reply_count+=1 if self.options['notify_replies'] and has_pynotify: user = data['screen_name'] #the message shouldn't be marked up if the server doesn't understand markup if notifier_reads_markup: message = self.markup_dent_text(data['text'],True) else: message = data['text'] avatar = self.imagecache.get_image_path(data['profile_image_url']) self.notify.notify_reply(user,message,avatar) else: dent_count+=1 else: self.log("filter #%s %s" %(data['status_id'], filtered[1] ) ) #keep track of the last status_id if count_ref!=None and data!=None: highest_id[count_ref]=data['status_id'] self.is_first_dents=False #get the related images self.imagecache.get_images() #do we notify? if (dent_count!=0 or reply_count!=0) and has_pynotify and target_page==self.dentspage: if self.options['notifications']: if not self.options['notify_replies']: self.notify.notify_updates_replies(dent_count,reply_count,self.standard_icon_path) else: if dent_count!=0: self.notify.notify_updates(dent_count,self.standard_icon_path) #prune off the extra dents target_page.dentScroller.prune(self.dent_limit) def process_widget_image(self,comm,data,name): self.imagecache.widget_image_add(data,name) def process_communication_exception(self,communicator,code,data,signal=None): if self.logging: self.log("code:%s, signal:%s" % (code,signal) ) self.decrement_requests() #is there an error message? try: error_message = self.xmlprocessor.get_error_message(data) except: error_message = False if error_message and not code: self.mainwindow.set_message( error_message, MainWindow.ERROR_MESSAGE) elif code=='401': #bad authorization self.mainwindow.set_notebook_page(MainWindow.ACCOUNT) error_message = _("Invalid Authorization: Your name or password is incorrect") elif code == '404': error_message = _("Service Not Found") elif code == '503': error_message = _("Service Unavailable") elif code == 'unknown error': error_message = _("Unknown Error") else: error_message = code #send the error message self.mainwindow.set_message(error_message, MainWindow.ERROR_MESSAGE) #a signal may have been passed from the comm if signal == "new-statusXML": #a dent was sent but it failed self.mainwindow.emit_update_textview_responsed(error=True) #functions to handle the filtration system def add_string_filter(self,winder,string): if not string in self.filters['strings']: self.filters['strings'].append(string) self.filters['strings'].sort() self.settingspage.set_string_filters( self.filters['strings'] ) def remove_string_filter(self,winder,string): if string in self.filters['strings']: self.filters['strings'].remove(string) self.settingspage.set_string_filters( self.filters['strings'] ) def add_user_filter(self,winder,user): if not user in self.filters['users']: self.filters['users'].append(user) self.filters['users'].sort() self.settingspage.set_user_filters( self.filters['users'] ) def remove_user_filter(self,winder,user): if user in self.filters['users']: self.filters['users'].remove(user) self.settingspage.set_user_filters( self.filters['users'] ) def check_filtered(self,data): if len(self.filters['users'])!=0 : #filter against the user for user in self.filters['users']: if data['screen_name'].lower()==user.lower(): return (True, "user: %s" % data['screen_name'] ) if len(self.filters['strings'])!=0: #filter against the strings #get the dent text text = data['text'] #loop through the filter strings for string in self.filters['strings']: if re.search(string,text, flags=re.IGNORECASE): return (True, "string: %s" % string ) #if we get this far, just return return (False, None) def status_clicked(self,widget): if self.window_is_hidden==True: self.window_is_hidden=False self.mainwindow.show() self.align_window() self.mainwindow.present() else: self.window_to_tray(widget) def window_size_allocate(self,widget,size): self.window_width = size[2] self.window_height = size[3] def save_app_info(self): #save the filters self.conf.set('settings','filters', self.filters ,True) #save the window info self.conf.set('window_info','width', self.window_width ) self.conf.set('window_info','height', self.window_height ) try: #some themes don't pass root origin? origin = self.mainwindow.window.get_root_origin() self.window_x = origin[0] self.window_y = origin[1] self.conf.set('window_info','x', self.window_x ) self.conf.set('window_info','y', self.window_y ) except: pass self.conf.save() def mainwindow_delete_event(self,window,event=None): self.save_app_info() #are we in tray mode? if self.conf.get_bool_option('run_as_tray_app') or self.has_status_icon: #is the status icon embedded? if self.statusicon.is_embedded(): self.window_is_hidden=True self.mainwindow.hide_on_delete() #do not propogate the signal return True else: #we need to quit self.quit_app() def quit_triggered(self,widget): self.save_app_info() self.quit_app() def option_changed(self,widget,value,option): #save the option change in the configuration self.conf.set('options',option,value) self.options[option]=value self.conf.save() #is this the run_tray_app: if option=='run_as_tray_app': if value: self.create_status_icon() else: self.destroy_status_icon() elif option=='no_avatars': self.imagecache.set_disabled(value) elif option=='ctrl_enter': self.mainwindow.set_ctrl_enter(value) def redent_clicked(self,dent,name,text): if self.options['api_retweet']: self.comm.send_redent(dent.id) else: self.respond_to_id=dent.id #formatted_text= u'\u267A @%s: %s' % (name,text) formatted_text= u'\u267A @%s: %s' % (name,text) self.mainwindow.update_textbuffer.set_text(formatted_text ) self.mainwindow.update_textview.grab_focus() def view_group(self,widget,group_name): #where were we? self.pre_group_page=self.mainwindow.notebook_current_page #make some flags self.grouppage.joined_checkbutton.set_sensitive(False) #make the grouppage visible self.grouppage.show_all() #rehide its collapsed widgetbox, that doesn't need to be visible yet self.grouppage.widgetbox_collapsed.hide() #clear the grouppage self.grouppage.clear() #switch to the group page self.mainwindow.set_notebook_page(GROUP) #get the group info self.get_group_info(group_name) def hide_contextpage(self,widget): #end any conversation in progress self.conversation_id="0" self.mainwindow.set_notebook_page( self.pre_context_page ) self.contextpage.hide() def hide_grouppage(self,widget): self.mainwindow.set_notebook_page( self.pre_group_page ) self.grouppage.hide() def hide_userpage(self,widget): self.mainwindow.set_notebook_page( self.pre_user_page ) self.userpage.hide() def dent_text_clicked(self,dent,text_label): self.mainwindow.last_clicked_label = text_label def clear_respond_to_id(self,widget=None): self.respond_to_id=0 def set_initial_dents(self,widget,value): self.initial_dents=value self.dent_limit = int(self.initial_dents)*2 self.conf.set('settings','initial_dents',value) def set_pull_time(self, widget,value): """A method for setting the time between pulls. obvious comment is obvious. Very possible everything will die now that I've added this. --Muel Kiel (aka samsnotunix)""" self.pull_time=value self.conf.set('settings','pull_time',value) self.pull_time_changed_bool = True self.pull_time_mentions = True def set_link_color(self,widget,string): self.conf.set('settings','link_color',string) self.theme_link_color(string) def theme_link_color(self,color): style=''' style "label" { GtkLabel::link-color="%s" } widget_class "*GtkLabel" style "label" ''' % (color) gtk.rc_parse_string(style) #f**k you GTK for not make this work, more than once! #functions for blocking/unblocking def block_create(self,widget,user_id): self.comm.block_create(user_id) def block_destroy(self,widget,user_id): self.comm.block_destroy(user_id) def set_is_direct_message_mode(self,mode,user=None): self.is_direct_message_mode=mode self.mainwindow.set_is_direct_message_mode(mode,user) if mode: self.default_icon_path=self.direct_icon_path else: self.default_icon_path=self.standard_icon_path #if we aren't waiting on any requests, swap the graphic if self.waiting_requests==0: try: self.mainwindow.set_icon_from_file(self.default_icon_path) except: pass try: self.mainwindow.set_throbber(self.default_icon_path) except: pass def simple_decrement(self,text=None,data=None): self.decrement_requests() ''' function window_to_tray sets the run_as_tray_app to true and minimizes the app ''' def window_to_tray(self,window): if self.options['run_as_tray_app']: self.mainwindow_delete_event(window) def open_link(self, widget, uri): webbrowser.open(uri) return True ''' command = "xdg-open '%s'" % ( uri ) #print command subprocess.Popen(command,shell=True) return True ''' def log(self,string): if self.logging: now = time.strftime("%H:%M:%S") file = os.path.join( os.path.expanduser("~"),"heybuddy.log") f = open(file,'a') f.write("%s %s\n" % (now,string) ) f.close()