Factored mytwitter into two modules to be cleaner

This commit is contained in:
Anna 2010-04-14 11:03:20 -04:00
parent 2f2a4d926d
commit bf23f6e3fc
2 changed files with 431 additions and 427 deletions

View File

@ -2,11 +2,11 @@
#
# Custom twitter client... mostly for learning Python
import sys, ConfigParser, os, re, subprocess
import datetime, dateutil.tz
import sys, ConfigParser, os, re
import twitter
import gtk, gtk.glade, gobject
from urllib2 import HTTPError
from twitterwidgets import TweetPane
class MyTwitter():
@ -227,431 +227,6 @@ class MyTwitter():
### end class MyTwitter
class TweetPane(gtk.ScrolledWindow):
'''
Box that holds all the TweetBoxes for a given feed
This box will not update itself, the parent should do that.
It will connect num_entries listeners to its parent's on_reply() and on_retweet()
It also gets some data from its parent, including num_entries
'''
def __init__(self, list_name, num_entries=20, single_tweet=None):
gtk.ScrolledWindow.__init__(self)
self.updated_once = False
self.single_tweet = single_tweet
self.list_name = list_name
self.tab_label = CloseTabLabel(self.list_name)
# These handle determining which tweets are unread
self.last_tweet_read = None
self.latest_tweet = None
self.num_new_tweets = 0
self.tweets = []
self.num_entries = num_entries
if self.single_tweet is not None:
self.num_entries = 1
self.init_widgets()
def init_widgets(self):
self.tab_label.connect('label_clicked', self.set_tweets_read_callback)
tweet_box = gtk.VBox()
viewport = gtk.Viewport()
# Build us some labels...
for i in range(0, self.num_entries):
self.tweets.append(TweetBox())
tweet_box.pack_start(self.tweets[i], expand=False)
self.tweets[i].connect('reply', self.on_tweet_reply)
self.tweets[i].connect('retweet', self.on_retweet)
self.tweets[i].connect('in-reply-to', self.on_tweet_reply_to)
viewport.add(tweet_box)
# Several different actions should mark the tweets as 'read'
self.connect('focus', self.set_tweets_read_callback)
viewport.connect('button_press_event', self.set_tweets_read_callback)
self.connect('scroll-event', self.set_tweets_read_callback)
self.connect('scroll-child', self.set_tweets_read_callback)
self.add(viewport)
self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self.show_all()
def update_window(self, raw_statuses, using_results=False):
if using_results:
statuses = self.statuses_from_results(raw_statuses)
else:
statuses = raw_statuses
if self.updated_once is False:
self.updated_once = True
# If this is our first load of this list, don't treat anything as new!
if self.last_tweet_read is None:
self.last_tweet_read = statuses[0].id
# Keep count of the new tweets for posting a status message
self.num_new_tweets = 0
for i in range(0, self.num_entries):
read = True
if i < len(statuses):
if statuses[i].id > self.last_tweet_read:
self.num_new_tweets += 1
read = False
self.tweets[i].set_status(statuses[i], read)
else:
self.tweets[i].clear_status()
self.latest_tweet = statuses[0].id
self.update_tab_label()
# Update the label with the number of unread tweets
def update_tab_label(self):
pane_text = self.list_name
if self.num_new_tweets > 0:
pane_text += ' (' + str(self.num_new_tweets) + ')'
self.tab_label.set_label_text(pane_text)
def get_list_name(self):
return self.list_name
def set_tweets_read(self):
self.last_tweet_read = self.latest_tweet
self.num_new_tweets = 0
self.update_tab_label()
def set_tweets_read_callback(self, event, arg1=None, arg2=None):
self.set_tweets_read()
def get_tab_label(self):
return self.tab_label
def get_single_tweet(self):
return self.single_tweet
def updated_once(self):
return self.updated_once
def on_tweet_reply(self, widget):
self.emit('tweet-reply', {'screen_name': widget.screen_name, 'id': widget.id})
def on_retweet(self, widget):
self.emit('tweet-retweet', {'id': widget.id})
def on_tweet_reply_to(self, widget, data):
self.emit('tweet-in-reply-to', data)
# To keep things simple elsewhere and improve code reuse
# we'll build a list of home-cooked Status objects out of results.
# Why is this even necessary?
# Why can't we have more consistency out of the Twitter API?
def statuses_from_results(self, results):
statuses = []
for result in results.results:
status = Status()
status.id = result.id
status.user = User()
status.user.screen_name = result.from_user
status.user.name = ""
status.in_reply_to_screen_name = result.to_user
# The Twitter Search API has different timestamps than the
# REST API... balls
# fixme:
# Gotta be a cleaner way to do this, but I can't think of it
# right now
created_at = re.sub(',', '', result.created_at)
created_split = re.split(' ', created_at)
status.created_at = created_split[0] + ' ' + created_split[2] + ' ' + created_split[1] + ' ' + created_split[4] + ' ' + created_split[5] + ' ' + created_split[3]
status.text = result.text
statuses.append(status)
return statuses
### end class TweetPane
# signals for TweetPane
gobject.signal_new("tweet-reply", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("tweet-retweet", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("tweet-in-reply-to", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
class TweetBox(gtk.VBox):
'''
GUI for displaying one tweet and associated buttons
Also stores the data necessary for replying or retweeting (id, screen name)
'''
def __init__(self):
gtk.VBox.__init__(self)
self.screen_name = None
self.id = None
self.in_reply_to_id = None
self.in_reply_to_screen_name = None
self.init_widgets()
def init_widgets(self):
## Build the header
self.header = gtk.Label()
label_eb = gtk.EventBox()
label_eb.add(self.header)
self.pack_start(label_eb)
# Set the header's properties
label_eb.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#ffffff"))
label_eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse("#8888ff"))
self.header.set_alignment(0.0, 0.0)
self.header.set_selectable(True)
self.header.set_line_wrap(True)
## Build the text
self.text = gtk.Label()
text_align = gtk.Alignment()
text_align.add(self.text)
self.text_eb = gtk.EventBox()
self.text_eb.add(text_align)
self.pack_start(self.text_eb)
# Set the text's properties
text_align.set_padding(2, 5, 10, 5)
self.text.set_alignment(0.0, 0.0)
self.text.set_selectable(True)
self.text.set_line_wrap(True)
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
self.text.connect('activate-link', self.on_url_clicked)
self.text.connect('button-press-event', self.on_mouse_clicked)
# Build the buttons
button_box_align = gtk.Alignment()
button_box_align.set_padding(0, 15, 0, 0)
button_box = gtk.HBox()
self.pack_start(button_box)
self.reply_to_button = gtk.Button("")
self.reply_to_button.set_relief(gtk.RELIEF_NONE)
button_box.pack_start(self.reply_to_button, expand=False)
self.reply_to_button.connect("clicked", self.on_in_reply_to_clicked)
reply_button = gtk.Button("Reply")
reply_button.set_relief(gtk.RELIEF_HALF)
button_box.pack_end(reply_button, expand=False)
reply_button.connect("clicked", self.on_reply_clicked)
retweet_button = gtk.Button("Retweet")
retweet_button.set_relief(gtk.RELIEF_HALF)
button_box.pack_end(retweet_button, expand=False)
retweet_button.connect("clicked", self.on_retweet_clicked)
def set_status(self, status, read=True):
self.set_read(read)
timezone = dateutil.tz.gettz()
time_format = "%Y.%m.%d %H:%M:%S %Z"
# Get the user object
user = status.user
# Get user's data for retweeting / replying
self.screen_name = user.screen_name
self.id = status.id
self.in_reply_to_id = status.in_reply_to_status_id
self.in_reply_to_screen_name = status.in_reply_to_screen_name
# ... and a formatted timestamp
timestamp = datetime.datetime.strptime(status.created_at, "%a %b %d %H:%M:%S +0000 %Y")
timestamp = timestamp.replace(tzinfo=dateutil.tz.gettz('UTC'))
timestring = timestamp.astimezone(timezone).strftime(time_format)
# Set the header
self.header.set_markup(user.name + " (" + user.screen_name + ") " + timestring)
# and the text
new_text = status.text
new_text = re.sub(r'&([^;]*?)( |$)', r'&amp;\1\2', new_text)
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
new_text = re.sub(r"(http://.*?)( |$)", r'<a href="\1">\1</a>\2', new_text)
self.text.set_markup(new_text)
# If this is in reply to something, set appropriate label
if self.in_reply_to_screen_name:
self.reply_to_button.set_label('in reply to ' + self.in_reply_to_screen_name)
def clear_status(self):
self.header.set_markup('')
self.text.set_markup('')
self.screen_name = None
self.id = None
self.set_read(True)
def set_read(self, read=True):
if read:
self.text_eb.modify_bg(gtk.STATE_NORMAL,
gtk.gdk.color_parse("#f2f1f0"))
else:
self.text_eb.modify_bg(gtk.STATE_NORMAL,
gtk.gdk.color_parse("#dbffdb"))
def on_reply_clicked(self, widget):
self.emit('reply')
def on_retweet_clicked(self, widget):
self.emit('retweet')
def on_in_reply_to_clicked(self, widget):
self.emit('in-reply-to', {'id': self.in_reply_to_id, 'name': self.in_reply_to_screen_name})
def on_mouse_clicked(self, widget, event):
if event.button == 1:
self.set_read(True)
# fixme: call on_url_clicked if there is an active uri
# Apparently, this must wait until pygtk 2.18
def on_url_clicked(self, widget):
# fixme: we're catching this signal just to debug why it doesn't get emitted
# seems to be related to EventBox?
print 'debug: on_url_clicked()'
return True
# end class TweetBox
# signals for TweetBox
gobject.signal_new("reply", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
gobject.signal_new("retweet", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
gobject.signal_new("in-reply-to", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
class CloseTabLabel(gtk.EventBox):
'''
This class holds a label and a button with an 'I' in it. This button causes the CloseTabLabel
to emit a clicked signal
'''
def __init__(self, name=None):
gtk.EventBox.__init__(self)
self.init_widgets(name)
# This code is still heinous, but at least it is
# isolated to its own class
def init_widgets(self, name):
#create a custom tab for notebook containing a
#label and a button with STOCK_ICON
tabBox = gtk.HBox(False, 2)
tabButton=gtk.Button()
tabButton.connect('clicked', self.on_clicked)
self.label = gtk.Label(name)
#Add a picture on a button
iconBox = gtk.HBox(False, 0)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_CLOSE,gtk.ICON_SIZE_MENU)
gtk.Button.set_relief(tabButton,gtk.RELIEF_NONE)
settings = gtk.Widget.get_settings(tabButton)
(w,h) = gtk.icon_size_lookup_for_settings(settings,gtk.ICON_SIZE_MENU)
gtk.Widget.set_size_request(tabButton, w + 4, h + 4);
iconBox.pack_start(image, True, False, 0)
tabButton.add(iconBox)
tabBox.pack_start(self.label, False)
tabBox.pack_start(tabButton, False)
self.connect('button-press-event', self.on_button_press)
# needed, otherwise even calling show_all on the notebook won't
# make the hbox contents appear.
tabBox.show_all()
self.add(tabBox)
def set_label_text(self, new_text):
self.label.set_text(new_text)
def on_clicked(self, event):
self.emit('close-clicked')
def on_button_press(self, event, direction):
self.emit('label-clicked')
### end class CloseTabLabel
# signals for CloseTabLabel
gobject.signal_new("close-clicked", CloseTabLabel,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
gobject.signal_new("label-clicked", CloseTabLabel,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
class Status():
def __init__(self):
self.user = User()
self.id = None
self.created_at = None
class User():
def __init__(self):
self.screen_name = None
self.name = None
# main

429
twitterwidgets.py Normal file
View File

@ -0,0 +1,429 @@
import re
import datetime, dateutil.tz
import gtk, gobject
class TweetPane(gtk.ScrolledWindow):
'''
Box that holds all the TweetBoxes for a given feed
This box will not update itself, the parent should do that.
It will connect num_entries listeners to its parent's on_reply() and on_retweet()
It also gets some data from its parent, including num_entries
'''
def __init__(self, list_name, num_entries=20, single_tweet=None):
gtk.ScrolledWindow.__init__(self)
self.updated_once = False
self.single_tweet = single_tweet
self.list_name = list_name
self.tab_label = CloseTabLabel(self.list_name)
# These handle determining which tweets are unread
self.last_tweet_read = None
self.latest_tweet = None
self.num_new_tweets = 0
self.tweets = []
self.num_entries = num_entries
if self.single_tweet is not None:
self.num_entries = 1
self.init_widgets()
def init_widgets(self):
self.tab_label.connect('label_clicked', self.set_tweets_read_callback)
tweet_box = gtk.VBox()
viewport = gtk.Viewport()
# Build us some labels...
for i in range(0, self.num_entries):
self.tweets.append(TweetBox())
tweet_box.pack_start(self.tweets[i], expand=False)
self.tweets[i].connect('reply', self.on_tweet_reply)
self.tweets[i].connect('retweet', self.on_retweet)
self.tweets[i].connect('in-reply-to', self.on_tweet_reply_to)
viewport.add(tweet_box)
# Several different actions should mark the tweets as 'read'
self.connect('focus', self.set_tweets_read_callback)
viewport.connect('button_press_event', self.set_tweets_read_callback)
self.connect('scroll-event', self.set_tweets_read_callback)
self.connect('scroll-child', self.set_tweets_read_callback)
self.add(viewport)
self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self.show_all()
def update_window(self, raw_statuses, using_results=False):
if using_results:
statuses = self.statuses_from_results(raw_statuses)
else:
statuses = raw_statuses
if self.updated_once is False:
self.updated_once = True
# If this is our first load of this list, don't treat anything as new!
if self.last_tweet_read is None:
self.last_tweet_read = statuses[0].id
# Keep count of the new tweets for posting a status message
self.num_new_tweets = 0
for i in range(0, self.num_entries):
read = True
if i < len(statuses):
if statuses[i].id > self.last_tweet_read:
self.num_new_tweets += 1
read = False
self.tweets[i].set_status(statuses[i], read)
else:
self.tweets[i].clear_status()
self.latest_tweet = statuses[0].id
self.update_tab_label()
# Update the label with the number of unread tweets
def update_tab_label(self):
pane_text = self.list_name
if self.num_new_tweets > 0:
pane_text += ' (' + str(self.num_new_tweets) + ')'
self.tab_label.set_label_text(pane_text)
def get_list_name(self):
return self.list_name
def set_tweets_read(self):
self.last_tweet_read = self.latest_tweet
self.num_new_tweets = 0
self.update_tab_label()
def set_tweets_read_callback(self, event, arg1=None, arg2=None):
self.set_tweets_read()
def get_tab_label(self):
return self.tab_label
def get_single_tweet(self):
return self.single_tweet
def updated_once(self):
return self.updated_once
def on_tweet_reply(self, widget):
self.emit('tweet-reply', {'screen_name': widget.screen_name, 'id': widget.id})
def on_retweet(self, widget):
self.emit('tweet-retweet', {'id': widget.id})
def on_tweet_reply_to(self, widget, data):
self.emit('tweet-in-reply-to', data)
# To keep things simple elsewhere and improve code reuse
# we'll build a list of home-cooked Status objects out of results.
# Why is this even necessary?
# Why can't we have more consistency out of the Twitter API?
def statuses_from_results(self, results):
statuses = []
for result in results.results:
status = Status()
status.id = result.id
status.user = User()
status.user.screen_name = result.from_user
status.user.name = ""
status.in_reply_to_screen_name = result.to_user
# The Twitter Search API has different timestamps than the
# REST API... balls
# fixme:
# Gotta be a cleaner way to do this, but I can't think of it
# right now
created_at = re.sub(',', '', result.created_at)
created_split = re.split(' ', created_at)
status.created_at = created_split[0] + ' ' + created_split[2] + ' ' + created_split[1] + ' ' + created_split[4] + ' ' + created_split[5] + ' ' + created_split[3]
status.text = result.text
statuses.append(status)
return statuses
### end class TweetPane
# signals for TweetPane
gobject.signal_new("tweet-reply", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("tweet-retweet", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("tweet-in-reply-to", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
class TweetBox(gtk.VBox):
'''
GUI for displaying one tweet and associated buttons
Also stores the data necessary for replying or retweeting (id, screen name)
'''
def __init__(self):
gtk.VBox.__init__(self)
self.screen_name = None
self.id = None
self.in_reply_to_id = None
self.in_reply_to_screen_name = None
self.init_widgets()
def init_widgets(self):
## Build the header
self.header = gtk.Label()
label_eb = gtk.EventBox()
label_eb.add(self.header)
self.pack_start(label_eb)
# Set the header's properties
label_eb.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#ffffff"))
label_eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse("#8888ff"))
self.header.set_alignment(0.0, 0.0)
self.header.set_selectable(True)
self.header.set_line_wrap(True)
## Build the text
self.text = gtk.Label()
text_align = gtk.Alignment()
text_align.add(self.text)
self.text_eb = gtk.EventBox()
self.text_eb.add(text_align)
self.pack_start(self.text_eb)
# Set the text's properties
text_align.set_padding(2, 5, 10, 5)
self.text.set_alignment(0.0, 0.0)
self.text.set_selectable(True)
self.text.set_line_wrap(True)
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
self.text.connect('activate-link', self.on_url_clicked)
self.text.connect('button-press-event', self.on_mouse_clicked)
# Build the buttons
button_box_align = gtk.Alignment()
button_box_align.set_padding(0, 15, 0, 0)
button_box = gtk.HBox()
self.pack_start(button_box)
self.reply_to_button = gtk.Button("")
self.reply_to_button.set_relief(gtk.RELIEF_NONE)
button_box.pack_start(self.reply_to_button, expand=False)
self.reply_to_button.connect("clicked", self.on_in_reply_to_clicked)
reply_button = gtk.Button("Reply")
reply_button.set_relief(gtk.RELIEF_HALF)
button_box.pack_end(reply_button, expand=False)
reply_button.connect("clicked", self.on_reply_clicked)
retweet_button = gtk.Button("Retweet")
retweet_button.set_relief(gtk.RELIEF_HALF)
button_box.pack_end(retweet_button, expand=False)
retweet_button.connect("clicked", self.on_retweet_clicked)
def set_status(self, status, read=True):
self.set_read(read)
timezone = dateutil.tz.gettz()
time_format = "%Y.%m.%d %H:%M:%S %Z"
# Get the user object
user = status.user
# Get user's data for retweeting / replying
self.screen_name = user.screen_name
self.id = status.id
self.in_reply_to_id = status.in_reply_to_status_id
self.in_reply_to_screen_name = status.in_reply_to_screen_name
# ... and a formatted timestamp
timestamp = datetime.datetime.strptime(status.created_at, "%a %b %d %H:%M:%S +0000 %Y")
timestamp = timestamp.replace(tzinfo=dateutil.tz.gettz('UTC'))
timestring = timestamp.astimezone(timezone).strftime(time_format)
# Set the header
self.header.set_markup(user.name + " (" + user.screen_name + ") " + timestring)
# and the text
new_text = status.text
new_text = re.sub(r'&([^;]*?)( |$)', r'&amp;\1\2', new_text)
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
new_text = re.sub(r"(http://.*?)( |$)", r'<a href="\1">\1</a>\2', new_text)
self.text.set_markup(new_text)
# If this is in reply to something, set appropriate label
if self.in_reply_to_screen_name:
self.reply_to_button.set_label('in reply to ' + self.in_reply_to_screen_name)
def clear_status(self):
self.header.set_markup('')
self.text.set_markup('')
self.screen_name = None
self.id = None
self.set_read(True)
def set_read(self, read=True):
if read:
self.text_eb.modify_bg(gtk.STATE_NORMAL,
gtk.gdk.color_parse("#f2f1f0"))
else:
self.text_eb.modify_bg(gtk.STATE_NORMAL,
gtk.gdk.color_parse("#dbffdb"))
def on_reply_clicked(self, widget):
self.emit('reply')
def on_retweet_clicked(self, widget):
self.emit('retweet')
def on_in_reply_to_clicked(self, widget):
self.emit('in-reply-to', {'id': self.in_reply_to_id, 'name': self.in_reply_to_screen_name})
def on_mouse_clicked(self, widget, event):
if event.button == 1:
self.set_read(True)
# fixme: call on_url_clicked if there is an active uri
# Apparently, this must wait until pygtk 2.18
def on_url_clicked(self, widget):
# fixme: we're catching this signal just to debug why it doesn't get emitted
# seems to be related to EventBox?
print 'debug: on_url_clicked()'
return True
# end class TweetBox
# signals for TweetBox
gobject.signal_new("reply", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
gobject.signal_new("retweet", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
gobject.signal_new("in-reply-to", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
class CloseTabLabel(gtk.EventBox):
'''
This class holds a label and a button with an 'I' in it. This button causes the CloseTabLabel
to emit a clicked signal
'''
def __init__(self, name=None):
gtk.EventBox.__init__(self)
self.init_widgets(name)
# This code is still heinous, but at least it is
# isolated to its own class
def init_widgets(self, name):
#create a custom tab for notebook containing a
#label and a button with STOCK_ICON
tabBox = gtk.HBox(False, 2)
tabButton=gtk.Button()
tabButton.connect('clicked', self.on_clicked)
self.label = gtk.Label(name)
#Add a picture on a button
iconBox = gtk.HBox(False, 0)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_CLOSE,gtk.ICON_SIZE_MENU)
gtk.Button.set_relief(tabButton,gtk.RELIEF_NONE)
settings = gtk.Widget.get_settings(tabButton)
(w,h) = gtk.icon_size_lookup_for_settings(settings,gtk.ICON_SIZE_MENU)
gtk.Widget.set_size_request(tabButton, w + 4, h + 4);
iconBox.pack_start(image, True, False, 0)
tabButton.add(iconBox)
tabBox.pack_start(self.label, False)
tabBox.pack_start(tabButton, False)
self.connect('button-press-event', self.on_button_press)
# needed, otherwise even calling show_all on the notebook won't
# make the hbox contents appear.
tabBox.show_all()
self.add(tabBox)
def set_label_text(self, new_text):
self.label.set_text(new_text)
def on_clicked(self, event):
self.emit('close-clicked')
def on_button_press(self, event, direction):
self.emit('label-clicked')
### end class CloseTabLabel
# signals for CloseTabLabel
gobject.signal_new("close-clicked", CloseTabLabel,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
gobject.signal_new("label-clicked", CloseTabLabel,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, ())
class Status():
def __init__(self):
self.user = User()
self.id = None
self.created_at = None
class User():
def __init__(self):
self.screen_name = None
self.name = None