This repository has been archived on 2019-12-04. You can view files and clone it, but cannot push or open issues or pull requests.
hrafn/twitterwidgets.py

876 lines
28 KiB
Python
Raw Normal View History

import re
import datetime, dateutil.tz
import gtk, gobject
from threading import RLock
from usercache import AvCache,NameCache
import webbrowser
import config
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, username, num_entries=20, single_tweet=None, is_user=False, conversation=False, is_dm=False):
gtk.ScrolledWindow.__init__(self)
# If the username is encoded in the tweet pane's name, we really want
# to use it instead, since it may not match the current api's name
if re.search(r'(^| ).*/', list_name):
self.username = re.sub(r'(list: | )?(.*?)/.*$', r'\2', list_name)
else:
self.username = username
self.list_name = list_name
self.single_tweet = single_tweet
2010-05-18 18:23:17 +00:00
self.conversation = conversation
self.num_entries = num_entries
2010-05-18 18:23:17 +00:00
self.is_user = is_user
self.following = False
self.verified = False
self.is_dm = is_dm
self.tab_label = CloseTabLabel(self.list_name)
self.message = gtk.Label('Loading...')
# These handle determining which tweets are unread
self.last_tweet_read = None
self.latest_tweet = None
self.num_new_tweets = 0
self.tweets = []
self.init_widgets()
def init_widgets(self):
2010-04-16 18:39:37 +00:00
self.tab_label.connect('label-clicked', self.set_tweets_read_callback)
tweet_box = gtk.VBox()
viewport = gtk.Viewport()
if self.is_user:
self.user_box = UserBox()
tweet_box.pack_start(self.user_box)
tweet_box.pack_start(self.message)
# Build us some labels...
for i in range(0, self.num_entries):
self.tweets.append(TweetBox(self.conversation, self.is_user, self.is_dm))
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)
self.tweets[i].connect('conversation', self.on_tweet_conversation)
self.tweets[i].connect('show-user', self.on_show_user)
2010-05-28 23:44:09 +00:00
self.tweets[i].connect('show-hashtag', self.on_show_hashtag)
self.tweets[i].connect('tweet-read', self.set_tweets_read_callback)
viewport.add(tweet_box)
# Several different actions should mark the tweets as 'read'
self.connect('focus', self.set_tweets_read_callback)
2010-04-16 18:39:37 +00:00
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()
for tweet in self.tweets:
tweet.hide()
if self.is_user:
self.user_box.hide_widgets()
2010-04-16 19:10:33 +00:00
def update_window(self, statuses):
if statuses is None:
if self.last_tweet_read is None:
self.message.set_label('An error occurred while fetching data')
self.message.show()
for i in range(0, self.num_entries):
self.tweets[i].hide()
if config.debug:
print 'Error fetching data for ' + self.tab_label
return
self.message.hide()
# If this is our first load of this list, don't treat anything as new!
if self.last_tweet_read is None:
2010-04-20 19:43:06 +00:00
try:
2010-05-18 18:23:17 +00:00
ids = [status.id for status in statuses]
ids.sort()
ids.reverse()
self.last_tweet_read = ids[0]
2010-04-20 19:43:06 +00:00
except IndexError:
self.last_tweet_read = 0
# 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:
read = False
if statuses[i].user.screen_name != self.username:
self.num_new_tweets += 1
self.tweets[i].set_status(statuses[i], read)
self.tweets[i].show()
else:
self.tweets[i].clear_status()
self.tweets[i].hide()
if self.num_new_tweets > 0:
2010-05-26 04:14:56 +00:00
self.emit('new-tweets')
if len(statuses) == 0:
self.message.set_label('There is no data to display')
2010-04-20 19:43:06 +00:00
try:
self.latest_tweet = statuses[0].id
except IndexError:
self.latest_tweet = 0
self.update_tab_label()
# Update the user_box with profile icon, name, etc...
# Thread calling this should have the gtk lock...
def update_user_info(self, user):
if self.is_user:
self.user_box.update_info(user)
# 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):
num_read = self.num_new_tweets
self.last_tweet_read = self.latest_tweet
self.num_new_tweets = 0
self.update_tab_label()
2010-05-26 04:14:56 +00:00
self.emit('tweets-read')
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
2010-05-18 18:23:17 +00:00
def get_conversation(self):
return self.conversation
def on_tweet_reply(self, widget):
if self.is_dm:
self.emit('tweet-reply-dm', widget.screen_name)
else:
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)
def on_tweet_conversation(self, widget, data):
self.emit('tweet-conversation', data)
def on_show_user(self, widget, data):
self.emit('show-user', data)
2010-05-28 23:44:09 +00:00
def on_show_hashtag(self, widget, data):
self.emit('show-hashtag', data)
def get_is_user(self):
return self.is_user
def set_lists(self, lists):
if not self.is_user:
return
self.user_box.set_lists(lists)
### 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-reply-dm", 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,))
gobject.signal_new("tweet-conversation", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("show-user", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
2010-05-28 23:44:09 +00:00
gobject.signal_new("show-hashtag", TweetPane,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("new-tweets", TweetPane,
gobject.SIGNAL_RUN_LAST,
2010-05-26 04:14:56 +00:00
gobject.TYPE_NONE, ())
gobject.signal_new("tweets-read", TweetPane,
gobject.SIGNAL_RUN_LAST,
2010-05-26 04:14:56 +00:00
gobject.TYPE_NONE, ())
class TweetBox(gtk.HBox):
'''
GUI for displaying one tweet and associated buttons
Also stores the data necessary for replying or retweeting (id, screen name)
'''
def __init__(self, conversation=False, is_user=False, is_dm=False):
gtk.HBox.__init__(self)
self.screen_name = None
self.id = None
self.in_reply_to_id = None
self.in_reply_to_screen_name = None
self.app_url = None
2010-05-18 18:23:17 +00:00
# Lets the tweetbox know if it is part of a conversation or not
self.conversation = conversation
self.is_user = is_user
self.is_dm = is_dm
self.init_widgets()
def init_widgets(self):
# Build the image
if not self.is_user:
self.avatar = gtk.Image()
self.avatar.set_alignment(0.0, 0.0)
2010-05-20 04:39:53 +00:00
self.avatar.set_padding(5, 5)
self.pack_start(self.avatar, expand=False, fill=False)
self.avatar.hide()
# Everything else goes in a VBox beside the image
text_box = gtk.VBox()
self.pack_start(text_box)
## Build the header
self.user_button = gtk.Button(use_underline=False)
2010-05-23 01:39:53 +00:00
user_button_eb = gtk.EventBox()
user_button_eb.add(self.user_button)
self.time_label = gtk.Label()
2010-05-23 01:39:53 +00:00
time_label_eb = gtk.EventBox()
time_label_eb.add(self.time_label)
self.app_button = gtk.Button(use_underline=False)
2010-05-23 01:39:53 +00:00
app_button_eb = gtk.EventBox()
app_button_eb.add(self.app_button)
self.via_label = gtk.Label(' via ')
2010-05-23 01:39:53 +00:00
via_label_eb = gtk.EventBox()
via_label_eb.add(self.via_label)
2010-05-23 01:39:53 +00:00
2010-05-23 01:01:28 +00:00
label_box = gtk.HBox()
2010-05-23 01:39:53 +00:00
label_box.pack_start(user_button_eb, expand=False)
label_box.pack_start(time_label_eb, expand=False)
label_box.pack_start(via_label_eb, expand=False)
label_box.pack_start(app_button_eb, expand=False)
2010-05-23 01:01:28 +00:00
text_box.pack_start(label_box)
# Set the header's properties
self.user_button.set_relief(gtk.RELIEF_NONE)
self.user_button.set_alignment(0.0, 0.0)
2010-05-23 01:39:53 +00:00
user_button_eb.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#ffffff"))
user_button_eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse("#8888ff"))
2010-05-23 00:44:49 +00:00
self.time_label.set_alignment(0.0, 0.5)
2010-05-23 01:39:53 +00:00
time_label_eb.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#ffffff"))
time_label_eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse("#8888ff"))
self.via_label.set_alignment(0.0, 0.5)
2010-05-23 01:39:53 +00:00
via_label_eb.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#ffffff"))
via_label_eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse("#8888ff"))
self.app_button.set_relief(gtk.RELIEF_NONE)
self.app_button.set_alignment(0.0, 0.0)
2010-05-23 01:39:53 +00:00
app_button_eb.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#ffffff"))
app_button_eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse("#8888ff"))
# Handle the header buttons being clicked
if self.is_user:
self.user_button.set_sensitive(False)
else:
self.user_button.connect('clicked', self.on_user_clicked)
self.app_button.connect('clicked', self.on_app_button_clicked)
## 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)
text_box.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)
self.text_eb.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()
text_box.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)
self.reply_to_button.hide()
2010-05-18 18:23:17 +00:00
self.conversation_button = gtk.Button("(conversation)")
self.conversation_button.set_relief(gtk.RELIEF_NONE)
button_box.pack_start(self.conversation_button, expand=False)
self.conversation_button.connect("clicked", self.on_conversation_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)
if not self.is_dm:
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):
# To avoid leftover data when reusing
self.clear_status()
2010-05-17 21:31:42 +00:00
# Set avatar
if not self.is_user:
try:
with AvCache().lock:
image = AvCache().map[status.user.screen_name]
self.avatar.set_from_pixbuf(image)
self.avatar.show()
except KeyError:
self.avatar.hide()
try:
with NameCache().lock:
name = NameCache().map[status.user.screen_name]
except KeyError:
name = status.user.name
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
if status.source is not None:
source = status.source
if re.match(r'&lt;', source):
metalabel = gtk.Label()
metalabel.set_markup(status.source)
source = metalabel.get_text()
self.app_url = re.sub(r'.*<a href=\"(.*?)\".*', r'\1', source)
app_name = re.sub(r'.*<a.*?>(.*)</a>.*', r'\1', source)
self.app_button.set_label(app_name)
self.app_button.show()
self.via_label.show()
else:
self.app_button.hide()
self.via_label.hide()
self.app_url = ''
if re.match('/', self.app_url):
self.app_url = 'http://twitter.com' + self.app_url
elif re.match('web', self.app_url):
self.app_url = None
self.time_label.set_label(timestring)
if self.is_user:
self.user_button.set_label('')
else:
self.user_button.set_label(name + " (" + user.screen_name + ") ")
### and the text
new_text = status.text
# Clean up odd characters in the text
new_text = re.sub(r'&(?=[^;]*?( |&|$))', r'&amp;', new_text)
new_text = re.sub(r'"(?=[^;]*?( |"|$))', r'&quot;', new_text)
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
2010-05-28 23:44:09 +00:00
# Make URLs into links
new_text = re.sub(r"(http://.*?)(?=[^0-9a-zA-Z.~/_?=&;-]|$)", r'<a href="\1">\1</a>', new_text)
2010-05-28 23:44:09 +00:00
# Make @ or # refs into links, to be used internally
new_text = re.sub(r'@(.*?)([^0-9a-zA-Z_]|$)', self._make_user_link, new_text)
2010-06-07 13:45:12 +00:00
new_text = re.sub(r'#(.*?)([ ;,.:*]|$)', self._make_hashtag_link, new_text)
self.text.set_markup(new_text)
# If this is in reply to something, set appropriate label
2010-05-18 18:23:17 +00:00
if not self.conversation and self.in_reply_to_screen_name and self.in_reply_to_id:
self.reply_to_button.set_label('in reply to ' + self.in_reply_to_screen_name)
self.reply_to_button.show()
self.conversation_button.show()
def clear_status(self):
self.user_button.set_label('')
self.time_label.set_label('')
self.app_button.set_label('')
self.text.set_markup('')
self.screen_name = None
self.id = None
self.set_read(True)
self.reply_to_button.set_label('')
self.reply_to_button.hide()
self.conversation_button.hide()
if not self.is_user:
self.avatar.hide()
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.set_read()
self.emit('reply')
self.emit('tweet-read')
def on_retweet_clicked(self, widget):
self.set_read()
self.emit('retweet')
self.emit('tweet-read')
def on_in_reply_to_clicked(self, widget):
self.set_read()
self.emit('in-reply-to', {'id': self.in_reply_to_id, 'name': self.in_reply_to_screen_name})
self.emit('tweet-read')
def on_conversation_clicked(self, widget):
self.set_read()
self.emit('conversation', {'id': self.id, 'name': 'conversation'})
self.emit('tweet-read')
def on_user_clicked(self, widget):
self.set_read()
self.emit('show-user', self.screen_name)
self.emit('tweet-read')
def on_app_button_clicked(self, widget):
self.set_read()
if self.app_url:
webbrowser.open(self.app_url)
def on_mouse_clicked(self, widget, event):
if event.button == 1:
self.set_read(True)
self.emit('tweet-read')
def on_url_clicked(self, widget, uri):
self.set_read()
self.emit('tweet-read')
if re.match(r'@', uri):
self.emit('show-user', re.sub(r'@', '', uri))
return True
2010-05-28 23:44:09 +00:00
if re.match(r'#', uri):
self.emit('show-hashtag', re.sub(r'#', '', uri))
return True
def _make_user_link(self, matchobj):
name = matchobj.group(1)
if name == '':
return '@' + matchobj.group(2)
else:
return '@<a href="@' + name + '">' + name + '</a>' + matchobj.group(2)
2010-05-28 23:44:09 +00:00
def _make_hashtag_link(self, matchobj):
name = matchobj.group(1)
if name == '':
return '#' + matchobj.group(2)
else:
return '<a href="#' + name + '">#' + name + '</a>' + matchobj.group(2)
# 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("tweet-read", 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,))
gobject.signal_new("conversation", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("show-user", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
2010-05-28 23:44:09 +00:00
gobject.signal_new("show-hashtag", TweetBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
class UserBox(gtk.VBox):
def __init__(self):
gtk.VBox.__init__(self)
self.data_lock = RLock()
self.user_name = None
self.following = False
self.verified = False
self.info_loaded = False
self.init_widgets()
def init_widgets(self):
self.name_label = gtk.Label()
self.avatar = gtk.Image()
2010-05-20 04:39:53 +00:00
self.avatar.set_padding(5, 5)
self.follow_button = gtk.Button()
self.at_button = gtk.Button('@')
self.follow_label = gtk.Label('You are following this user')
self.verified_label = gtk.Label('Verified account')
self.list_box = gtk.combo_box_entry_new_text()
self.list_label = gtk.Label('')
self.list_box.append_text('add to list')
self.list_box.set_active(0)
self.list_box.connect('changed', self.on_add_to_list)
self.name_label.set_alignment(0.0, 0.0)
self.follow_label.set_alignment(0.0, 0.0)
self.verified_label.set_alignment(0.0, 0.0)
self.list_label.set_alignment(0.0, 0.0)
2010-05-20 04:35:13 +00:00
text_col = gtk.VBox()
text_col.pack_start(self.name_label, expand=False)
text_col.pack_start(self.verified_label, expand=False)
text_col.pack_start(self.follow_label, expand=False)
text_col.pack_start(self.list_label, expand=False)
2010-05-20 04:35:13 +00:00
info_row = gtk.HBox()
info_row.pack_start(self.avatar, expand=False)
info_row.pack_start(text_col, expand=False)
button_row = gtk.HBox()
button_row.pack_start(self.follow_button, expand=False)
button_row.pack_start(self.at_button, expand=False)
button_row.pack_start(self.list_box, expand=False)
2010-05-20 04:35:13 +00:00
self.pack_start(info_row, expand=False)
self.pack_start(button_row, expand=False)
self.at_button.connect('clicked', self.on_at_clicked)
self.follow_button.connect('clicked', self.on_follow_clicked)
self.show_all()
def update_info(self, user):
self.user_name = user.screen_name
name = ''
try:
with AvCache().lock:
image = AvCache().map[user.screen_name]
self.avatar.set_from_pixbuf(image)
self.avatar.show()
except KeyError:
self.avatar.hide()
try:
with NameCache().lock:
name = NameCache().map[user.screen_name]
except KeyError:
name = user.name
self.name_label.set_text(name + ' (' + self.user_name + ')')
with self.data_lock:
self.verified = user.verified
if self.verified:
self.verified_label.show()
else:
self.verified_label.hide()
if self.following:
self.follow_label.show()
else:
self.follow_label.hide()
self.name_label.show()
self.avatar.show()
self.at_button.show()
self.follow_button.show()
self.list_box.show()
if self.list_label.get_text() != '':
self.list_label.show()
self.info_loaded = True
def on_follow_clicked(self, event):
if self.following:
follow = False # destroy the friendship
else:
follow = True
self.emit('follow-clicked', follow)
def on_at_clicked(self, widget):
self.emit('at-clicked', self.user_name)
def get_following(self):
with self.data_lock:
return self.following
def get_verified(self):
with self.data_lock:
return self.verified
def set_following(self, following):
with self.data_lock:
self.following = following
if following:
self.follow_button.set_label('Unfollow')
if self.info_loaded:
self.follow_label.show()
else:
self.follow_button.set_label('Follow')
self.follow_label.hide()
# Hide widgets until update_user_info is done
def hide_widgets(self):
self.at_button.hide()
self.follow_button.hide()
self.follow_label.hide()
self.verified_label.hide()
self.name_label.hide()
self.avatar.hide()
2010-06-02 21:07:12 +00:00
self.list_label.hide()
self.list_box.hide()
def set_lists(self, lists):
if not lists:
return
2010-06-02 21:07:12 +00:00
list_label_text = 'Lists: '
for l in lists:
list_label_text += l + ' '
self.list_label.set_text(list_label_text)
def list_added(self, new_list):
pass
# fixme: this should add the list to the text field, and remove it
# from the combo box
def on_add_to_list(self, widget):
if widget.get_active_text() == 'add to list':
return
self.emit('add-to-list', widget.get_active_text())
widget.set_active(0)
# end class UserBox
# signals for UserBox
gobject.signal_new("add-to-list", UserBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("follow-clicked", UserBox,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("at-clicked", UserBox,
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 modified from create_custom_tab in:
# http://www.daa.com.au/pipermail/pygtk/2006-April/012216.html
#
# My version of this code is a little 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(use_underline=False)
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, ())