Browse Source

Removed a lot of (now) unused code. Some should return.

master
Julio Biason 16 years ago
parent
commit
77f72c197e
  1. 909
      mitterlib/ui/ui_pygtk.py

909
mitterlib/ui/ui_pygtk.py

@ -38,82 +38,14 @@ from mitterlib.ui.helpers import timesince
# Constants
URL_RE = re.compile(
r'((?:(?:https?|ftp)://|www[-\w]*\.)[^\s\n\r]+[-\w+&@#%=~])', re.I)
_log = logging.getLogger('ui.pygtk')
class Columns:
(PIC, NAME, MESSAGE, USERNAME, ID, DATETIME, ALL_DATA) = range(7)
class Interface(object):
"""Linux/GTK interface for Mitter."""
NAMESPACE = 'pygtk'
def systray_cb(self, widget, user_param=None):
if self.window.get_property('visible') and self.window.is_active():
x, y = self.window.get_position()
self.prefs['position_x'] = x
self.prefs['position_y'] = y
self.window.hide()
else:
self.window.move(
self.prefs['position_x'],
self.prefs['position_y'])
self.window.deiconify()
self.window.present()
def create_settings_dialog(self):
"""Creates the settings dialog."""
self.settings_window = gtk.Dialog(title="Settings",
parent=self.window, flags=gtk.DIALOG_MODAL |
gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=(gtk.STOCK_CANCEL, 0, gtk.STOCK_OK, 1))
self.settings_box = gtk.Table(rows=4, columns=2, homogeneous=False)
username_label = gtk.Label('Username:')
password_label = gtk.Label('Password:')
refresh_label = gtk.Label('Refresh interval (minutes):')
https_label = gtk.Label('Use secure connections (HTTPS):')
labels = [username_label, password_label, refresh_label, https_label]
for label in labels:
label.set_alignment(0, 0.5)
label.set_padding(2, 0)
self.username_field = gtk.Entry()
self.password_field = gtk.Entry()
self.password_field.set_visibility(False)
self.refresh_interval_field = gtk.SpinButton()
self.refresh_interval_field.set_range(1, 99)
self.refresh_interval_field.set_numeric(True)
self.refresh_interval_field.set_value(self.prefs['refresh_interval'])
self.refresh_interval_field.set_increments(1, 5)
self.https_field = gtk.CheckButton()
self.https_field.set_active(self.https)
self.settings_box.attach(username_label, 0, 1, 0, 1)
self.settings_box.attach(self.username_field, 1, 2, 0, 1)
self.settings_box.attach(password_label, 0, 1, 1, 2)
self.settings_box.attach(self.password_field, 1, 2, 1, 2)
self.settings_box.attach(refresh_label, 0, 1, 2, 3)
self.settings_box.attach(self.refresh_interval_field, 1, 2, 2, 3)
self.settings_box.attach(https_label, 0, 1, 3, 4)
self.settings_box.attach(self.https_field, 1, 2, 3, 4)
self.settings_box.show_all()
self.settings_window.vbox.pack_start(self.settings_box, True,
True, 0)
self.settings_window.connect('close', self.close_dialog)
self.settings_window.connect('response', self.update_preferences)
return
def show_about(self, widget):
"""Show the about dialog."""
@ -143,823 +75,6 @@ class Interface(object):
about_window.hide()
# ------------------------------------------------------------
# Widget creation functions
# ------------------------------------------------------------
# ------------------------------------------------------------
# Grid cell content callback
# ------------------------------------------------------------
# Non-widget attached callbacks
def set_auto_refresh(self):
"""Configure auto-refresh of tweets every `interval` minutes"""
if self._refresh_id:
gobject.source_remove(self._refresh_id)
self._refresh_id = gobject.timeout_add(
self.prefs['refresh_interval']*60*1000,
self.refresh, None)
return
def update_friends_list(self):
"""Fetch the user's list of twitter friends and add it
to the friends_store for @reply autocompletion"""
_log.debug('Checking friends list...')
friends = self.twitter.friends_list(self.post_update_friends_list)
return
def post_update_friends_list(self, friends, error):
"""Function called after we fetch the friends list."""
_log.debug('Received the friends list')
if error == 401: # TODO: Constants for this?
# not authorized
_log.error('User is not authorized yet')
return
if error in (500, 502, 503):
_log.error('Twitter asked us to try getting friends list' \
' sometime later')
gobject.timeout_add(5*60*1000, self.update_friends_list)
return
if error:
# any error
# well, we just don't add any friends, then.
_log.error('Error getting friend list, leaving list empty')
return
# I'm not really sure if we need to set the thread locking here (as we
# are just updating the store), but better safe than sorry!
gtk.gdk.threads_enter()
# Sometimes due to twitter API quirks and moon phases, the friends
# list ends up getting populated more than once. So watch for
# duplicates....
known_friends = [row[0] for row in self.friends_store]
_log.debug('known_friends: %s' % " ".join(known_friends))
for friend in friends:
try:
screen_name = '@' + friend['screen_name'] + ': '
if screen_name not in known_friends:
_log.debug('Adding "%s" to the list' % (screen_name))
self.friends_store.append([screen_name])
except Exception, e:
# No `error` does not always mean twitter sent us good data
_log.error('Error processing friend list. %s' % str(e))
gtk.gdk.threads_leave()
_log.debug('friends list processing complete')
return
def prune_grid_store(self):
"""Prune the grid_store by removing the oldest rows."""
if len(self.grid_store) <= MAX_STATUS_DISPLAY:
return True # Required by gobject.idle_add() for this to be called
# again
_log.debug("prune_grid_store called")
gtk.gdk.threads_enter()
self.grid.freeze_child_notify()
self.grid.set_model(None)
# Since I don't know how to get the last row in grid_store,
# I'll reverse the list and then pop out the first row instead.
self.grid_store.set_sort_column_id(Columns.DATETIME,
gtk.SORT_ASCENDING)
iter = self.grid_store.get_iter_first()
while (len(self.grid_store) > MAX_STATUS_DISPLAY) and iter:
_log.debug("popping off tweet with id %s" %
self.grid_store.get_value(iter, Columns.ID))
self.grid_store.remove(iter) # iter is auto set to next row
self.grid_store.set_sort_column_id(Columns.DATETIME,
gtk.SORT_DESCENDING)
self.grid.set_model(self.grid_store)
self.grid.thaw_child_notify()
gtk.gdk.threads_leave()
return True
# Main window callbacks
def size_request(self, widget, requisition, data=None):
"""Callback when the window changes its sizes. We use it to set the
proper word-wrapping for the message column."""
self.prefs['width'], self.prefs['height'] = self.window.get_size()
# this is based on a mail of Kristian Rietveld, on gtk maillist
if not len(self.grid_store):
# nothing to rearrange
return
column = self.message_column
iter = self.grid_store.get_iter_first()
path = self.grid_store.get_path(iter)
column_rectangle = self.grid.get_cell_area(path, column)
width = column_rectangle.width
_log.debug('Width=%d' % (width))
# there should be only
renderers = column.get_cell_renderers()
for render in renderers:
_log.debug('Render update')
render.set_property('wrap-width', width)
while iter:
path = self.grid_store.get_path(iter)
self.grid_store.row_changed(path, iter)
iter = self.grid_store.iter_next(iter)
return
def notify_reset(self, widget, event, user_data=None):
if getattr(event, 'in_', False):
self._main_window.set_urgency_hint(False)
if self._systray:
self._systray.set_tooltip('Mitter: Click to toggle ' \
'window visibility.')
self._systray.set_from_file(self._app_icon)
self.unread_tweets = 0
return
def notify(self, new_tweets=0):
"""Set the window hint as urgent, so Mitter window will flash,
notifying the user about the new messages. Also send a notification
message with one of the new tweets."""
self.window.set_urgency_hint(True)
if self._systray and self.unread_tweets > 0:
self._systray.set_tooltip('Mitter: %s new' % self.unread_tweets)
self._systray.set_from_file(self._app_icon_alert)
if self.action_group.get_action('MuteNotify').get_active():
_log.debug('notifications are currently muted')
return
if new_tweets and len(self.grid_store) > 0:
iter = self.grid_store.get_iter_first()
while iter:
sender = self.grid_store.get_value(iter, Columns.USERNAME)
if sender == self.username_field.get_text():
iter = self.grid_store.iter_next(iter)
continue
else:
tweet = self.grid_store.get_value(iter, Columns.MESSAGE)
_log.debug('notify_broadcast with this tweet: %s' %
tweet)
break
if new_tweets > 1:
msg = '<b>%d</b> unread tweets including ' \
'this from <i>%s</i>:<br/>%s' % (self.unread_tweets,
sender, tweet)
else:
msg = 'One new tweet from <i>%s</i>:<br/>%s' % (sender,
tweet)
if self.systray:
gtk.gdk.threads_enter()
screen, rect, orientation = self.systray.get_geometry()
gtk.gdk.threads_leave()
self.notify_broadcast(msg, rect.x, rect.y)
return
# settings callbacks
def show_settings(self, widget, user_data=None):
"""Create and display the settings window."""
self.settings_window.show()
self.settings_window.run()
return
def close_dialog(self, user_data=None):
"""Hide the dialog window."""
return True
def update_preferences(self, widget, response_id=0, user_data=None):
"""
Update the user preferences when the user press the "OK" button in the
settings window."""
if response_id == 1:
self.statusbar.push(self.statusbar_context,
'Saving your profile...')
self.save_interface_prefs()
# update the (internal) twitter prefences too!
self.twitter.username = self.username_field.get_text()
self.twitter.password = self.password_field.get_text()
self.twitter.https = self.https_field.get_active()
refresh_interval = self.refresh_interval_field.get_value_as_int()
self.prefs['refresh_interval'] = refresh_interval
# update the list
self.refresh(None)
self.update_friends_list()
self.statusbar.pop(self.statusbar_context)
# update auto-refresh
self.set_auto_refresh()
self.settings_window.hide()
return True
# update status
def update_status(self, user_data=None):
"""Update the user status on Twitter."""
status = self.update_text.get_text()
status = status.strip()
if not str_len(status):
return
self.update_text.set_sensitive(False)
self.statusbar.push(self.statusbar_context, 'Updating your status...')
if str_len(status) > 140:
error_message = 'Your message has more than 140 characters and' \
' Twitter may truncate it. It would still be visible ' \
'on the website. Do you still wish to go ahead?'
if str_len(status) > 160:
error_message = 'Your message has more than 160 characters ' \
'and it is very likely Twitter will refuse it. You ' \
'can try shortening your URLs before posting. Do ' \
'you still wish to go ahead?'
error_dialog = gtk.MessageDialog(parent=self.window,
type=gtk.MESSAGE_QUESTION,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
message_format="Your status update message is too long.",
buttons=gtk.BUTTONS_YES_NO)
error_dialog.format_secondary_text(error_message)
response = error_dialog.run()
error_dialog.destroy()
if response == gtk.RESPONSE_NO:
self.statusbar.pop(self.statusbar_context)
self.update_text.set_sensitive(True)
self.window.set_focus(self.update_text)
return
data = self.twitter.update(status, self.post_update_status)
def post_update_status(self, data, error):
"""Function called after we receive the answer from the update
status."""
if error:
gtk.gdk.threads_enter()
error_dialog = gtk.MessageDialog(parent=self.window,
type=gtk.MESSAGE_ERROR,
message_format='Error updating status. Please try again.',
buttons=gtk.BUTTONS_OK)
error_dialog.connect("response", lambda *a:
error_dialog.destroy())
error_dialog.run()
gtk.gdk.threads_leave()
else:
if data:
# i wonder if this will really work
self.post_refresh([data], None, False)
else:
self.refresh(None, False)
gtk.gdk.threads_enter()
self.update_text.set_text("")
gtk.gdk.threads_leave()
gtk.gdk.threads_enter()
self.statusbar.pop(self.statusbar_context)
self.update_text.set_sensitive(True)
self.window.set_focus(self.update_text)
gtk.gdk.threads_leave()
return True
def shrink_url(self, widget, user_data=None):
bounds = self.update_text.get_selection_bounds()
if not bounds:
return
else:
start, end = bounds
longurl = self.update_text.get_chars(start, end).strip()
if not longurl:
return
_log.debug('shrink url request for: %s' % longurl)
self.update_text.set_sensitive(False)
self.statusbar.push(self.statusbar_context, 'Shrinking URL...')
self.twitter.download('http://is.gd/api.php?longurl=' + longurl,
self.post_shrink_url, longurl=longurl,
start=start, end=end)
def post_shrink_url(self, url, error, longurl, start, end):
if error:
_log.error("Exception in shrinking url. ' \
'Error code: %s" % error)
# error dialog
gtk.gdk.threads_enter()
error_dialog = gtk.MessageDialog(parent=self.window,
type=gtk.MESSAGE_ERROR,
message_format='Failed to shrink the URL %s' % longurl,
buttons=gtk.BUTTONS_OK)
error_dialog.connect("response", lambda *a:
error_dialog.destroy())
error_dialog.run()
gtk.gdk.threads_leave()
else:
_log.debug('Got shrunk url: %s' % url)
char = self.update_text.get_chars(start-1, start)
if start and not char.isspace():
url = ' '+url
char = self.update_text.get_chars(end, end+1)
if not char.isspace():
url = url+' '
gtk.gdk.threads_enter()
self.update_text.delete_text(start, end)
self.update_text.insert_text(url, start)
self.update_text.set_position(start+len(url))
gtk.gdk.threads_leave()
gtk.gdk.threads_enter()
self.statusbar.pop(self.statusbar_context)
self.update_text.set_sensitive(True)
self.update_text.grab_focus()
gtk.gdk.threads_leave()
# post related callbacks
def reply_tweet(self, widget, user_data=None):
"""Reply by putting the username in your input"""
cursor = self.grid.get_cursor()
if not cursor:
return
path = cursor[0]
iter = self.grid_store.get_iter(path)
username = self.grid_store.get_value(iter, Columns.USERNAME)
text_insert = '@%s: ' % (username)
_log.debug('Inserting reply text: %s' % (text_insert))
status = self.update_text.get_text()
status = text_insert + status
self.update_text.set_text(status)
self.window.set_focus(self.update_text)
self.update_text.set_position(len(status))
def retweet(self, widget, user_data=None):
"""Retweet by putting the string rt and username in your input"""
cursor = self.grid.get_cursor()
if not cursor:
return
path = cursor[0]
iter = self.grid_store.get_iter(path)
username = self.grid_store.get_value(iter, Columns.USERNAME)
msg = self.grid_store.get_value(iter, Columns.MESSAGE)
text_insert = 'RT @%s: %s' % (username, msg)
_log.debug('Inserting retweet text: %s' % (text_insert))
status = text_insert + self.update_text.get_text()
self.update_text.set_text(status)
self.window.set_focus(self.update_text)
self.update_text.set_position(str_len(status))
def delete_tweet(self, widget, user_data=None):
"""Delete a twit."""
cursor = self.grid.get_cursor()
if not cursor:
return
path = cursor[0]
iter = self.grid_store.get_iter(path)
tweet_id = int(self.grid_store.get_value(iter, Columns.ID))
_log.debug('Deleting tweet: %d' % (tweet_id))
self.statusbar.push(self.statusbar_context, 'Deleting tweet...')
self.twitter.tweet_destroy(tweet_id, self.post_delete_tweet,
tweet=tweet_id)
return
def post_delete_tweet(self, data, error, tweet):
"""Function called after we delete a tweet on the server."""
if error:
gtk.gdk.threads_enter()
error_dialog = gtk.MessageDialog(parent=self.window,
type=gtk.MESSAGE_ERROR,
message_format='Error deleting tweet. Please try again.',
buttons=gtk.BUTTONS_OK)
error_dialog.connect("response", lambda *a:
error_dialog.destroy())
error_dialog.run()
gtk.gdk.threads_leave()
else:
# locate that tweet in the store and remove it.
iter = self.grid_store.get_iter_first()
tweet = int(tweet)
while iter:
id = self.grid_store.get_value(iter, Columns.ID)
if int(id) == tweet:
self.grid_store.remove(iter)
break
iter = self.grid_store.iter_next(iter)
# update the interface
gtk.gdk.threads_enter()
self.statusbar.pop(self.statusbar_context)
self.grid.queue_draw()
gtk.gdk.threads_leave()
return
def check_post(self, treeview, user_data=None):
"""Callback when one of the rows is selected."""
cursor = treeview.get_cursor()
if not cursor:
return
path = cursor[0]
iter = self.grid_store.get_iter(path)
username = self.grid_store.get_value(iter, Columns.USERNAME)
delete_action = self.action_group.get_action('Delete')
if username == self.username_field.get_text():
delete_action.set_property('sensitive', True)
else:
delete_action.set_property('sensitive', False)
return
def open_post(self, treeview, path, view_column, user_data=None):
"""Callback when one of the rows in activated."""
iter = self.grid_store.get_iter(path)
username = self.grid_store.get_value(iter, Columns.USERNAME)
tweet_id = self.grid_store.get_value(iter, Columns.ID)
message = self.grid_store.get_value(iter, Columns.MESSAGE)
urls = url_re.search(message)
if urls:
# message contains a link; go to the link instead
url = urls.groups()[0]
else:
url = 'http://twitter.com/%s/statuses/%s/' % (username, tweet_id)
self.open_url(path, url)
def click_post(self, treeview, event, user_data=None):
"""Callback when a mouse click event occurs on one of the rows."""
if event.button != 3:
# Only right clicks are processed
return False
x = int(event.x)
y = int(event.y)
pth = treeview.get_path_at_pos(x, y)
if not pth:
# The click wasn't on a row
return False
path, col, cell_x, cell_y = pth
treeview.grab_focus()
treeview.set_cursor(path, col, 0)
self.show_post_popup(treeview, event)
return True
def show_post_popup(self, treeview, event, user_data=None):
"""Shows the popup context menu in the treeview"""
cursor = treeview.get_cursor()
if not cursor:
return
path = cursor[0]
row_iter = self.grid_store.get_iter(path)
popup_menu = gtk.Menu()
popup_menu.set_screen(self.window.get_screen())
# An open submenu with various choices underneath
open_menu_items = []
tweet = self.grid_store.get_value(row_iter, Columns.ALL_DATA)
urls = url_re.findall(tweet['text'])
for url in urls:
if len(url) > 20:
item_name = url[:20] + '...'
else:
item_name = url
item = gtk.MenuItem(item_name)
item.connect('activate', self.open_url, url)
open_menu_items.append(item)
if tweet['in_reply_to_status_id']:
# I wish twitter made it easy to construct target url
# without having to make another API call
reply_to = re.search(r'@(?P<user>\w+)', tweet['text'])
if reply_to:
url = 'http://twitter.com/%s/statuses/%s' % (
reply_to.group('user'),
tweet['in_reply_to_status_id'])
item = gtk.MenuItem('In reply to')
item.connect('activate', self.open_url, url)
open_menu_items.append(item)
item = gtk.MenuItem('This tweet')
username = self.grid_store.get_value(row_iter, Columns.USERNAME)
tweet_id = self.grid_store.get_value(row_iter, Columns.ID)
url = 'http://twitter.com/%s/statuses/%s/' % (username, tweet_id)
item.connect('activate', self.open_url, url)
open_menu_items.append(item)
open_menu = gtk.Menu()
for item in open_menu_items:
open_menu.append(item)
open_item = gtk.MenuItem("Open")
open_item.set_submenu(open_menu)
popup_menu.append(open_item)
# Reply, only if it's not yourself
item = gtk.MenuItem("Reply")
item.connect('activate', self.reply_tweet, "Reply")
if username == self.username_field.get_text():
item.set_property('sensitive', False)
popup_menu.append(item)
# Retweet, only if it's not yourself
item = gtk.MenuItem("Retweet")
item.connect('activate', self.retweet, "Retweet")
if username == self.username_field.get_text():
item.set_property('sensitive', False)
popup_menu.append(item)
item = gtk.MenuItem("Delete")
item.connect('activate', self.delete_tweet, "Delete")
if username != self.username_field.get_text():
item.set_property('sensitive', False)
popup_menu.append(item)
popup_menu.show_all()
if event:
b = event.button
t = event.time
else:
b = 1
t = 0
popup_menu.popup(None, None, None, b, t)
return True
# action callbacks
# (yes, settings should be here, but there are more settings-related
# callbacks, so let's keep them together somewhere else)
def open_url(self, source, url):
"""Simply opens specified url in new browser tab. We need source
parameter so that this function can be used as an event callback"""
_log.debug('opening url: %s' % url)
import webbrowser
webbrowser.open_new_tab(url)
self.window.set_focus(self.update_text)
def refresh(self, widget, notify=True):
"""Update the list of twits."""
if self.last_update:
self.statusbar.pop(self.statusbar_context)
self.last_update = datetime.datetime.now()
_log.debug('Updating list of tweets...')
self.statusbar.push(self.statusbar_context,
'Updating list of tweets...')
self.twitter.friends_timeline(self.post_refresh, notify=notify)
return True # required by gobject.timeout_add
def post_refresh(self, data, error, notify):
"""Function called when the system retrieves the list of new
tweets."""
_log.debug('Data: %s' % (str(data)))
if error == 401:
# Not authorized, popup the settings window
gtk.gdk.threads_enter()
error_dialog = gtk.MessageDialog(parent=self.window,
type=gtk.MESSAGE_ERROR,
message_format='Autorization error, check your login ' \
'information in the prefrences',
buttons=gtk.BUTTONS_OK)
error_dialog.connect("response", lambda *a:
error_dialog.destroy())
error_dialog.run()
gtk.gdk.threads_leave()
return
if not data:
gtk.gdk.threads_enter()
self.statusbar.pop(self.statusbar_context)
self.show_last_update()
_log.debug('No new data')
gtk.gdk.threads_leave()
return
known_tweets = [row[Columns.ID] for row in self.grid_store]
need_notify = False
new_tweets = 0
new_tweets_list = []
for tweet in data:
id = tweet['id']
if str(id) in known_tweets:
_log.debug('Tweet %s is already in the list' % (id))
continue
created_at = tweet['created_at']
display_name = tweet['user']['name']
username = tweet['user']['screen_name']
user_pic = tweet['user']['profile_image_url']
message = tweet['text']
new_tweets_list.append((user_pic, display_name, message, username,
id, created_at, tweet))
self.queue_pic(user_pic)
_log.debug('New tweet with id %s from %s' % (id, username))
if not username == self.username_field.get_text():
# we don't want to be notified about tweets from ourselves,
# but from everyone else it is fine.
new_tweets += 1
# add the new tweets in the store
gtk.gdk.threads_enter()
for data in new_tweets_list:
self.grid_store.append(data)
self.statusbar.pop(self.statusbar_context)
# there is new stuff, so we move to the top
p = self.grid_store.get_path(self.grid_store.get_iter_first())
self.grid.scroll_to_cell(p)
self.show_last_update()
_log.debug('Tweets updated')
gtk.gdk.threads_leave()
if new_tweets and notify:
self.unread_tweets += new_tweets
self.notify(new_tweets)
self.refresh_rate_limit()
self.prune_grid_store()
# ------------------------------------------------------------
# Helper functions
# ------------------------------------------------------------
def clear_list(self):
"""Clear the list, so we can add more items."""
self.grid_store.clear()
return
def refresh_rate_limit(self):
"""Request the rate limit and check if we are doing okay."""
self.twitter.rate_limit_status(self.post_refresh_rate_limit)
return
def post_refresh_rate_limit(self, data, error):
"""Callback for the refresh_rate_limit."""
if error or not data:
_log.error('Error fetching rate limit')
return
# Check if we are running low on our limit
reset_time = datetime.datetime.fromtimestamp(
int(data['reset_time_in_seconds']))
if reset_time < datetime.datetime.now():
# Clock differences can cause this
return
time_delta = reset_time - datetime.datetime.now()
mins_till_reset = time_delta.seconds/60 # Good enough!
needed_hits = mins_till_reset/self.prefs['refresh_interval']
remaining_hits = int(data['remaining_hits'])
_log.debug('remaining_hits: %s. reset in %s mins.'
% (remaining_hits, mins_till_reset))
if needed_hits > remaining_hits:
gtk.gdk.threads_enter()
error_dialog = gtk.MessageDialog(parent=self.window,
type=gtk.MESSAGE_WARNING,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
message_format='Refresh rate too high',
buttons=gtk.BUTTONS_OK)
error_dialog.format_secondary_text(
"You have only %d twitter requests left until your " \
"request count is reset in %d minutes. But at your " \
"current refresh rate (every %d minutes), you will " \
"exhaust your limit within %d minutes. You should " \
"consider increasing the refresh interval in Mitter's " \
"Settings dialog." % (remaining_hits, mins_till_reset,
self.prefs['refresh_interval'],
remaining_hits * self.prefs['refresh_interval']))
error_dialog.connect("response", lambda *a:
error_dialog.destroy())
error_dialog.run()
gtk.gdk.threads_leave()
def show_last_update(self):
"""Add the last update time in the status bar."""
last_update = self.last_update.strftime('%H:%M')
next_update = (self.last_update +
datetime.timedelta(minutes=self.prefs[
'refresh_interval'])).strftime('%H:%M')
message = 'Last update %s, next update %s' % (last_update,
next_update)
self.statusbar.push(self.statusbar_context, message)
return
def queue_pic(self, pic):
"""Check if the pic is in the queue or already downloaded. If it is
not in any of those, add it to the download queue."""
if pic in self.user_pics:
return
if pic in self.pic_queue:
return
self.pic_queue.add(pic)
self.twitter.download(pic, self.post_pic_download, id=pic)
return
def post_pic_download(self, data, error, id):
"""Function called once we downloaded the user pic."""
_log.debug('Received pic %s' % (id))
if error or not data:
_log.debug('Error with the pic, not loading')
return
loader = gtk.gdk.PixbufLoader()
loader.write(data)
loader.close()
self.user_pics[id] = loader.get_pixbuf()
self.pic_queue.discard(id)
# finally, request the grid to redraw itself
gtk.gdk.threads_enter()
self.grid.queue_draw()
gtk.gdk.threads_leave()
return
# ------------------------------------------------------------
# Helper functions
# ------------------------------------------------------------
@ -1063,7 +178,7 @@ class Interface(object):
message_renderer.set_property('width', 10)
message_column = gtk.TreeViewColumn('Message',
message_renderer, text=1)
message_renderer)
message_column.set_cell_data_func(message_renderer,
self._cell_renderer_message)
self.grid.append_column(message_column)
@ -1088,7 +203,7 @@ class Interface(object):
refresh_action = gtk.Action('Refresh', '_Refresh',
'Update the listing', gtk.STOCK_REFRESH)
refresh_action.connect('activate', self.refresh)
#refresh_action.connect('activate', self.refresh)
quit_action = gtk.Action('Quit', '_Quit',
'Exit Mitter', gtk.STOCK_QUIT)
@ -1096,7 +211,7 @@ class Interface(object):
settings_action = gtk.Action('Settings', '_Settings',
'Settings', gtk.STOCK_PREFERENCES)
settings_action.connect('activate', self.show_settings)
#settings_action.connect('activate', self.show_settings)
update_action = gtk.Action('Update', '_Update', 'Update your status',
gtk.STOCK_ADD)
@ -1106,19 +221,19 @@ class Interface(object):
delete_action = gtk.Action('Delete', '_Delete', 'Delete a post',
gtk.STOCK_DELETE)
delete_action.set_property('sensitive', False)
delete_action.connect('activate', self.delete_tweet)
#delete_action.connect('activate', self.delete_tweet)
about_action = gtk.Action('About', '_About', 'About Mitter',
gtk.STOCK_ABOUT)
about_action.connect('activate', self.show_about)
shrink_url_action = gtk.Action('ShrinkURL', 'Shrink _URL',
'Shrink selected URL', gtk.STOCK_EXECUTE)
shrink_url_action.connect('activate', self.shrink_url)
#shrink_url_action = gtk.Action('ShrinkURL', 'Shrink _URL',
# 'Shrink selected URL', gtk.STOCK_EXECUTE)
#shrink_url_action.connect('activate', self.shrink_url)
mute_action = gtk.ToggleAction('MuteNotify', '_Mute Notifications',
'Mutes notifications on new tweets', gtk.STOCK_MEDIA_PAUSE)
mute_action.set_active(False)
#mute_action = gtk.ToggleAction('MuteNotify', '_Mute Notifications',
# 'Mutes notifications on new tweets', gtk.STOCK_MEDIA_PAUSE)
#mute_action.set_active(False)
post_action = gtk.Action('Posts', '_Posts', 'Post management', None)
@ -1140,8 +255,8 @@ class Interface(object):
self.action_group.add_action(edit_action)
self.action_group.add_action(help_action)
self.action_group.add_action(about_action)
self.action_group.add_action_with_accel(shrink_url_action, '<Ctrl>u')
self.action_group.add_action_with_accel(mute_action, '<Ctrl>m')
#self.action_group.add_action_with_accel(shrink_url_action, '<Ctrl>u')
#self.action_group.add_action_with_accel(mute_action, '<Ctrl>m')
self.action_group.add_action_with_accel(update_action,
'<Ctrl>Return')

Loading…
Cancel
Save