2010-04-07 03:05:51 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Custom twitter client... mostly for learning Python
|
|
|
|
|
2010-04-10 17:21:52 +00:00
|
|
|
import sys, twitter, ConfigParser, os, datetime, dateutil.tz, gtk, gtk.glade, gobject, re, subprocess
|
2010-04-07 03:05:51 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
class MyTwitter():
|
2010-04-07 03:05:51 +00:00
|
|
|
|
|
|
|
""" Display Tweets, post to twitter """
|
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
# Precompile a regex for searching for @ at the beginning of a string
|
|
|
|
at_check = re.compile('^@')
|
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def __init__(self):
|
2010-04-07 17:17:21 +00:00
|
|
|
config = ConfigParser.ConfigParser()
|
|
|
|
config.read(os.path.expanduser("~/.mytwitter"))
|
|
|
|
self.username = config.get('global', 'username')
|
|
|
|
self.password = config.get('global', 'password')
|
2010-04-08 21:07:27 +00:00
|
|
|
|
2010-04-07 18:47:16 +00:00
|
|
|
self.num_entries = int(config.get('global', 'entries'))
|
2010-04-08 21:07:27 +00:00
|
|
|
|
2010-04-07 18:47:16 +00:00
|
|
|
self.refresh_time = int(config.get('global', 'refreshtime'))
|
2010-04-08 21:07:27 +00:00
|
|
|
if self.refresh_time < 10:
|
|
|
|
self.refresh_time = 10
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-09 04:56:51 +00:00
|
|
|
self.reply_id = None
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
# Authenticate with twitter, set up the API object
|
|
|
|
self.api = twitter.Api(username=self.username, password=self.password)
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
# Load up all the GUI stuff
|
|
|
|
self.init_user_interface('./default.glade')
|
|
|
|
self.init_widgets()
|
2010-04-08 19:12:57 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def init_user_interface(self, path_to_skin):
|
|
|
|
self.widget_tree=gtk.glade.XML(path_to_skin, "window")
|
|
|
|
self.widget_tree.signal_autoconnect(self)
|
2010-04-08 19:12:57 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def init_widgets(self):
|
2010-04-12 18:11:27 +00:00
|
|
|
# Get widgets from glade
|
|
|
|
self.tweet_notebook = self.widget_tree.get_widget('tweet_notebook')
|
|
|
|
self.view_menu = self.widget_tree.get_widget('view_menu')
|
2010-04-08 20:39:56 +00:00
|
|
|
self.update_entry = self.widget_tree.get_widget('update_entry')
|
|
|
|
self.update_count = self.widget_tree.get_widget('update_count')
|
2010-04-11 05:37:09 +00:00
|
|
|
self.status_bar = self.widget_tree.get_widget('status_bar')
|
2010-04-12 21:58:00 +00:00
|
|
|
self.search_entry = self.widget_tree.get_widget('search_entry')
|
|
|
|
|
2010-04-11 05:44:44 +00:00
|
|
|
self.context_id = self.status_bar.get_context_id('message')
|
2010-04-07 17:21:55 +00:00
|
|
|
|
2010-04-12 18:11:27 +00:00
|
|
|
self.tweet_notebook.remove_page(0) # kill the page that glade makes us have
|
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
# When we change tabs, any unread tweets in it become read
|
|
|
|
self.tweet_notebook.connect('switch_page', self.on_tab_change)
|
|
|
|
|
2010-04-12 18:11:27 +00:00
|
|
|
# Add the Home tab to the notebook
|
2010-04-12 21:58:00 +00:00
|
|
|
self.add_to_notebook('Home')
|
2010-04-08 20:39:56 +00:00
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
# Put Home, @user, and lists in the View menu...
|
2010-04-08 21:07:27 +00:00
|
|
|
lists = self.api.GetUserLists()
|
2010-04-11 04:45:41 +00:00
|
|
|
list_names = []
|
2010-04-08 21:07:27 +00:00
|
|
|
for l in lists['lists']:
|
2010-04-11 04:45:41 +00:00
|
|
|
list_names.append(l.name)
|
|
|
|
list_names.sort()
|
2010-04-12 18:50:04 +00:00
|
|
|
list_names.insert(0, 'Home')
|
|
|
|
list_names.insert(1, '@' + self.username)
|
2010-04-11 04:45:41 +00:00
|
|
|
for l in list_names:
|
2010-04-12 18:50:04 +00:00
|
|
|
menu_item = gtk.MenuItem(l)
|
|
|
|
self.view_menu.append(menu_item)
|
|
|
|
menu_item.connect('activate', self.on_view_selected, l)
|
|
|
|
menu_item.show()
|
2010-04-08 21:07:27 +00:00
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
# Timer to update periodically
|
2010-04-12 18:50:04 +00:00
|
|
|
self.update_windows()
|
|
|
|
gobject.timeout_add(self.refresh_time * 1000, self.update_windows)
|
2010-04-08 19:12:57 +00:00
|
|
|
|
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
def update_windows(self):
|
2010-04-12 19:19:09 +00:00
|
|
|
for i in range(0, self.tweet_notebook.get_n_pages()):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(i)
|
2010-04-12 18:50:04 +00:00
|
|
|
list_name = pane.get_list_name()
|
2010-04-08 21:07:27 +00:00
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
if list_name is None or list_name == 'Home':
|
|
|
|
statuses = self.api.GetHomeTimeline(count=self.num_entries)
|
|
|
|
elif list_name == '@' + self.username:
|
|
|
|
statuses = self.api.GetMentions(count=self.num_entries)
|
2010-04-12 21:58:00 +00:00
|
|
|
elif re.match(r'user: ', list_name):
|
|
|
|
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', list_name), count=self.num_entries)
|
|
|
|
elif re.match(r'#', list_name):
|
2010-04-12 21:27:15 +00:00
|
|
|
statuses = self.api.Search(list_name, rpp=self.num_entries)
|
2010-04-12 18:50:04 +00:00
|
|
|
else:
|
|
|
|
statuses = self.api.GetListStatuses(list_name, per_page=self.num_entries)
|
2010-04-12 20:53:03 +00:00
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
pane.update_window(statuses)
|
2010-04-11 05:37:09 +00:00
|
|
|
|
2010-04-12 20:53:03 +00:00
|
|
|
# Update the label with the number of unread tweets
|
|
|
|
pane_text = list_name
|
|
|
|
if pane.get_num_new_tweets() > 0:
|
|
|
|
pane_text += ' (' + str(pane.get_num_new_tweets()) + ')'
|
|
|
|
self.tweet_notebook.get_tab_label(pane).set_label_text(pane_text)
|
|
|
|
|
2010-04-12 21:21:14 +00:00
|
|
|
# We have to return true, so the timeout_add event will keep happening
|
|
|
|
return True
|
|
|
|
|
2010-04-07 18:17:57 +00:00
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
def update_windows_callback(self, widget):
|
|
|
|
self.update_windows()
|
2010-04-08 21:07:27 +00:00
|
|
|
|
|
|
|
|
2010-04-07 18:17:57 +00:00
|
|
|
def update_status(self):
|
2010-04-08 20:39:56 +00:00
|
|
|
text = self.update_entry.get_text()
|
2010-04-08 21:07:27 +00:00
|
|
|
self.update_entry.set_text("")
|
2010-04-09 05:08:32 +00:00
|
|
|
self.api.PostUpdate(text, in_reply_to_status_id=self.reply_id)
|
|
|
|
self.reply_id = None
|
2010-04-11 05:44:44 +00:00
|
|
|
self.status_bar.push(self.context_id, 'Tweet Posted')
|
2010-04-07 18:17:57 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def update_status_callback(self, widget):
|
2010-04-07 18:17:57 +00:00
|
|
|
self.update_status()
|
2010-04-07 18:07:26 +00:00
|
|
|
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
def text_watcher(self, widget):
|
|
|
|
''' Watch text entered on the update_entry, update things '''
|
|
|
|
text_len = self.update_entry.get_text_length()
|
|
|
|
new_count = str(text_len) + "/140"
|
2010-04-08 20:39:56 +00:00
|
|
|
self.update_count.set_label(new_count)
|
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
# If reply_id is set, unset it if we have removed the @ symbol
|
|
|
|
if self.reply_id is not None and not MyTwitter.at_check.match(self.update_entry.get_text()):
|
|
|
|
self.reply_id = None
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
|
|
|
|
def gtk_main_quit(self, widget):
|
|
|
|
gtk.main_quit()
|
|
|
|
|
|
|
|
|
|
|
|
def on_about(self, widget):
|
2010-04-09 21:45:21 +00:00
|
|
|
print "STUB: help->about not yet implemented"
|
2010-04-08 19:12:57 +00:00
|
|
|
|
2010-04-07 19:54:54 +00:00
|
|
|
|
2010-04-09 05:08:32 +00:00
|
|
|
def on_reply(self, widget):
|
|
|
|
self.update_entry.set_text('@' + widget.screen_name + ' ')
|
|
|
|
self.reply_id = widget.id
|
2010-04-09 21:45:21 +00:00
|
|
|
self.update_entry.grab_focus()
|
2010-04-09 04:56:51 +00:00
|
|
|
|
|
|
|
|
2010-04-09 05:08:32 +00:00
|
|
|
def on_retweet(self, widget):
|
2010-04-10 14:46:51 +00:00
|
|
|
self.api.PostRetweet(widget.id)
|
2010-04-09 04:56:51 +00:00
|
|
|
|
2010-04-12 01:14:24 +00:00
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
def on_view_selected(self, event, name):
|
2010-04-12 19:19:09 +00:00
|
|
|
# If it already exists, don't add it, just switch to it
|
|
|
|
for i in range(self.tweet_notebook.get_n_pages()):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(i)
|
|
|
|
if pane.get_list_name() == name:
|
|
|
|
self.tweet_notebook.set_current_page(i)
|
|
|
|
return
|
|
|
|
|
|
|
|
# Now, add a new tab with this list
|
2010-04-12 21:58:00 +00:00
|
|
|
self.add_to_notebook(name)
|
2010-04-12 19:19:09 +00:00
|
|
|
|
|
|
|
# And, to propagate it:
|
|
|
|
self.update_windows()
|
2010-04-12 18:50:04 +00:00
|
|
|
|
2010-04-12 19:34:45 +00:00
|
|
|
|
|
|
|
# Remove one of the views from the tweet notebook.
|
|
|
|
# Called when the close button is clicked on one of the views
|
|
|
|
def remove_view(self, event, name):
|
|
|
|
for i in range(self.tweet_notebook.get_n_pages()):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(i)
|
|
|
|
if (pane.get_list_name() == name):
|
|
|
|
self.tweet_notebook.remove_page(i)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# This code modified from create_custom_tab in:
|
|
|
|
# http://www.daa.com.au/pipermail/pygtk/2006-April/012216.html
|
2010-04-12 21:58:00 +00:00
|
|
|
def add_to_notebook(self, name):
|
|
|
|
new_pane = TweetPane(name, self)
|
|
|
|
|
2010-04-12 20:31:38 +00:00
|
|
|
tab_label = CloseTabLabel(name)
|
2010-04-12 21:58:00 +00:00
|
|
|
self.tweet_notebook.append_page(new_pane, tab_label)
|
2010-04-12 20:31:38 +00:00
|
|
|
tab_label.connect('clicked', self.remove_view, name)
|
2010-04-12 20:53:03 +00:00
|
|
|
self.tweet_notebook.set_current_page(-1) # switch to the new pane
|
2010-04-12 19:34:45 +00:00
|
|
|
|
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
def on_tab_change(self, event, page, page_num):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(page_num)
|
|
|
|
tab_label = self.tweet_notebook.get_tab_label(pane)
|
|
|
|
|
|
|
|
pane.set_tweets_read()
|
|
|
|
tab_label.set_label_text(pane.get_list_name())
|
|
|
|
|
2010-04-12 21:58:00 +00:00
|
|
|
|
|
|
|
def on_search(self, event):
|
|
|
|
search_string = self.search_entry.get_text()
|
|
|
|
self.search_entry.set_text('')
|
|
|
|
if re.match(r'#', search_string):
|
|
|
|
self.add_to_notebook(search_string)
|
|
|
|
else:
|
|
|
|
# Assume this is a user name we want to lookup
|
|
|
|
self.add_to_notebook('user: ' + search_string)
|
|
|
|
|
|
|
|
self.update_windows()
|
|
|
|
|
|
|
|
|
2010-04-09 04:56:51 +00:00
|
|
|
### end class MyTwitter
|
|
|
|
|
|
|
|
|
2010-04-12 18:11:27 +00:00
|
|
|
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, mytwitter):
|
|
|
|
gtk.ScrolledWindow.__init__(self)
|
|
|
|
|
|
|
|
self.list_name = list_name
|
|
|
|
self.mytwitter = mytwitter
|
|
|
|
|
|
|
|
# These handle determining which tweets are unread
|
|
|
|
self.last_tweet_read = None
|
|
|
|
self.latest_tweet = None
|
2010-04-12 20:31:38 +00:00
|
|
|
self.num_new_tweets = 0
|
2010-04-12 18:11:27 +00:00
|
|
|
|
|
|
|
self.tweets = []
|
|
|
|
|
|
|
|
self.init_widgets()
|
|
|
|
|
|
|
|
|
|
|
|
def init_widgets(self):
|
|
|
|
tweet_box = gtk.VBox()
|
|
|
|
viewport = gtk.Viewport()
|
|
|
|
|
|
|
|
# Build us some labels...
|
|
|
|
for i in range(0, self.mytwitter.num_entries):
|
|
|
|
self.tweets.append(TweetBox())
|
|
|
|
tweet_box.pack_start(self.tweets[i])
|
|
|
|
self.tweets[i].connect('reply', self.mytwitter.on_reply)
|
|
|
|
self.tweets[i].connect('retweet', self.mytwitter.on_retweet)
|
|
|
|
|
|
|
|
viewport.add(tweet_box)
|
2010-04-12 20:53:03 +00:00
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
# 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)
|
2010-04-12 20:53:03 +00:00
|
|
|
|
2010-04-12 18:11:27 +00:00
|
|
|
self.add(viewport)
|
|
|
|
self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
2010-04-12 18:28:39 +00:00
|
|
|
self.show_all()
|
2010-04-12 18:11:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
def update_window(self, statuses):
|
|
|
|
# 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
|
2010-04-12 20:31:38 +00:00
|
|
|
self.num_new_tweets = 0
|
2010-04-12 18:11:27 +00:00
|
|
|
|
|
|
|
for i in range(0, self.mytwitter.num_entries):
|
|
|
|
read = True
|
|
|
|
if i < len(statuses):
|
|
|
|
if statuses[i].id > self.last_tweet_read:
|
2010-04-12 20:31:38 +00:00
|
|
|
self.num_new_tweets += 1
|
2010-04-12 18:11:27 +00:00
|
|
|
read = False
|
|
|
|
self.tweets[i].set_status(statuses[i], read)
|
|
|
|
else:
|
|
|
|
self.tweets[i].clear_status()
|
|
|
|
|
|
|
|
self.latest_tweet = statuses[0].id
|
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
|
|
|
|
def get_list_name(self):
|
|
|
|
return self.list_name
|
|
|
|
|
2010-04-12 19:19:09 +00:00
|
|
|
|
|
|
|
def set_tweets_read(self):
|
|
|
|
self.last_tweet_read = self.latest_tweet
|
2010-04-12 20:53:03 +00:00
|
|
|
self.num_new_tweets = 0
|
2010-04-12 19:19:09 +00:00
|
|
|
|
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
def set_tweets_read_callback(self, event, arg1=None, arg2=None):
|
|
|
|
self.set_tweets_read()
|
2010-04-12 20:31:38 +00:00
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
|
2010-04-12 20:31:38 +00:00
|
|
|
def get_num_new_tweets(self):
|
|
|
|
return self.num_new_tweets
|
|
|
|
|
2010-04-12 18:11:27 +00:00
|
|
|
### end class TweetPane
|
|
|
|
|
|
|
|
|
2010-04-09 04:56:51 +00:00
|
|
|
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.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)
|
2010-04-12 01:07:37 +00:00
|
|
|
self.text_eb = gtk.EventBox()
|
|
|
|
self.text_eb.add(text_align)
|
|
|
|
self.pack_start(self.text_eb)
|
2010-04-09 04:56:51 +00:00
|
|
|
|
|
|
|
# Set the text's properties
|
|
|
|
text_align.set_padding(2, 10, 3, 0)
|
|
|
|
self.text.set_alignment(0.0, 0.0)
|
|
|
|
self.text.set_selectable(True)
|
|
|
|
self.text.set_line_wrap(True)
|
2010-04-12 00:01:45 +00:00
|
|
|
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
|
2010-04-11 04:21:18 +00:00
|
|
|
self.text.connect('activate-link', self.on_url_clicked)
|
2010-04-09 04:56:51 +00:00
|
|
|
|
|
|
|
button_box = gtk.HBox()
|
|
|
|
self.pack_start(button_box)
|
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
reply_button = gtk.Button("Reply")
|
|
|
|
button_box.pack_start(reply_button, expand=False)
|
|
|
|
reply_button.connect("clicked", self.on_reply_clicked)
|
|
|
|
retweet_button = gtk.Button("Retweet")
|
|
|
|
button_box.pack_start(retweet_button, expand=False)
|
|
|
|
retweet_button.connect("clicked", self.on_retweet_clicked)
|
2010-04-09 04:56:51 +00:00
|
|
|
|
|
|
|
|
2010-04-12 01:07:37 +00:00
|
|
|
def set_status(self, status, read=True):
|
|
|
|
self.set_read(read)
|
|
|
|
|
2010-04-09 04:56:51 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
# ... 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
|
2010-04-10 02:03:21 +00:00
|
|
|
new_text = status.text
|
2010-04-11 04:22:37 +00:00
|
|
|
new_text = re.sub(r'&([^;]*?)( |$)', r'&\1\2', new_text)
|
2010-04-12 00:01:45 +00:00
|
|
|
if gtk.gtk_version[0] > 2 or (gtk.gtk_version[0] == 2 and gtk.gtk_version[1] >= 18):
|
2010-04-11 04:21:18 +00:00
|
|
|
new_text = re.sub(r"(http://.*?)( |$)", r'<a href="\1">\1</a>\2', new_text)
|
2010-04-10 02:03:21 +00:00
|
|
|
self.text.set_markup(new_text)
|
2010-04-09 21:45:21 +00:00
|
|
|
|
|
|
|
|
2010-04-10 17:01:31 +00:00
|
|
|
def clear_status(self):
|
|
|
|
self.header.set_markup('')
|
|
|
|
self.text.set_markup('')
|
|
|
|
self.screen_name = None
|
|
|
|
self.id = None
|
2010-04-12 01:07:37 +00:00
|
|
|
self.set_read(True)
|
|
|
|
|
|
|
|
|
|
|
|
def set_read(self, read=True):
|
|
|
|
if read:
|
|
|
|
self.text_eb.modify_bg(gtk.STATE_NORMAL,
|
2010-04-12 20:31:38 +00:00
|
|
|
gtk.gdk.color_parse("#f2f1f0"))
|
2010-04-12 01:07:37 +00:00
|
|
|
else:
|
|
|
|
self.text_eb.modify_bg(gtk.STATE_NORMAL,
|
2010-04-12 20:53:03 +00:00
|
|
|
gtk.gdk.color_parse("#dbffdb"))
|
2010-04-10 17:01:31 +00:00
|
|
|
|
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
def on_reply_clicked(self, widget):
|
|
|
|
self.emit('reply')
|
|
|
|
|
|
|
|
|
|
|
|
def on_retweet_clicked(self, widget):
|
|
|
|
self.emit('retweet')
|
2010-04-10 17:21:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
def on_url_clicked(self, widget):
|
|
|
|
# fixme: for now, hard code firefox, since that's what I use
|
|
|
|
# Eventually make this configgable
|
2010-04-12 21:13:13 +00:00
|
|
|
# fixme: this doesn't work at all right now... figure out how to make this signal happen
|
2010-04-12 00:01:45 +00:00
|
|
|
print 'debug: on_url_clicked()'
|
2010-04-12 21:13:13 +00:00
|
|
|
# subprocess.Popen('/usr/bin/firefox ' + self.text.get_current_uri(), shell=False).pid
|
2010-04-09 04:56:51 +00:00
|
|
|
|
|
|
|
# end class TweetBox
|
|
|
|
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-12 20:31:38 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
# 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('clicked')
|
|
|
|
|
|
|
|
|
|
|
|
### end class CloseTabLabel
|
|
|
|
|
|
|
|
|
2010-04-07 03:05:51 +00:00
|
|
|
|
|
|
|
# main
|
2010-04-09 21:45:21 +00:00
|
|
|
|
|
|
|
# Create custom events for TweetBox
|
2010-04-12 20:31:38 +00:00
|
|
|
gobject.signal_new("clicked", CloseTabLabel,
|
|
|
|
gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE, ())
|
2010-04-09 21:45:21 +00:00
|
|
|
gobject.signal_new("reply", TweetBox,
|
|
|
|
gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE, ())
|
|
|
|
gobject.signal_new("retweet", TweetBox,
|
|
|
|
gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE, ())
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
my_twitter = MyTwitter()
|
|
|
|
gtk.main()
|