--- /dev/null
+#-*- coding: utf-8 -*-
+
+'''Get Twitter following/followers wizard
+'''
+
+################################################################################
+#
+# Copyright (c) 2011 University of Tsukuba Linux User Group
+#
+# This file is part of "gwit".
+#
+# "gwit" is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# "gwit" is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with "gwit". If not, see <http://www.gnu.org/licenses/>.
+#
+################################################################################
+
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+
+import threading
+
+class GetFriendsWizard(gtk.Assistant):
+ twitter = None
+
+ def __init__(self):
+ gtk.Assistant.__init__(self)
+ self.connect("cancel", self.on_cancel_close)
+ self.connect("close", self.on_cancel_close)
+ self.connect("apply", self.on_apply)
+
+ # page1
+ self.page1 = gtk.Label("""
+
+This process may take a few minutes.
+If you have too many followings/followers,
+you should mind remaining API limit.
+(Get 100 followings/followers per call)
+
+""")
+
+ # page2
+ self.chkfr = gtk.CheckButton("Get all friends")
+ self.chkfo = gtk.CheckButton("Get all followers")
+ self.chkfr.connect("toggled", self.on_check_toggled)
+ self.chkfo.connect("toggled", self.on_check_toggled)
+
+ box = gtk.VBox(spacing = 10)
+ box.pack_start(self.chkfr)
+ box.pack_end(self.chkfo)
+ self.page2 = box
+
+ # page3
+ buf = gtk.TextBuffer()
+ view = gtk.TextView(buf)
+ self.page3 = gtk.ScrolledWindow()
+ self.page3.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.page3.add(view)
+ view.set_editable(False)
+
+ # page4
+ self.page4 = gtk.Label("""Get followings/followers information successfully!
+There will add to user selection after few seconds.""")
+
+ self.append_page(self.page1)
+ self.set_page_title(self.page1, "Get followings/followers")
+ self.set_page_type(self.page1, gtk.ASSISTANT_PAGE_INTRO)
+ self.set_page_complete(self.page1, True)
+
+ self.append_page(self.page2)
+ self.set_page_title(self.page2, "Get followings/followers")
+ self.set_page_type(self.page2, gtk.ASSISTANT_PAGE_CONFIRM)
+
+ self.append_page(self.page3)
+ self.set_page_title(self.page3, "Getting...")
+ self.set_page_type(self.page3, gtk.ASSISTANT_PAGE_PROGRESS)
+ self.set_page_complete(self.page3, False)
+
+ self.append_page(self.page4)
+ self.set_page_title(self.page4, "Complete!")
+ self.set_page_type(self.page4, gtk.ASSISTANT_PAGE_SUMMARY)
+
+ # get users
+ def _get_users_in_thread(self):
+ def p(buf, text):
+ gtk.gdk.threads_enter()
+ buf.insert_at_cursor(text)
+ gtk.gdk.threads_leave()
+
+ users = dict()
+ log = self.page3.get_child().get_buffer()
+
+ if self.chkfr.get_active():
+ p(log, "=== Getting friedns ===\n")
+ cursor = -1
+ while cursor != 0:
+ p(log, "GET: %s\n" % cursor)
+
+ r = self.twitter.api_wrapper(self.twitter.api.friends, cursor = cursor)
+ cursor = r["next_cursor"]
+ users.update([(i.id, i) for i in r["users"]])
+
+ p(log, "%d users\n" % len(users))
+
+ if self.chkfo.get_active():
+ p(log, "=== Getting followers ===\n")
+ cursor = -1
+ while cursor != 0:
+ p(log, "GET: %s\n" % cursor)
+
+ r = self.twitter.api_wrapper(self.twitter.api.followers, cursor = cursor)
+ cursor = r["next_cursor"]
+ users.update([(i.id, i) for i in r["users"]])
+
+ p(log, "%d users\n" % len(users))
+
+ p(log, "\nDone.\n")
+ gtk.gdk.threads_enter()
+ self.set_page_complete(self.page3, True)
+ gtk.gdk.threads_leave()
+
+ self.twitter.add_users(users)
+
+ def on_cancel_close(self, widget):
+ widget.hide_all()
+ widget.destroy()
+
+ def on_apply(self, assistant):
+ threading.Thread(target = self._get_users_in_thread).start()
+
+ # page2 checkbox
+ def on_check_toggled(self, check):
+ if self.chkfr.get_active() or self.chkfo.get_active():
+ self.set_page_complete(self.page2, True)
+ else:
+ self.set_page_complete(self.page2, False)
+++ /dev/null
-<?xml version="1.0"?>
-<interface>
- <requires lib="gtk+" version="2.16"/>
- <!-- interface-naming-policy project-wide -->
- <object class="GtkAssistant" id="assistant_getfollow">
- <property name="border_width">12</property>
- <property name="title" translatable="yes">Get followings/followers</property>
- <signal name="prepare" handler="on_assistant_getfollow_prepare"/>
- <signal name="apply" handler="on_assistant_getfollow_apply"/>
- <signal name="cancel" handler="on_assistant_getfollow_cancel"/>
- <child>
- <placeholder/>
- </child>
- <child>
- <object class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Get all followings/followers wizard.
-This process may take a few minutes.
-If you have too many followings/followers, you should check remaining API limit.
-(Get 20 followings/followers per call)
-</property>
- <property name="use_markup">True</property>
- </object>
- <packing>
- <property name="page_type">intro</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="vbox1">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkHBox" id="hbox1">
- <property name="visible">True</property>
- <child>
- <object class="GtkCheckButton" id="checkbutton1">
- <property name="label" translatable="yes">Followings</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinButton" id="spinbutton1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">●</property>
- <property name="climb_rate">20</property>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkHBox" id="hbox2">
- <property name="visible">True</property>
- <child>
- <object class="GtkCheckButton" id="checkbutton2">
- <property name="label" translatable="yes">Followers</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinButton" id="spinbutton2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">●</property>
- <property name="climb_rate">20</property>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="page_type">confirm</property>
- </packing>
- </child>
- <child>
- <object class="GtkTextView" id="textview1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </object>
- <packing>
- <property name="page_type">progress</property>
- </packing>
- </child>
- </object>
-</interface>
self.stores.append((store, n))
def remove_store(self, store):
+ remove = None
+
for i in self.stores:
if store == i[0]:
- self.stores.remove(i)
+ remove = i
+ break
+
+ if remove:
+ self.stores.remove(remove)
class NewIcon(threading.Thread):
def __init__(self, user, stores, icons, semaphore):
# Icon Refresh
for store, n in self.stores:
- for row in store:
- # replace icon to all user's status
+ for row in store:
+ # replace icon to all user's status
if row[n] == self.user.id:
gtk.gdk.threads_enter()
store[row.path][0] = icopix
from listsselection import ListsSelection, ListsView
from statusdetail import StatusDetail
from twittertools import TwitterTools
+from getfriendswizard import GetFriendsWizard
# Main Class
class Main(object):
# Constractor
def __init__(self, screen_name, keys):
# Gtk Multithread Setup
- gtk.gdk.threads_init()
- gobject.threads_init()
+ if sys.platform == "win32":
+ gobject.threads_init()
+ else:
+ gtk.gdk.threads_init()
# init status timelines
self.timelines = list()
ListsView.iconstore = self.iconstore
UserSelection.twitter = self.twitter
UserSelection.iconstore = self.iconstore
+ GetFriendsWizard.twitter = self.twitter
self.initialize()
def main(self):
- gtk.gdk.threads_enter()
window = self.builder.get_object("window1")
# settings allocation
# Start gtk main loop
gtk.main()
- gtk.gdk.threads_leave()
def read_settings(self):
try:
return color
def status_update_thread(self, status):
- t = threading.Thread(target = self.status_update, args = (status,))
+ t = threading.Thread(target = self._status_update, args = (status,))
t.start()
- def status_update(self, status):
+ def _status_update(self, status):
args = dict()
gtk.gdk.threads_enter()
self._old_path = None
# for width changed
self._old_width = None
+
+ self.render_event = threading.Event()
+ self._render_color_only = False
+
+ # background thread for rewrite
+ t = threading.Thread(target=self._render_thread)
+ t.setName("status render")
+ t.setDaemon(True)
+ t.start()
# Get selected status
def get_selected_status(self):
long(i), long(status.user.id),
background, favico)
+ # background render thread function
+ def _render_thread(self):
+ while True:
+ self.render_event.wait()
+ self.render_event.clear()
+
+ status = self._render_color_only
+ self._render_color_only = False
+
+ if status == False:
+ self._reset_status_text_in_thread()
+ status = None
+
+ self._color_status_in_thread(status)
+
# Color status
def color_status(self, status = None):
- t = threading.Thread(target=self.color_status_in_thread, args=(status,))
- t.setName("color_status")
- t.start()
+ self._render_color_only = status
+ self.render_event.set()
- def color_status_in_thread(self, status = None):
+ def _color_status_in_thread(self, status = None):
myname = self.twitter.my_name
myid = self.twitter.my_id
status = self.get_selected_status()
for row in self.store:
+ if self.render_event.is_set(): break
+
bg = None
status_id = row[2]
self.store[row.path][4] = bg
gtk.gdk.threads_leave()
+ # Reset all data to change row height
+ def reset_status_text(self):
+ self.render_event.set()
+
+ def _reset_status_text_in_thread(self):
+ for row in self.store:
+ if self.render_event.is_set(): break
+
+ status_id = row[2]
+ packed_row = self.status_pack(status_id)
+
+ gtk.gdk.threads_enter()
+ self.store[row.path] = packed_row
+ gtk.gdk.threads_leave()
########################################
# Gtk Signal Events
# Really changed?
# (this event is called when add statuses too.)
- if self._old_width == text_width:
- return
- else:
+ if self._old_width != text_width:
self._old_width = text_width
-
- # Set "Status" width
- cellr = columns[1].get_cell_renderers()
- cellr[0].set_property("wrap-width", text_width)
-
- def refresh_text():
- # Reset all data to change row height
- for row in self.store:
- # Maybe no affects performance
- # if treeview.allocation.width != width:
- # break
- status_id = row[2]
- packed_row = self.status_pack(status_id)
-
- gtk.gdk.threads_enter()
- self.store[row.path] = packed_row
- gtk.gdk.threads_leave()
- self.color_status_in_thread()
-
- t = threading.Thread(target=refresh_text)
- t.setName("refresh_text")
- t.start()
+ # Set "Status" width
+ cellr = columns[1].get_cell_renderers()
+ cellr[0].set_property("wrap-width", text_width)
+
+ self.reset_status_text()
def on_treeview_destroy(self, treeview):
self.iconstore.remove_store(self.store)
def get_followers(self):
self.followers.update([int(i) for i in self.api_wrapper(self.api.followers_ids)])
- def add_statuses(self, slist):
- for i in slist:
+ def add_statuses(self, statuses):
+ for i in statuses:
self.add_status(i)
def add_status(self, status):
if status.retweeted_status != None:
self.add_status(status.retweeted_status)
+ def add_users(self, users):
+ if isinstance(users, dict):
+ self.users.update(users)
+ else:
+ self.users.update([(i.id, i) for i in users])
+
def add_user(self, user):
self.users[user.id] = user
self.on_twitterapi_requested()
self.apilock.release()
- time.sleep(5)
+ time.sleep(1)
return response
import time
from twittertools import TwitterTools
+from getfriendswizard import GetFriendsWizard
class UserSelection(gtk.VBox):
twitter = None
button_add.set_image(gtk.image_new_from_stock("gtk-add", gtk.ICON_SIZE_BUTTON))
button_add.connect("clicked", self.on_button_add_clicked)
hbox.pack_start(button_add, expand = False, padding = 5)
-
+
+ # get followings/followers button
button_refresh = gtk.Button()
button_refresh.set_image(gtk.image_new_from_stock("gtk-refresh", gtk.ICON_SIZE_BUTTON))
button_refresh.connect("clicked", self.on_button_refresh_clicked)
else:
self.treeview.get_model().set_sort_column_id(n, gtk.SORT_ASCENDING if n == 1 else gtk.SORT_DESCENDING)
+ # open get followings followers wizard
def on_button_refresh_clicked(self, button):
- builder = gtk.Builder()
- gladefile = os.path.join(os.path.dirname(__file__), "glade/getfollow.glade")
- builder.add_from_file(gladefile)
- builder.connect_signals(self)
- win = builder.get_object("assistant_getfollow")
- win.show_all()
-
- def on_assistant_getfollow_prepare(self, assistant, page):
- pass
-
- def on_assistant_getfollow_apply(self, assistant):
- assistant.destroy()
-
- def on_assistant_getfollow_cancel(self, assistant):
- assistant.destroy()
+ w = GetFriendsWizard()
+ w.show_all()