def __init__(self, screen_name, keys): # Gtk Multithread Setup if sys.platform == "win32": gobject.threads_init() else: gtk.gdk.threads_init() if USE_NOTIFY: pynotify.init("gwit") # force change gtk icon settings settings = gtk.settings_get_default() if not getattr(settings.props, 'gtk_button_images', True): settings.props.gtk_button_images = True # init status timelines self.timelines = list() self.tlhash = dict() self.timeline_mention = None # Twitter class instance self.twitter = TwitterAPI(screen_name, *keys) self.twitter.on_tweet_event = self.refresh_tweet self.twitter.on_notify_event = self.notify self.read_settings() # set event (show remaining api count) self.twitter.on_twitterapi_requested = self.on_timeline_refresh self.twitter.new_timeline = self.new_timeline # Get configuration self.twitter.update_configuration_bg() # Get users self.twitter.get_followers_bg() if not self.userstream: self.twitter.get_following_bg() # init icon store IconStore.iconmode = self.iconmode self.iconstore = IconStore() # GtkBuilder instance self.builder = gtk.Builder() # Glade file input gladefile = os.path.join(os.path.dirname(__file__), "ui/gwit.ui") self.builder.add_from_file(gladefile) # Connect signals self.builder.connect_signals(self) self.notebook = self.builder.get_object("notebook1") self.textview = self.builder.get_object("textview1") self.btnupdate = self.builder.get_object("button1") self.charcount = self.builder.get_object("label1") self.dsettings = self.builder.get_object("dialog_settings") self.imgtable = self.builder.get_object("table_images") self.menu_tweet = self.builder.get_object("menu_tweet") self.builder.get_object("menuitem_tweet").set_submenu(self.menu_tweet) self.menu_timeline = self.builder.get_object("menu_timeline") self.builder.get_object("menuitem_timeline").set_submenu( self.menu_timeline) # set class variables Timeline.twitter = self.twitter StatusView.twitter = self.twitter StatusView.iconstore = self.iconstore StatusView.iconmode = self.iconmode StatusView.pmenu = self.menu_tweet BaseThread.twitter = self.twitter StatusDetail.twitter = self.twitter StatusDetail.iconstore = self.iconstore ListsView.twitter = self.twitter ListsView.iconstore = self.iconstore UserSelection.twitter = self.twitter UserSelection.iconstore = self.iconstore GetFriendsWizard.twitter = self.twitter IconThread.twitter = self.twitter IconThread.use_icon_cache = self.iconcache imgpath = os.path.join(os.path.dirname(__file__), "images/") StatusView.favico_off = gtk.gdk.pixbuf_new_from_file( imgpath + "favorite.png") StatusView.favico_hover = gtk.gdk.pixbuf_new_from_file( imgpath + "favorite_hover.png") StatusView.favico_on = gtk.gdk.pixbuf_new_from_file( imgpath + "favorite_on.png") StatusView.rtico_off = gtk.gdk.pixbuf_new_from_file( imgpath + "retweet.png") StatusView.rtico_hover = gtk.gdk.pixbuf_new_from_file( imgpath + "retweet_hover.png") StatusView.rtico_on = gtk.gdk.pixbuf_new_from_file( imgpath + "retweet_on.png") self.initialize()
class Main(object): # Default settings interval = (300, 300, -1) msgfooter = u"" alloc = gtk.gdk.Rectangle(0, 0, 240, 320) scounts = (20, 200) iconmode = True iconcache = True userstream = True # My status, Mentions to me, Reply to, Reply to user, Selected user status_color = ("#CCCCFF", "#FFCCCC", "#FFCC99", "#FFFFCC", "#CCFFCC") # Tweet parameters twparams = dict() # Streaming API filter _filter_tab = None _toggle_change_flag = False _text_delete_flag = False # Constractor def __init__(self, screen_name, keys): # Gtk Multithread Setup if sys.platform == "win32": gobject.threads_init() else: gtk.gdk.threads_init() if USE_NOTIFY: pynotify.init("gwit") # force change gtk icon settings settings = gtk.settings_get_default() if not getattr(settings.props, 'gtk_button_images', True): settings.props.gtk_button_images = True # init status timelines self.timelines = list() self.tlhash = dict() self.timeline_mention = None # Twitter class instance self.twitter = TwitterAPI(screen_name, *keys) self.twitter.on_tweet_event = self.refresh_tweet self.twitter.on_notify_event = self.notify self.read_settings() # set event (show remaining api count) self.twitter.on_twitterapi_requested = self.on_timeline_refresh self.twitter.new_timeline = self.new_timeline # Get configuration self.twitter.update_configuration_bg() # Get users self.twitter.get_followers_bg() if not self.userstream: self.twitter.get_following_bg() # init icon store IconStore.iconmode = self.iconmode self.iconstore = IconStore() # GtkBuilder instance self.builder = gtk.Builder() # Glade file input gladefile = os.path.join(os.path.dirname(__file__), "ui/gwit.ui") self.builder.add_from_file(gladefile) # Connect signals self.builder.connect_signals(self) self.notebook = self.builder.get_object("notebook1") self.textview = self.builder.get_object("textview1") self.btnupdate = self.builder.get_object("button1") self.charcount = self.builder.get_object("label1") self.dsettings = self.builder.get_object("dialog_settings") self.imgtable = self.builder.get_object("table_images") self.menu_tweet = self.builder.get_object("menu_tweet") self.builder.get_object("menuitem_tweet").set_submenu(self.menu_tweet) self.menu_timeline = self.builder.get_object("menu_timeline") self.builder.get_object("menuitem_timeline").set_submenu( self.menu_timeline) # set class variables Timeline.twitter = self.twitter StatusView.twitter = self.twitter StatusView.iconstore = self.iconstore StatusView.iconmode = self.iconmode StatusView.pmenu = self.menu_tweet BaseThread.twitter = self.twitter StatusDetail.twitter = self.twitter StatusDetail.iconstore = self.iconstore ListsView.twitter = self.twitter ListsView.iconstore = self.iconstore UserSelection.twitter = self.twitter UserSelection.iconstore = self.iconstore GetFriendsWizard.twitter = self.twitter IconThread.twitter = self.twitter IconThread.use_icon_cache = self.iconcache imgpath = os.path.join(os.path.dirname(__file__), "images/") StatusView.favico_off = gtk.gdk.pixbuf_new_from_file( imgpath + "favorite.png") StatusView.favico_hover = gtk.gdk.pixbuf_new_from_file( imgpath + "favorite_hover.png") StatusView.favico_on = gtk.gdk.pixbuf_new_from_file( imgpath + "favorite_on.png") StatusView.rtico_off = gtk.gdk.pixbuf_new_from_file( imgpath + "retweet.png") StatusView.rtico_hover = gtk.gdk.pixbuf_new_from_file( imgpath + "retweet_hover.png") StatusView.rtico_on = gtk.gdk.pixbuf_new_from_file( imgpath + "retweet_on.png") self.initialize() def main(self): window = self.builder.get_object("window1") # settings allocation window.resize(self.alloc.width, self.alloc.height) window.show_all() # Start gtk main loop gtk.main() def read_settings(self): # Read settings d = Config.get_section("DEFAULT") self.interval = eval(d.get("interval", str(self.interval))) self.alloc = eval(d.get("allocation", str(self.alloc))) self.scounts = eval(d.get("counts", str(self.scounts))) self.iconmode = eval(d.get("iconmode", str(self.iconmode))) self.iconcache = eval(d.get("iconcache", str(self.iconcache))) self.userstream = eval(d.get("userstream", str(self.userstream))) self.status_color = eval(d.get("color", str(self.status_color))) u = Config.get_section(self.twitter.my_name) self.msgfooter = u.get("footer", "") # Initialize Tabs (in another thread) def initialize(self): # Set Status Views for i in (("Home", "home_timeline", self.userstream), ("@Mentions", "mentions")): # create new timeline and tab view deny_close = {"deny_close" : True} self.new_timeline(*i, **deny_close) # Set statusbar (Show API Remaining) self.label_apilimit = gtk.Label() self.statusbar = self.builder.get_object("statusbar1") self.statusbar.pack_start(self.label_apilimit, expand = False, padding = 10) self.statusbar.show_all() # Users tab append users = UserSelection() self.new_tab(users, "Users", deny_close = True) # Lists tab append lists = ListsSelection() self.new_tab(lists, "Lists", deny_close = True) self.notebook.set_current_page(0) # Window close event def close(self, widget): window = self.builder.get_object("window1") # Save Allocation (window position, size) alloc = repr(window.allocation) Config.save("DEFAULT", "allocation", alloc) # hide window window.hide_all() # Stop Icon Refresh self.iconstore.stop() def exit(self, widget): # hide window quickly while gtk.events_pending(): gtk.main_iteration() # Stop Timeline for i in self.timelines: if i != None: i.destroy() if i.timeline != None: i.timeline.join(1) if i.stream != None: i.stream.join(1) gtk.main_quit() self.save_settings() # Create new Timeline and append to notebook def new_timeline(self, label, method, userstream = False, *args, **kwargs): # Create Timeline Object tl = Timeline() if method == "filter": if self.get_filter_tab(): # filter method only one connection self.message_dialog( "May create only one standing connection to the Streaming API.\n" "Please close existing Streaming API tab if you want.") tl.destroy() return # set Streaming API stream tl.set_stream("filter", kwargs) else: interval = self.get_default_interval(method) tl.set_timeline(method, interval, self.scounts, args, kwargs) # Put error to statubar tl.timeline.on_twitterapi_error = self.on_twitterapi_error # for Event tl.view.new_timeline = self.new_timeline # Add Notebook (Tab view) uid = self.new_tab(tl, label, tl, kwargs.get("deny_close", False)) if method == "filter": self.set_filter_tab(uid) # Set color tl.view.set_color(self.status_color) if method == "mentions": # memory mentions tab_id self.timeline_mention = uid tl.on_status_added = self.on_mentions_added else: tl.on_status_added = self.on_status_added # Put tweet information to statusbar tl.view.on_status_selection_changed = self.on_status_selection_changed # Reply on double click tl.view.on_status_activated = self.on_status_activated # Set UserStream parameter if userstream: tl.set_stream("user") tl.start_stream() tl.start_timeline() # Append Tab to Notebook def new_tab(self, widget, label, timeline = None, deny_close = False): # close button button = gtk.Button() button.set_relief(gtk.RELIEF_NONE) icon = gtk.image_new_from_stock("gtk-close", gtk.ICON_SIZE_MENU) button.set_image(icon) uid = uuid.uuid4().int button.connect("clicked", self.on_tabclose_clicked, uid) n = self.notebook.get_n_pages() self.tlhash[uid] = n self.timelines.append(timeline) # Label lbl = gtk.Label(label) box = gtk.HBox() box.pack_start(lbl, True, True) if not deny_close: box.pack_start(button, False, False) box.show_all() if timeline != None: button.connect("button-press-event", self.on_notebook_tabbar_button_press) # append self.notebook.append_page(widget, box) self.notebook.show_all() self.notebook.set_current_page(n) return uid def get_selected_status(self): tab = self.get_current_tab() if tab != None: return tab.view.get_selected_status() def get_current_tab_n(self): return self.notebook.get_current_page() def get_current_tab(self): return self.timelines[self.notebook.get_current_page()] # Get text def get_textview(self): buf = self.textview.get_buffer() start, end = buf.get_start_iter(), buf.get_end_iter() return buf.get_text(start, end) # Set text def set_textview(self, txt, focus = False): buf = self.textview.get_buffer() buf.set_text(txt) if focus: self.textview.grab_focus() # Add text at cursor def add_textview(self, txt, focus = False): buf = self.textview.get_buffer() buf.insert_at_cursor(txt) if focus: self.textview.grab_focus() # Clear text def clear_textview(self, focus = False): self.set_textview("", focus) # Reply to selected status def reply_to_selected_status(self): status = self.get_selected_status() self.reply_to_status(status) def reply_to_status(self, status): self.twparams["reply_to"] = status.id name = status.user.screen_name buf = self.textview.get_buffer() buf.set_text("@%s " % (name)) self.textview.grab_focus() # Color selection dialog run for settings def color_dialog_run(self, title, color, entry): # Sample treeview setup store = gtk.ListStore(gtk.gdk.Pixbuf, str, str) treeview = gtk.TreeView(store) cellp = gtk.CellRendererPixbuf() colp = gtk.TreeViewColumn("icon", cellp, pixbuf = 0) cellt = gtk.CellRendererText() cellt.set_property("wrap-mode", pango.WRAP_CHAR) colt = gtk.TreeViewColumn("status", cellt, markup = 1) colp.add_attribute(cellp, "cell-background", 2) colt.add_attribute(cellt, "cell-background", 2) treeview.append_column(colp) treeview.append_column(colt) status = self.twitter.statuses.values()[0] store.append((self.iconstore.get(status.user), "<b>%s</b>\n%s" % (status.user.screen_name, status.text), color)) def on_changed_cursor(view): view.get_selection().unselect_all() treeview.set_property("can-focus", False) treeview.set_headers_visible(False) treeview.connect("cursor-changed", on_changed_cursor) treeview.show() swin = gtk.ScrolledWindow() swin.add(treeview) swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER) swin.show() label = gtk.Label("Sample") label.set_justify(gtk.JUSTIFY_LEFT) label.set_padding(0, 10) label.set_alignment(0, 0.5) label.show() def on_colorselection_color_changed(colorselection, liststore): strcolor = colorselection.get_current_color().to_string() liststore.set_value(liststore.get_iter_first(), 2, strcolor) # Dialog setup dialog = gtk.ColorSelectionDialog(title) selection = dialog.get_color_selection() selection.set_current_color(gtk.gdk.color_parse(color)) selection.connect("color-changed", on_colorselection_color_changed, store) selection.pack_start(label) selection.pack_start(swin) dialog.show_all() if dialog.run() == -5: color = selection.get_current_color().to_string() entry.set_text(color) else: color = None dialog.destroy() return color def status_update_thread(self, status): t = threading.Thread(target = self._status_update, args = (status,)) t.start() def _status_update(self, status): args = dict() gtk.gdk.threads_enter() self.textview.set_sensitive(False) self.btnupdate.set_sensitive(False) gtk.gdk.threads_leave() if self.twparams.get("reply_to", None): args["in_reply_to_status_id"] = self.twparams.get("reply_to", None) elif self.msgfooter != "": status = u"%s %s" % (status, self.msgfooter) if self.twparams.get("media", None): resp = self.twitter.api_wrapper( self.twitter.api.status_update_with_media, status, self.twparams["media"], **args) else: resp = self.twitter.api_wrapper( self.twitter.api.status_update, status, **args) if resp: gtk.gdk.threads_enter() self.clear_textview() gtk.gdk.threads_leave() self.twparams.pop("reply_to", None) self.twparams.pop("media", None) self.imgtable.forall(self.imgtable.remove) self.imgtable.set_visible(False) gtk.gdk.threads_enter() self.textview.set_sensitive(True) self.btnupdate.set_sensitive(True) self.textview.grab_focus() gtk.gdk.threads_leave() def get_default_interval(self, method): if method == "home_timeline": interval = self.interval[0] elif method == "mentions": interval = self.interval[1] else: interval = self.interval[2] return interval def get_filter_tab(self): if not self._filter_tab: return None elif self.tlhash.get(self._filter_tab, -1) < 0: # filter tab already closed self.set_filter_tab(None) return None else: return self._filter_tab @classmethod def set_filter_tab(cls, tab_id): cls._filter_tab = tab_id def save_settings(self): conf = (("DEFAULT", "interval", self.interval), ("DEFAULT", "counts", self.scounts), ("DEFAULT", "iconmode", self.iconmode), ("DEFAULT", "iconcache", self.iconcache), ("DEFAULT", "userstream", self.userstream), ("DEFAULT", "color", self.status_color), (self.twitter.my_name, "footer", self.msgfooter)) Config.save_section(conf) # desktop notify def notify(self, title, text, icon_user = None): if USE_NOTIFY: notify = pynotify.Notification(title, text) if icon_user: icon = self.iconstore.get(icon_user) notify.set_icon_from_pixbuf(icon) notify.show() def refresh_tweet(self, i): for tl in self.timelines: if tl: tl.view.reset_status_text() def message_dialog(self, message, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_OK): md = gtk.MessageDialog(type = type, buttons = buttons) md.set_markup(message) r = md.run() md.destroy() return r ######################################## # Original Events # status added event def on_status_added(self, i): status = self.twitter.statuses[i] myid = self.twitter.my_id myname = self.twitter.my_name if status.in_reply_to_user_id == myid or status.text.find("@%s" % myname) >= 0: # add mentions tab mentiontab = self.timelines[self.tlhash[self.timeline_mention]] if status.id not in mentiontab.get_timeline_ids(): mentiontab.timeline.add_statuses(((status,))) def on_mentions_added(self, i): status = self.twitter.statuses[i] self.notify("@%s mentioned you." % status.user.screen_name, status.text, status.user) # timeline refreshed event def on_timeline_refresh(self): if self.twitter.api.ratelimit_iplimit != -1: msg = "%d/%d %d/%d" % ( self.twitter.api.ratelimit_remaining, self.twitter.api.ratelimit_limit, self.twitter.api.ratelimit_ipremaining, self.twitter.api.ratelimit_iplimit) else: msg = "%d/%d" % ( self.twitter.api.ratelimit_remaining, self.twitter.api.ratelimit_limit) try: self.label_apilimit.set_text("API: %s" % msg) except: pass # status selection changed event def on_status_selection_changed(self, status): self.builder.get_object("menuitem_tweet").set_sensitive(True) self.statusbar.pop(0) self.statusbar.push(0, TwitterTools.get_footer(status)) # status activated event (to Reply def on_status_activated(self, status): self.reply_to_status(status) # show error on statusbar def on_twitterapi_error(self, timeline, e): if e.code == 400: message = "API rate limiting. Reset: %s" % ( self.twitter.api.ratelimit_reset.strftime("%H:%M:%S")) elif e.code == 500 or e.code == 502: message = "Twitter something is broken. Try again later." elif e.code == 503: message = "Twitter is over capacity. Try again later." else: message = "Oops! Couldn't reload timeline." self.statusbar.pop(0) self.statusbar.push(0, "[Error] %s %s (%s)" % ( timeline.getName(), message, e.code)) ######################################## # Gtk Signal Events # Status Update def on_button1_clicked(self, widget): txt = self.get_textview() if txt != "": # Status Update self.status_update_thread(txt) else: # Reload timeline if nothing in textview n = self.get_current_tab_n() self.twparams.pop("reply_to", None) if self.timelines[n] != None: self.timelines[n].reload() # key_press textview (for update status when press Ctrl + Enter) def on_textview1_key_press_event(self, textview, event): # Enter == 65293 if event.keyval == 65293 and event.state & gtk.gdk.CONTROL_MASK: txt = self.get_textview() # if update button enabled (== len(text) <= 140 if self.btnupdate.get_sensitive() and txt != "": self.status_update_thread(txt) return True # Update menu popup def on_button2_button_release_event(self, widget, event): menu = self.builder.get_object("menu_update") menu.popup(None, None, None, event.button, event.time) # Add an image to tweet def on_menuitem_add_image_activate(self, widget): dialog = gtk.FileChooserDialog("Add an image...") dialog.add_button(gtk.STOCK_OPEN, gtk.RESPONSE_OK) dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) ret = dialog.run() filename = dialog.get_filename() dialog.destroy() if ret == gtk.RESPONSE_OK: media = self.twparams.setdefault("media", list()) # duplicate image? if filename in media: self.message_dialog("Duplicate image.") return # max_media_per_upload check max_media = self.twitter.configuration.get("max_media_per_upload", 1) if len(media) >= max_media: self.message_dialog( "You can upload max %d images per upload." % max_media) return # ext check ext = os.path.splitext(filename)[1].upper() if ext not in [".JPG", ".JPEG", ".PNG", ".GIF"]: self.message_dialog( "File is not Image. Only JPG, PNG and GIF.") return # filesize check fsize = os.stat(filename).st_size limit = self.twitter.configuration.get("photo_size_limit", 3145728) if fsize > limit: self.message_dialog( "Image file size must be less than %d KB." % ( limit / 1024)) return pix = gtk.gdk.pixbuf_new_from_file(filename) ratio = float(pix.get_height()) / float(pix.get_width()) pix = pix.scale_simple(120, int(ratio * 120), gtk.gdk.INTERP_BILINEAR) img = gtk.Image() img.set_from_pixbuf(pix) box = gtk.EventBox() box.add(img) box.connect("button-release-event", self.on_image_button_release, len(media)) # add new row if len(media) % 4 == 0: self.imgtable.resize(len(media) / 4 + 1, 4) # attach image self.imgtable.attach( box, len(media) % 4, len(media) % 4 + 1, len(media) / 4, len(media) / 4 + 1, xoptions = gtk.SHRINK, yoptions = gtk.SHRINK, xpadding = 0, ypadding = 10) cursor = gtk.gdk.Cursor(gtk.gdk.HAND1) box.window.set_cursor(cursor) self.imgtable.set_visible(True) self.imgtable.show_all() # add params media.append(filename) def on_image_button_release(self, widget, event, media_num): if event.button == 1: # image clicked if sys.platform == "win32": os.startfile(self.twparams["media"][media_num]) else: os.system("xdg-open %s" % self.twparams["media"][media_num]) elif event.button == 3: # image delete r = self.message_dialog( "Are you sure you want to delete this image?", gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO) if r == gtk.RESPONSE_YES: self.imgtable.remove(widget) del self.twparams["media"][media_num] if self.twparams["media"]: self.imgtable.set_visible(False) # Timeline Tab Close def on_tabclose_clicked(self, widget, uid): n = self.tlhash[uid] del self.tlhash[uid] if self.timeline_mention == uid: self.timeline_mention = None self.notebook.remove_page(n) if self.timelines[n] != None: self.timelines[n].destroy() del self.timelines[n] for i, m in self.tlhash.iteritems(): if m > n: self.tlhash[i] -= 1 p = self.notebook.get_current_page() self.on_notebook1_switch_page( self.notebook, self.notebook.get_nth_page(p), p) # Tab right clicked def on_notebook_tabbar_button_press(self, widget, event): if event.button == 3: self.menu_timeline.popup( None, None, None, event.button, event.time) # Character count def on_textbuffer1_changed(self, buf): text = self.get_textview().decode("utf-8") # reply to user suggesstions cursor = buf.get_property("cursor-position") rspace = text.rfind(" ", 0, cursor) rat = text.rfind("@", 0, cursor) rhash = text.rfind("#", 0, cursor) prefix = postfix = None # is reply? if rat == 0 or (rspace > 0 and rat > rspace): prefix = text[rat + 1:cursor] users = self.twitter.get_users_startswith(prefix) if users: users.sort(key = lambda u: u.screen_name) postfix = users[0].screen_name[len(prefix):] # is hash? if rhash == 0 or (rspace > 0 and rhash > rspace): prefix = text[rhash + 1:cursor] hashtags = [h for h in self.twitter.hashtags if h.startswith(prefix)] if hashtags: hashtags.sort() postfix = hashtags[0][len(prefix):] # clear old suggesstions if buf.get_has_selection(): buf.delete_selection(True, True) self._text_delete_flag = False # print screen_name suggesstions if prefix and postfix and not self._text_delete_flag: cursor_iter = buf.get_iter_at_mark(buf.get_insert()) buf.insert_at_cursor(postfix) buf.select_range(buf.get_iter_at_offset(cursor), buf.get_iter_at_mark(buf.get_insert())) self._text_delete_flag = False # add footer if self.msgfooter != "" and self.twparams.get("reply_to", None): text = u"%s %s" % (text, self.msgfooter) # calculate tweet length n = TwitterTools.get_tweet_length( text, len(self.twparams.get("media", [])), self.twitter.configuration.get("short_url_length", 20), self.twitter.configuration.get("short_url_length_https", 20), self.twitter.configuration.get("characters_reserved_per_media", 20) ) if n <= 140: self.charcount.set_text(str(n)) self.btnupdate.set_sensitive(True) else: self.charcount.set_markup( "<b><span foreground='#FF0000'>%s</span></b>" % n) self.btnupdate.set_sensitive(False) def on_textbuffer1_delete_range(self, buf, start, end): self._text_delete_flag = True # Help - About menu def on_menuitem_about_activate(self, menuitem): self.builder.get_object("dialog_about").show_all() return True # About dialog closed def on_dialog_about_response(self, dialog, response_id): dialog.hide_all() # disable menu when switched tab def on_notebook1_switch_page(self, notebook, page, page_num): self.builder.get_object("menuitem_tweet").set_sensitive(False) menuitem_timeline = self.builder.get_object("menuitem_timeline") menuitem_timeline.set_sensitive(False) if page_num < 0: return False tab = self.timelines[page_num] if tab != None and tab.timeline != None: self._toggle_change_flg = True tl = tab.timeline method = tl.method default = self.get_default_interval(method) if default == -1: default = None menu_default = self.builder.get_object("menuitem_time_default") menu_default.get_child().set_text("Default (%s)" % default) interval = tl.interval if interval == default: menu_default.set_active(True) elif interval == -1: self.builder.get_object("menuitem_time_none").set_active(True) elif interval == 600: self.builder.get_object("menuitem_time_600").set_active(True) elif interval == 300: self.builder.get_object("menuitem_time_300").set_active(True) elif interval == 120: self.builder.get_object("menuitem_time_120").set_active(True) elif interval == 60: self.builder.get_object("menuitem_time_60").set_active(True) elif interval == 30: self.builder.get_object("menuitem_time_30").set_active(True) self._toggle_change_flg = False menuitem_timeline.set_sensitive(True) # Streaming API tab def on_menuitem_streaming_activate(self, menuitem): dialog = gtk.MessageDialog(buttons = gtk.BUTTONS_OK) dialog.set_markup("Please enter track keywords.") dialog.format_secondary_markup( "Examples: <i>hashtag, username, keyword</i>\n(Split comma. Unnecessary #, @)") entry = gtk.Entry() dialog.vbox.pack_start(entry) dialog.show_all() dialog.run() text = entry.get_text().decode("utf-8") dialog.destroy() params = {"track" : text.split(",")} self.new_timeline("Stream: %s" % text, "filter", **params) def on_destroy(self, widget, *args, **kwargs): widget.destroy() ######################################## # Tweet menu event def on_menuitem_reply_activate(self, menuitem): self.reply_to_selected_status() # Retweet menu clicked def on_menuitem_retweet_activate(self, memuitem): self.get_current_tab().view.retweet_selected_status() # Retweet with comment menu clicked def on_menuitem_reteet_with_comment_activate(self, memuitem): status = self.get_selected_status() name = status.user.screen_name text = status.text self.twparams.pop("reply_to", None) self.set_textview("RT @%s: %s" % (name, text), True) # Added user timeline tab def on_menuitem_usertl_activate(self, menuitem): status = self.get_selected_status() self.new_timeline("@%s" % status.user.screen_name, "user_timeline", user = status.user.id) # view conversation def on_menuitem_detail_activate(self, menuitem): status = self.get_selected_status() detail = StatusDetail(status) self.new_tab(detail, "%s: %s..." % ( status.user.screen_name, status.text[:10])) # favorite def on_menuitem_fav_activate(self, menuitem): self.get_current_tab().view.favorite_selected_status() # Destroy status def on_menuitem_destroy_activate(self, menuitem): status = self.get_selected_status() self.twitter.destory_tweet(status) # view on twitter.com def on_menuitem_ontwitter_activate(self, menuitem): status = self.get_selected_status() url = "https://twitter.com/%s/status/%s" % ( status.user.screen_name, status.id) webbrowser.open_new_tab(url) ######################################## # Timeline menu Event def change_interval(self, interval): if self._toggle_change_flg: return tl = self.get_current_tab().timeline if interval == 0: method = tl.api_method.func_name interval = self.get_default_interval(method) old = tl.interval tl.interval = interval if old == -1: tl.lock.set() def on_menuitem_time_600_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(600) def on_menuitem_time_300_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(300) def on_menuitem_time_120_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(120) def on_menuitem_time_60_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(60) def on_menuitem_time_30_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(30) def on_menuitem_time_default_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(0) def on_menuitem_time_none_toggled(self, menuitem): if menuitem.get_active() == True: self.change_interval(-1) ######################################## # Settings dialog event # Settings def on_imageitem_settings_activate(self, menuitem): home, mentions, other = self.interval # interval if home == -1: self.builder.get_object("checkbutton_home").set_active(False) if mentions == -1: self.builder.get_object("checkbutton_mentions").set_active(False) if other == -1: self.builder.get_object("checkbutton_other").set_active(False) self.builder.get_object("spinbutton_home").set_value(home) self.builder.get_object("spinbutton_mentions").set_value(mentions) self.builder.get_object("spinbutton_other").set_value(other) # status counts self.builder.get_object("spinbutton_firstn").set_value(self.scounts[0]) self.builder.get_object("spinbutton_maxn").set_value(self.scounts[1]) # show icons self.builder.get_object("checkbutton_showicon").set_active(self.iconmode) # icon cache self.builder.get_object("checkbutton_iconcache").set_active(self.iconcache) # userstream self.builder.get_object("checkbutton_userstream").set_active(self.userstream) # footer self.builder.get_object("entry_footer").set_text(self.msgfooter) # OAuth information self.builder.get_object("entry_myname").set_text(self.twitter.my_name) self.builder.get_object("entry_ckey").set_text(self.twitter.api.oauth.ckey) self.builder.get_object("entry_csecret").set_text(self.twitter.api.oauth.csecret) self.builder.get_object("entry_atoken").set_text(self.twitter.api.oauth.atoken) self.builder.get_object("entry_asecret").set_text(self.twitter.api.oauth.asecret) # Color color_entrys = (self.builder.get_object("entry_color_mytweet"), self.builder.get_object("entry_color_mentions"), self.builder.get_object("entry_color_replyto"), self.builder.get_object("entry_color_replyto_user"), self.builder.get_object("entry_color_selected_user")) for i, entry in enumerate(color_entrys): entry.set_text(self.status_color[i]) self.dsettings.show() # Close or Cancel def on_dialog_settings_close(self, widget): self.dsettings.hide() # OK def on_dialog_settings_ok(self, widget): # interval if self.builder.get_object("checkbutton_home").get_active(): home = self.builder.get_object("spinbutton_home").get_value_as_int() else: self.charcount.set_markup("<b><span foreground='#FF0000'>%s</span></b>" % n) self.btnupdate.set_sensitive(False) home = -1 if self.builder.get_object("checkbutton_mentions").get_active(): mentions = self.builder.get_object("spinbutton_mentions").get_value_as_int() else: mentions = -1 if self.builder.get_object("checkbutton_other").get_active(): other = self.builder.get_object("spinbutton_other").get_value_as_int() else: other = -1 self.interval = (home, mentions, other) # status counts self.scounts = ( self.builder.get_object("spinbutton_firstn").get_value_as_int(), self.builder.get_object("spinbutton_maxn").get_value_as_int()) # show icons self.iconmode = self.builder.get_object("checkbutton_showicon").get_active() # icon cache self.iconcache = self.builder.get_object("checkbutton_iconcache").get_active() # userstream self.userstream = self.builder.get_object("checkbutton_userstream").get_active() # footer self.msgfooter = unicode(self.builder.get_object("entry_footer").get_text()) # Color self.status_color = (self.builder.get_object("entry_color_mytweet").get_text(), self.builder.get_object("entry_color_mentions").get_text(), self.builder.get_object("entry_color_replyto").get_text(), self.builder.get_object("entry_color_replyto_user").get_text(), self.builder.get_object("entry_color_selected_user").get_text()) for t in self.timelines: if t != None: t.view.set_color(self.status_color) self.save_settings() self.dsettings.hide() # toggle checkbox def on_checkbutton_home_toggled(self, checkbutton): sb = self.builder.get_object("spinbutton_home") sb.set_sensitive(checkbutton.get_active()) def on_checkbutton_mentions_toggled(self, checkbutton): sb = self.builder.get_object("spinbutton_mentions") sb.set_sensitive(checkbutton.get_active()) def on_checkbutton_other_toggled(self, checkbutton): sb = self.builder.get_object("spinbutton_other") sb.set_sensitive(checkbutton.get_active()) def on_entry_color_changed(self, entry): entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(entry.get_text())) # Color selection dialog open def on_button_color1_clicked(self, widget): entry = self.builder.get_object("entry_color_mytweet") self.color_dialog_run("My status", entry.get_text(), entry) def on_button_color2_clicked(self, widget): entry = self.builder.get_object("entry_color_mentions") self.color_dialog_run("Mentions to me", entry.get_text(), entry) def on_button_color3_clicked(self, widget): entry = self.builder.get_object("entry_color_replyto") self.color_dialog_run("Reply to", entry.get_text(), entry) def on_button_color4_clicked(self, widget): entry = self.builder.get_object("entry_color_replyto_user") self.color_dialog_run("Reply to user", entry.get_text(), entry) def on_button_color5_clicked(self, widget): entry = self.builder.get_object("entry_color_selected_user") self.color_dialog_run("Selected user", entry.get_text(), entry)