Compare commits

...

26 Commits

Author SHA1 Message Date
c4478198b6 NEw snapshot 2015-08-31 11:18:10 -05:00
f468924b85 Merge branch 'next-gen' of https://github.com/manuelcortez/TWBlue into next-gen 2015-08-31 11:03:54 -05:00
158b48e4d5 Add and remove user to list are implemented in GUI 2015-08-31 10:08:34 -05:00
756a58e443 New timeline sound is played again 2015-08-31 08:42:28 -05:00
85ce5b0791 Trending topics now have their names at startup 2015-08-31 08:15:37 -05:00
Jose Manuel Delicado
e534d1cd20 Updated readme. 2015-08-28 11:47:54 +02:00
2d35304ef0 New snapshot 2015-08-27 08:13:01 -05:00
4f0e6d758b Restores buffer positions at startup using cached database 2015-08-25 13:37:31 -05:00
bd4aa89c2b Added text_focus() in some actions to the tweet dialogue 2015-08-24 10:00:34 -05:00
b046360293 Added right click menu in buffers 2015-08-24 09:54:15 -05:00
6971fb3999 Bugfix in retweet with comment 2015-08-21 09:55:05 -05:00
7b840f29c4 Keystroke editor can execute the actions directly 2015-08-21 09:51:01 -05:00
71fed7300b IF there are no tweets or favs, the timeline is not created 2015-08-21 09:12:54 -05:00
57315c3b6e open_timeline() cleaned 2015-08-21 08:57:15 -05:00
3d3abc90e1 Expanded URL are displayed in the view tweet dialogue 2015-08-20 17:57:06 -05:00
de7882e4cf Logout session improvements 2015-08-20 17:32:27 -05:00
jmdaweb
10190d61c0 Fixed windows dependencies submodule. Please, don't forget to run git submodule update before sending a commit or pull request. 2015-08-19 13:38:10 +02:00
bb6fa7cb46 logout() now removes database for the session 2015-08-19 05:28:56 -05:00
80cb70c9a6 Merge branch 'next-gen' of https://github.com/manuelcortez/TWBlue into next-gen 2015-08-18 08:05:21 -05:00
77d51aa51a New snapshot 2015-08-18 08:04:58 -05:00
jmdaweb
ebb4e22d02 Updated Windows dependencies. Now wx buttons and messages should be localized. 2015-08-16 15:42:17 +02:00
4344a0df0c Get full text for dm buffers 2015-08-12 17:21:00 -05:00
34ad0c5e47 Reconnecting streams every 5 mins 2015-08-12 16:43:23 -05:00
704ade560a Increasing character limit for direct messages 2015-08-12 15:57:29 -05:00
a4892cf847 TWBlue does not change the current session in invisible interface 2015-08-11 08:58:11 -05:00
e59661775a Updated translations 2015-08-10 09:49:16 -05:00
39 changed files with 8306 additions and 15953 deletions

View File

@@ -39,7 +39,7 @@ If you want to build both x86 and x64 binaries, you can install python x86 to C:
* [Pycurl](http://pycurl.sourceforge.net) 7.19.5.1 for Python 2.7: [32-bit downloads,](https://pypi.python.org/pypi/pycurl/7.19.5.1) [64-bit downloads](http://www.lfd.uci.edu/~gohlke/pythonlibs/)
Note: the x64 version is in wheel format instead of executable installer, so you have to install it using pip. For example: C:\python27x64\scripts\pip install pycurl-7.19.5.1-cp27-none-win_amd64.whl
* [PyEnchant,](http://pythonhosted.org/pyenchant/) version 1.6.6.
x64 version has been built by TW Blue developers, so you only will find it in windows-dependencies folder
x64 version has been built by TWBlue developers, so you only will find it in windows-dependencies folder
The windows installers are available only in the windows-dependencies folder
@@ -71,8 +71,11 @@ setuptools install a script, called easy_install. You can find it in the python
* arrow
* goslate
* markdown
* pocket
easy_install will automatically get the additional libraries that these packages need to work properly.
Run the following command to quickly install and upgrade all packages and their dependencies:
easy_install -Z --upgrade six configobj goslate markdown future pocket suds requests oauthlib requests-oauthlib pypubsub pygeocoder arrow
#### Other dependencies
@@ -95,9 +98,16 @@ Now that you have installed all these packages, you can run TW Blue from source
If necessary, change the first part of the command to reflect the location of your python executable. You can run TW Blue using python x86 and x64
### Generating the documentation
To generate the documentation in html format, navigate to the doc folder inside this repo. After that, run this command:
python generator.py
The documentation will be generated, placing each language in a separate folder in the doc directory. Move these folders (for example de, en, es, fr, it, ...) to src/documentation, creating the directory if necesary.
Also, copy the license.txt located in the root of the repo to the documentation folder.
### Building a binary version
A binary version doesn't need python and the other dependencies to run, it's the same version that you will find on the TW Blue website if you download the zip files.
A binary version doesn't need python and the other dependencies to run, it's the same version that you will find on the TW Blue website if you download the zip files or the snapshot versions.
To build it, run the following command from the src folder:
@@ -105,6 +115,17 @@ To build it, run the following command from the src folder:
You will find the binaries in the dist directory.
### Building an installer
If you want to install TWBlue in your computer, you must create the installer first. Follow these steps:
* Navigate to the src directory, and create a binary version for x86: C:\python27\python setup.py py2exe
* Move the dist directory to the scripts folder in this repo, and rename it to twblue
* Repeat these steps with Python for x64: C:\python27x64\python setup.py py2exe
* Move the new dist directory to the scripts folder, and rename it to twblue64
* Go to the scripts folder, right click on the twblue.nsi file, and choose compyle unicode NSIS script
* This may take a while. After the process, you will find the installer in the scripts folder
### How to generate a translation template
Run the gen_pot.bat file, located in the tools directory. Your python installation must be in your path environment variable. The pot file will appear in the tools directory.

View File

@@ -5,7 +5,7 @@ if snapshot == False:
version = "0.80"
update_url = 'http://twblue.es/updates/twblue_ngen.json'
else:
version = "10.2"
version = "10.6"
update_url = 'http://twblue.es/updates/snapshots_ngen.json'
author = u"Manuel Cortéz, Bill Dengler"
authorEmail = "manuel@manuelcortez.net"

View File

@@ -2,7 +2,7 @@
import platform
if platform.system() == "Windows":
import wx
from wxUI import buffers, dialogs, commonMessageDialogs
from wxUI import buffers, dialogs, commonMessageDialogs, menus
import user
elif platform.system() == "Linux":
from gi.repository import Gtk
@@ -142,6 +142,13 @@ class bufferController(object):
call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image)
if hasattr(tweet.message, "destroy"): tweet.message.destroy()
def save_positions(self):
try:
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
except AttributeError:
pass
class accountPanel(bufferController):
def __init__(self, parent, name, account, account_id):
super(accountPanel, self).__init__(parent, None, name)
@@ -235,6 +242,10 @@ class baseBufferController(bufferController):
uri = tweet["long_uri"]
try:
tweet = self.session.twitter.twitter.show_status(id=tweet_id)
urls = utils.find_urls_in_text(tweet["text"])
for url in range(0, len(urls)):
try: tweet["text"] = tweet["text"].replace(urls[url], tweet["entities"]["urls"][url]["expanded_url"])
except IndexError: pass
except TwythonError as e:
utils.twitter_error(e)
return
@@ -246,6 +257,10 @@ class baseBufferController(bufferController):
id = tweets.get_id(l)
try:
tweet = self.session.twitter.twitter.show_status(id=id)
urls = utils.find_urls_in_text(tweet["text"])
for url in range(0, len(urls)):
try: tweet["text"] = tweet["text"].replace(urls[url], tweet["entities"]["urls"][url]["expanded_url"])
except IndexError: pass
except TwythonError as e:
utils.twitter_error(e)
return
@@ -357,6 +372,61 @@ class baseBufferController(bufferController):
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.retweet, self.buffer.retweet)
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.direct_message, self.buffer.dm)
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.reply, self.buffer.reply)
# Replace for the correct way in other platforms.
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key)
def show_menu(self, ev, pos=0, *args, **kwargs):
if self.buffer.list.get_count() == 0: return
if self.name == "sent_tweets" or self.name == "sent_direct_messages":
menu = menus.sentPanelMenu()
elif self.name == "direct_messages":
menu = menus.dmPanelMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.direct_message, menuitem=menu.reply)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
else:
menu = menus.basePanelMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.reply, menuitem=menu.reply)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.retweet, menuitem=menu.retweet)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.fav, menuitem=menu.fav)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unfav, menuitem=menu.unfav)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.url_, menuitem=menu.openUrl)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.audio, menuitem=menu.play)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove)
if pos != 0:
self.buffer.PopupMenu(menu, pos)
else:
self.buffer.PopupMenu(menu, ev.GetPosition())
def view(self, *args, **kwargs):
pub.sendMessage("execute-action", action="view_item")
def copy(self, *args, **kwargs):
pub.sendMessage("execute-action", action="copy_to_clipboard")
def user_actions(self, *args, **kwargs):
pub.sendMessage("execute-action", action="follow")
def fav(self, *args, **kwargs):
pub.sendMessage("execute-action", action="add_to_favourites")
def unfav(self, *args, **kwargs):
pub.sendMessage("execute-action", action="remove_from_favourites")
def delete_item_(self, *args, **kwargs):
pub.sendMessage("execute-action", action="delete_item")
def url_(self, *args, **kwargs):
self.url()
def show_menu_by_key(self, ev):
if self.buffer.list.get_count() == 0:
return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
def get_tweet(self):
if self.session.db[self.name][self.buffer.list.get_selected()].has_key("retweeted_status"):
@@ -423,7 +493,7 @@ class baseBufferController(bufferController):
self._retweet_with_comment(tweet, id)
def _retweet_with_comment(self, tweet, id, comment=''):
retweet = messages.tweet(self.session, _(u"Retweet"), _(u"Add your comment to the tweet"), u"“@%s: %s" % (tweet["user"]["screen_name"], tweet["text"]), max=116-len("@%s " % (tweet["user"]["screen_name"],)), messageType="retweet", twishort_enabled=self.session.settings["mysc"]["twishort_enabled"])
retweet = messages.tweet(self.session, _(u"Retweet"), _(u"Add your comment to the tweet"), u"“@%s: %s" % (tweet["user"]["screen_name"], tweet["text"]), max=116, messageType="retweet", twishort_enabled=self.session.settings["mysc"]["twishort_enabled"])
if comment != '':
retweet.message.set_text(comment)
if retweet.message.get_response() == widgetUtils.OK:
@@ -457,10 +527,9 @@ class baseBufferController(bufferController):
self.session.sound.play("audio.ogg")
if utils.is_geocoded(tweet):
self.session.sound.play("geo.ogg")
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
@_tweets_exist
def audio(self,url=''):
# @_tweets_exist
def audio(self, url='', *args, **kwargs):
if hasattr(sound.URLPlayer,'stream'):
return sound.URLPlayer.stop_audio(delete=True)
tweet = self.get_tweet()
@@ -480,8 +549,8 @@ class baseBufferController(bufferController):
except:
log.error("Exception while executing audio method.")
@_tweets_exist
def url(self,url='',announce=True):
# @_tweets_exist
def url(self, url='', announce=True, *args, **kwargs):
if url == '':
tweet = self.get_tweet()
urls = utils.find_urls(tweet)
@@ -599,6 +668,23 @@ class eventsBufferController(bufferController):
if dlg == widgetUtils.YES:
self.buffer.list.clear()
def show_menu(self, ev, pos=0, *args, **kwargs):
if self.buffer.list.get_count() == 0: return
menu = menus.eventsPanelMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove)
if pos != 0:
self.buffer.PopupMenu(menu, pos)
else:
self.buffer.PopupMenu(menu, ev.GetPosition())
def view(self, *args, **kwargs):
pub.sendMessage("execute-action", action="view_item")
def copy(self, *args, **kwargs):
pub.sendMessage("execute-action", action="copy_to_clipboard")
class peopleBufferController(baseBufferController):
def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs):
super(peopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel")
@@ -709,6 +795,22 @@ class peopleBufferController(baseBufferController):
def interact(self):
user.profileController(self.session, user=self.get_right_tweet()["screen_name"])
def show_menu(self, ev, pos=0, *args, **kwargs):
menu = menus.peoplePanelMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.direct_message, menuitem=menu.reply)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details)
# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
if pos != 0:
self.buffer.PopupMenu(menu, pos)
else:
self.buffer.PopupMenu(menu, ev.GetPosition())
def details(self, *args, **kwargs):
pub.sendMessage("execute-action", action="user_details")
class searchBufferController(baseBufferController):
def start_stream(self):
log.debug("Starting stream for %s buffer, %s account and %s type" % (self.name, self.account, self.type))
@@ -815,6 +917,8 @@ class trendsBufferController(bufferController):
# widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.retweet, self.buffer.retweet)
# widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.direct_message, self.buffer.dm)
# widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.reply, self.buffer.reply)
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key)
def get_message(self):
return self.compose_function(self.trends[self.buffer.list.get_selected()])[0]
@@ -832,6 +936,48 @@ class trendsBufferController(bufferController):
def interact(self, *args, **kwargs):
self.searchfunction(value=self.get_message())
def show_menu(self, ev, pos=0, *args, **kwargs):
menu = menus.trendsPanelMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.tweet_about_this_trend, menuitem=menu.tweetThisTrend)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
if pos != 0:
self.buffer.PopupMenu(menu, pos)
else:
self.buffer.PopupMenu(menu, ev.GetPosition())
def view(self, *args, **kwargs):
pub.sendMessage("execute-action", action="view_item")
def copy(self, *args, **kwargs):
pub.sendMessage("execute-action", action="copy_to_clipboard")
def tweet_about_this_trend(self, *args, **kwargs):
if self.buffer.list.get_count() == 0: return
title = _(u"Tweet")
caption = _(u"Write the tweet here")
tweet = messages.tweet(self.session, title, caption, self.get_message()+ " ", twishort_enabled=self.session.settings["mysc"]["twishort_enabled"])
tweet.message.set_cursor_at_end()
if tweet.message.get_response() == widgetUtils.OK:
self.session.settings["mysc"]["twishort_enabled"] = tweet.message.long_tweet.GetValue()
text = tweet.message.get_text()
if len(text) > 140 and tweet.message.get("long_tweet") == True:
if tweet.image == None:
text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text)
else:
text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1)
if tweet.image == None:
call_threaded(self.session.api_call, call_name="update_status", status=text)
else:
call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image)
if hasattr(tweet.message, "destroy"): tweet.message.destroy()
def show_menu_by_key(self, ev):
if self.buffer.list.get_count() == 0:
return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
class conversationBufferController(searchBufferController):
def start_stream(self, start=False):

View File

@@ -97,7 +97,7 @@ class Controller(object):
def get_buffers_for_account(self, account):
results = []
buffers = self.view.get_buffers()
[results.append(self.search_buffer(i.name, i.account)) for i in buffers if i.account == account]
[results.append(self.search_buffer(i.name, i.account)) for i in buffers if i.account == account and (i.type != "account")]
return results
def bind_stream_events(self):
@@ -125,10 +125,10 @@ class Controller(object):
log.debug("Binding other application events...")
pub.subscribe(self.logout_account, "logout")
pub.subscribe(self.login_account, "login")
pub.subscribe(self.manage_stream_errors, "stream-error")
pub.subscribe(self.manage_stream_errors, "streamError")
pub.subscribe(self.create_new_buffer, "create-new-buffer")
pub.subscribe(self.restart_streams, "restart-streams")
pub.subscribe(self.execute_action, "execute-action")
if system == "Windows":
pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed")
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide)
@@ -174,6 +174,8 @@ class Controller(object):
widgetUtils.connect_event(self.view.nb, widgetUtils.NOTEBOOK_PAGE_CHANGED, self.buffer_changed)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_documentation, self.view.doc)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_list, self.view.addToList)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_list, self.view.removeFromList)
def set_systray_icon(self):
self.systrayIcon = sysTrayIcon.SysTrayIcon()
@@ -235,7 +237,6 @@ class Controller(object):
self.create_ignored_session_buffer(session_.sessions[i])
continue
self.create_buffers(session_.sessions[i])
self.set_buffer_positions(session_.sessions[i])
# Connection checker executed each minute.
self.checker_function = RepeatingTimer(60, self.check_connection)
@@ -246,6 +247,7 @@ class Controller(object):
for i in session_.sessions:
if session_.sessions[i].is_logged == False: continue
self.start_buffers(session_.sessions[i])
self.set_buffer_positions(session_.sessions[i])
if config.app["app-settings"]["play_ready_sound"] == True:
session_.sessions[session_.sessions.keys()[0]].sound.play("ready.ogg")
if config.app["app-settings"]["speak_ready_msg"] == True:
@@ -263,6 +265,7 @@ class Controller(object):
for i in session_.sessions:
if session_.sessions[i].session_id == session_id: session = session_.sessions[i]
session.login()
session.db = dict()
self.create_buffers(session, False)
self.start_buffers(session)
@@ -286,11 +289,11 @@ class Controller(object):
self.buffers.append(mentions)
self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
elif i == 'dm':
dm = buffersController.baseBufferController(self.view.nb, "get_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", sound="dm_received.ogg")
dm = buffersController.baseBufferController(self.view.nb, "get_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", sound="dm_received.ogg", full_text=True)
self.buffers.append(dm)
self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
elif i == 'sent_dm':
sent_dm = buffersController.baseBufferController(self.view.nb, "get_sent_messages", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel")
sent_dm = buffersController.baseBufferController(self.view.nb, "get_sent_messages", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", full_text=True)
self.buffers.append(sent_dm)
self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
elif i == 'sent_tweets':
@@ -360,41 +363,28 @@ class Controller(object):
buffer.start_stream()
buffer.searchfunction = self.search
self.buffers.append(buffer)
self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (buffer.name_), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
buffer.timer = RepeatingTimer(300, buffer.start_stream)
buffer.timer.start()
self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (buffer.name_), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
def set_buffer_positions(self,session):
"Sets positions for buffers if values exist in the database."
for i in self.buffers:
if i.name+"_pos" in session.db and hasattr(i.buffer,'list'):
if i.account == session.db["user_name"] and session.db.has_key(i.name+"_pos") and hasattr(i.buffer,'list'):
i.buffer.list.select_item(session.db[str(i.name+"_pos")])
def logout_account(self, session_id):
for i in session_.sessions:
if session_.sessions[i].session_id == session_id: session = session_.sessions[i]
user = session.db["user_name"]
self.destroy_buffer("home_timeline", user)
self.destroy_buffer("mentions", user)
self.destroy_buffer("direct_messages", user)
self.destroy_buffer("sent_direct_messages", user)
self.destroy_buffer("sent_tweets", user)
self.destroy_buffer("favourites", user)
self.destroy_buffer("followers", user)
self.destroy_buffer("friends", user)
self.destroy_buffer("blocked", user)
self.destroy_buffer("muted", user)
self.destroy_buffer("events", user)
self.destroy_buffer("timelines", user)
for i in session.settings["other_buffers"]["timelines"]:
self.destroy_buffer("%s-timeline" % (i,), user)
self.destroy_buffer("favs_timelines", user)
self.destroy_buffer("searches", user)
for i in session.settings["other_buffers"]["tweet_searches"]:
self.destroy_buffer("%s-searchterm" % (i,), user)
for i in session.settings["other_buffers"]["trending_topic_buffers"]:
self.destroy_buffer("%s_tt" % (i,), user)
delete_buffers = []
for i in self.buffers:
if i.account == user and i.name != user:
delete_buffers.append(i.name)
for i in delete_buffers:
self.destroy_buffer(i, user)
session.db = None
def destroy_buffer(self, buffer_name, account):
buffer = self.search_buffer(buffer_name, account)
if buffer == None: return
@@ -508,8 +498,32 @@ class Controller(object):
except TwythonError as e:
output.speak("error %s: %s" % (e.error_code, e.msg))
def remove_from_list(self, user):
pass
def remove_from_list(self, *args, **kwargs):
buff = self.get_best_buffer()
if not hasattr(buff, "get_right_tweet"): return
tweet = buff.get_right_tweet()
if buff.type != "people":
users = utils.get_all_users(tweet, buff.session.db)
else:
users = [tweet["screen_name"]]
dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users)
if dlg.get_response() == widgetUtils.OK:
user = dlg.get_user()
else:
return
dlg = dialogs.lists.removeUserListDialog()
dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]])
if dlg.get_response() == widgetUtils.OK:
try:
list = buff.session.twitter.twitter.delete_list_member(list_id=buff.session.db["lists"][dlg.get_item()]["id"], screen_name=user)
older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()]["id"], buff.session.db["lists"])
listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()]["name"].lower()), buff.session.db["user_name"])
if listBuffer != None: listBuffer.get_user_ids()
buff.session.db["lists"].pop(older_list)
buff.session.db["lists"].append(list)
if listBuffer != None: pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buff.session)
except TwythonError as e:
output.speak("error %s: %s" % (e.error_code, e.msg))
def list_manager(self, *args, **kwargs):
s = self.get_best_buffer().session
@@ -561,6 +575,7 @@ class Controller(object):
self.exit_()
def exit_(self, *args, **kwargs):
for i in self.buffers: i.save_positions()
log.debug("Exiting...")
log.debug("Saving global configuration...")
config.app.write()
@@ -718,8 +733,7 @@ class Controller(object):
users = [tweet["screen_name"]]
dlg = dialogs.userSelection.selectUserDialog(users=users, default=default)
if dlg.get_response() == widgetUtils.OK:
buffer = self.get_best_buffer()
usr = utils.if_user_exists(buffer.session.twitter.twitter, dlg.get_user())
usr = utils.if_user_exists(buff.session.twitter.twitter, dlg.get_user())
if usr != None:
if usr["protected"] == True:
if usr["following"] == False:
@@ -728,32 +742,38 @@ class Controller(object):
answer = commonMessageDialogs.protected_user()
if answer == widgetUtils.NO: return
if dlg.get_action() == "tweets":
if dlg.get_user() in buffer.session.settings["other_buffers"]["timelines"]:
if usr["statuses_count"] == 0:
commonMessageDialogs.no_tweets()
return
if dlg.get_user() in buff.session.settings["other_buffers"]["timelines"]:
commonMessageDialogs.timeline_exist()
return
tl = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (dlg.get_user(),), buffer.session, buffer.session.db["user_name"], bufferType=None, screen_name=dlg.get_user())
tl = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (dlg.get_user(),), buff.session, buff.session.db["user_name"], bufferType=None, screen_name=dlg.get_user())
tl.start_stream()
pos=self.view.search("timelines", buffer.session.db["user_name"])
pos=self.view.search("timelines", buff.session.db["user_name"])
self.insert_buffer(tl, pos+1)
# self.buffers.insert(pos+1, tl)
self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(dlg.get_user()), pos=pos)
buffer.session.settings["other_buffers"]["timelines"].append(dlg.get_user())
pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buffer.session)
buffer.session.sound.play("create_timeline.ogg")
buff.session.settings["other_buffers"]["timelines"].append(dlg.get_user())
pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buff.session)
buff.session.sound.play("create_timeline.ogg")
else:
if usr["favourites_count"] == 0:
commonMessageDialogs.no_favs()
return
if dlg.get_user() in buffer.session.settings["other_buffers"]["favourites_timelines"]:
commonMessageDialogs.timeline_exist()
return
tl = buffersController.baseBufferController(self.view.nb, "get_favorites", "%s-favorite" % (dlg.get_user(),), buffer.session, buffer.session.db["user_name"], bufferType=None, screen_name=dlg.get_user())
pos=self.view.search("favs_timelines", buffer.session.db["user_name"])
tl = buffersController.baseBufferController(self.view.nb, "get_favorites", "%s-favorite" % (dlg.get_user(),), buff.session, buff.session.db["user_name"], bufferType=None, screen_name=dlg.get_user())
pos=self.view.search("favs_timelines", buff.session.db["user_name"])
self.insert_buffer(tl, pos+1)
# self.buffers.insert(pos+1, tl)
self.view.insert_buffer(buffer=tl.buffer, name=_(u"Favourites timeline for {}").format(dlg.get_user()), pos=pos)
tl.start_stream()
tl.timer = RepeatingTimer(300, tl.start_stream)
tl.timer.start()
buffer.session.settings["other_buffers"]["favourites_timelines"].append(dlg.get_user())
buffer.session.sound.play("create_timeline.ogg")
buff.session.settings["other_buffers"]["favourites_timelines"].append(dlg.get_user())
buff.session.sound.play("create_timeline.ogg")
else:
commonMessageDialogs.user_not_exist()
@@ -1202,11 +1222,15 @@ class Controller(object):
log.debug("Starting the streaming endpoint")
session.start_streaming()
def set_positions(self):
for i in session_.sessions:
self.set_buffer_positions(i)
def manage_stream_errors(self, session):
log.error("An error ocurred with the stream for the %s session. It will be destroyed" % (session,))
log.debug(" Restarting %s session streams. It will be destroyed" % (session,))
s = session_.sessions[session]
for i in self.buffers:
if i.invisible == True and i.session.session_id == s.session_id:
if i.invisible == True and i.session.session_id == s.session_id and i.type != "people":
i.start_stream()
s.listen_stream_error()
@@ -1350,5 +1374,9 @@ class Controller(object):
def repeat_item(self, *args, **kwargs):
output.speak(self.get_current_buffer().get_message())
def execute_action(self, action):
if hasattr(self, action):
getattr(self, action)()
def __del__(self):
config.app.write()

View File

@@ -25,6 +25,7 @@ class basicTweet(object):
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach)
# if system == "Windows":
# if messageType != "dm":
widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor)
self.text_processor()
widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten)
@@ -97,6 +98,7 @@ class basicTweet(object):
checker = SpellChecker.spellchecker.spellChecker(text, "")
if hasattr(checker, "fixed_text"):
self.message.set_text(checker.fixed_text)
self.message.text_focus()
def attach(self, *args, **kwargs):
def completed_callback():
@@ -109,6 +111,7 @@ class basicTweet(object):
output.speak(_(u"Unable to upload the audio"))
dlg.cleanup()
dlg = audioUploader.audioUploader(self.session.settings, completed_callback)
self.message.text_focus()
class tweet(basicTweet):
def __init__(self, session, title, caption, text, twishort_enabled, messageType="tweet", max=140):
@@ -130,6 +133,7 @@ class tweet(basicTweet):
self.image = self.message.get_image()
if self.image != None:
self.message.set("upload_image", _(u"Discard image"))
self.message.text_focus()
def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
@@ -151,7 +155,7 @@ class reply(tweet):
class dm(basicTweet):
def __init__(self, session, title, caption, text):
super(dm, self).__init__(session, title, caption, text, messageType="dm")
super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000)
widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
def autocomplete_users(self, *args, **kwargs):

View File

@@ -3,6 +3,7 @@ import widgetUtils
import config
import wx_ui
import constants
from pubsub import pub
class KeystrokeEditor(object):
def __init__(self):
@@ -14,6 +15,7 @@ class KeystrokeEditor(object):
self.hold_map = self.map.copy()
self.dialog.put_keystrokes(constants.actions, self.map)
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_keystroke)
widgetUtils.connect_event(self.dialog.execute, widgetUtils.BUTTON_PRESSED, self.execute_action)
self.dialog.get_response()
def edit_keystroke(self, *args, **kwargs):
@@ -52,3 +54,7 @@ class KeystrokeEditor(object):
wx_ui.no_key()
return
return "+".join(keys)
def execute_action(self, *args, **kwargs):
action = self.dialog.actions[self.dialog.get_action()]
pub.sendMessage("execute-action", action=action)

View File

@@ -13,18 +13,20 @@ class keystrokeEditorDialog(baseDialog.BaseWXDialog):
self.keys = widgets.list(self, _(u"Action"), _(u"Keystroke"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(400, 450))
self.keys.list.SetFocus()
firstSizer = wx.BoxSizer(wx.HORIZONTAL)
firstSizer.Add(keysText)
firstSizer.Add(self.keys.list)
firstSizer.Add(keysText, 0, wx.ALL, 5)
firstSizer.Add(self.keys.list, 0, wx.ALL, 5)
self.edit = wx.Button(panel, -1, _(u"Edit"))
self.edit.SetDefault()
self.execute = wx.Button(panel, -1, _(u"Execute action"))
close = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
secondSizer = wx.BoxSizer(wx.HORIZONTAL)
secondSizer.Add(self.edit)
secondSizer.Add(close)
sizer.Add(firstSizer)
sizer.Add(secondSizer)
panel.SetSizerAndFit(sizer)
secondSizer.Add(self.edit, 0, wx.ALL, 5)
secondSizer.Add(self.execute, 0, wx.ALL, 5)
secondSizer.Add(close, 0, wx.ALL, 5)
sizer.Add(firstSizer, 0, wx.ALL, 5)
sizer.Add(secondSizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def put_keystrokes(self, actions, keystrokes):
for i in keystrokes:

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -119,7 +119,8 @@ class Session(object):
# self.settings = None
def init_sound(self):
self.sound = sound.soundSystem(self.settings["sound"])
try: self.sound = sound.soundSystem(self.settings["sound"])
except: pass
@_require_configuration
def login(self, verify_credentials=True):
@@ -344,6 +345,7 @@ class Session(object):
self.logged = False
self.twitter = twitter.twitter.twitter()
self.login(False)
pub.sendMessage("streamError", session=self.session_id)
if self.reconnection_function_active == True: return
self.reconnection_function_active = True
if not hasattr(self, "main_stream"):

View File

@@ -1,4 +1,7 @@
import wx
import paths
import languageHandler
import sys
toolkit = "wx"
@@ -108,6 +111,15 @@ class mainLoopObject(wx.App):
def __init__(self):
self.app = wx.App()
self.lc = wx.Locale()
lang=languageHandler.getLanguage()
wxLang=self.lc.FindLanguageInfo(lang)
if not wxLang and '_' in lang:
wxLang=self.lc.FindLanguageInfo(lang.split('_')[0])
if hasattr(sys,'frozen'):
self.lc.AddCatalogLookupPathPrefix(paths.app_path("locales"))
if wxLang:
self.lc.Init(wxLang.Language)
def run(self):
self.app.MainLoop()

View File

@@ -52,3 +52,9 @@ def no_following():
def donation():
dlg = wx.MessageDialog(None, _(u"If you like {0} we need your help to keep it going. Help us by donating to the project. This will help us pay for the server, the domain and some other things to ensure that {0} will be actively maintained. Your donation will give us the means to continue the development of {0}, and to keep {0} free. Would you like to donate now?").format(application.name), _(u"We need your help"), wx.ICON_QUESTION|wx.YES_NO)
return dlg.ShowModal()
def no_tweets():
return wx.MessageDialog(None, _(u"This user has no tweets. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal()
def no_favs():
return wx.MessageDialog(None, _(u"This user has no favorited tweets. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal()

View File

@@ -123,6 +123,7 @@ class removeUserListDialog(listViewer):
self.SetTitle(_(u"Select a list to remove the user"))
self.createBtn.SetLabel(_(u"Remove"))
self.createBtn.SetDefault()
self.createBtn.SetId(wx.ID_OK)
self.editBtn.Disable()
self.view.Disable()
# self.subscriptors.Disable()

View File

@@ -216,7 +216,8 @@ class dm(textLimited):
self.buttonsBox3.Add(cancelButton, 0, wx.ALL, 5)
self.mainBox.Add(self.buttonsBox3, 0, wx.ALL, 5)
self.panel.SetSizer(self.mainBox)
# self.SetClientSize(self.mainBox.CalcMin())
def __init__(self, title, message, users):
super(dm, self).__init__()
self.createControls(message, title, users)

95
src/wxUI/menus.py Normal file
View File

@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
import wx
class basePanelMenu(wx.Menu):
def __init__(self):
super(basePanelMenu, self).__init__()
self.retweet = wx.MenuItem(self, wx.NewId(), _(u"&Retweet"))
self.AppendItem(self.retweet)
self.reply = wx.MenuItem(self, wx.NewId(), _(u"Re&ply"))
self.AppendItem(self.reply)
self.fav = wx.MenuItem(self, wx.NewId(), _(u"Add to &favourites"))
self.AppendItem(self.fav)
self.unfav = wx.MenuItem(self, wx.NewId(), _(u"Remove from favo&urites"))
self.AppendItem(self.unfav)
self.openUrl = wx.MenuItem(self, wx.NewId(), _(u"&Open URL"))
self.AppendItem(self.openUrl)
self.play = wx.MenuItem(self, wx.NewId(), _(u"&Play audio"))
self.AppendItem(self.play)
self.view = wx.MenuItem(self, wx.NewId(), _(u"&Show tweet"))
self.AppendItem(self.view)
self.copy = wx.MenuItem(self, wx.NewId(), _(u"&Copy to clipboard"))
self.AppendItem(self.copy)
self.remove = wx.MenuItem(self, wx.NewId(), _(u"&Delete"))
self.AppendItem(self.remove)
self.userActions = wx.MenuItem(self, wx.NewId(), _(u"&User actions..."))
self.AppendItem(self.userActions)
class dmPanelMenu(wx.Menu):
def __init__(self):
super(dmPanelMenu, self).__init__()
self.reply = wx.MenuItem(self, wx.NewId(), _(u"Re&ply"))
self.AppendItem(self.reply)
self.openUrl = wx.MenuItem(self, wx.NewId(), _(u"&Open URL"))
self.AppendItem(self.openUrl)
self.play = wx.MenuItem(self, wx.NewId(), _(u"&Play audio"))
self.AppendItem(self.play)
self.view = wx.MenuItem(self, wx.NewId(), _(u"&Show direct message"))
self.AppendItem(self.view)
self.copy = wx.MenuItem(self, wx.NewId(), _(u"&Copy to clipboard"))
self.AppendItem(self.copy)
self.remove = wx.MenuItem(self, wx.NewId(), _(u"&Delete"))
self.AppendItem(self.remove)
self.userActions = wx.MenuItem(self, wx.NewId(), _(u"&User actions..."))
self.AppendItem(self.userActions)
class sentPanelMenu(wx.Menu):
def __init__(self):
super(sentPanelMenu, self).__init__()
self.openUrl = wx.MenuItem(self, wx.NewId(), _(u"&Open URL"))
self.AppendItem(self.openUrl)
self.play = wx.MenuItem(self, wx.NewId(), _(u"&Play audio"))
self.AppendItem(self.play)
self.view = wx.MenuItem(self, wx.NewId(), _(u"&Show tweet"))
self.AppendItem(self.view)
self.copy = wx.MenuItem(self, wx.NewId(), _(u"&Copy to clipboard"))
self.AppendItem(self.copy)
self.remove = wx.MenuItem(self, wx.NewId(), _(u"&Delete"))
self.AppendItem(self.remove)
class eventsPanelMenu(wx.Menu):
def __init__(self):
super(eventsPanelMenu, self).__init__()
self.view = wx.MenuItem(self, wx.NewId(), _(u"&Show event"))
self.AppendItem(self.view)
self.copy = wx.MenuItem(self, wx.NewId(), _(u"&Copy to clipboard"))
self.AppendItem(self.copy)
self.remove = wx.MenuItem(self, wx.NewId(), _(u"&Delete"))
self.AppendItem(self.remove)
class peoplePanelMenu(wx.Menu):
def __init__(self):
super(peoplePanelMenu, self).__init__()
self.reply = wx.MenuItem(self, wx.NewId(), _(u"Direct &message"))
self.AppendItem(self.reply)
self.lists = wx.MenuItem(self, wx.NewId(), _(u"&View lists"))
self.AppendItem(self.lists)
self.lists.Enable(False)
self.details = wx.MenuItem(self, wx.NewId(), _(u"Show user &profile"))
self.AppendItem(self.details)
self.view = wx.MenuItem(self, wx.NewId(), _(u"&Show user"))
self.AppendItem(self.view)
self.copy = wx.MenuItem(self, wx.NewId(), _(u"&Copy to clipboard"))
self.AppendItem(self.copy)
self.userActions = wx.MenuItem(self, wx.NewId(), _(u"&User actions..."))
self.AppendItem(self.userActions)
class trendsPanelMenu(wx.Menu):
def __init__(self):
super(trendsPanelMenu, self).__init__()
self.tweetThisTrend = wx.MenuItem(self, wx.NewId(), _(u"&Tweet about this trend"))
self.AppendItem(self.tweetThisTrend)
self.view = wx.MenuItem(self, wx.NewId(), _(u"&Show item"))
self.AppendItem(self.view)
self.copy = wx.MenuItem(self, wx.NewId(), _(u"&Copy to clipboard"))
self.AppendItem(self.copy)

View File

@@ -41,7 +41,6 @@ class mainFrame(wx.Frame):
self.dm = user.Append(wx.NewId(), _(u"Direct me&ssage"))
self.addToList = user.Append(wx.NewId(), _(u"&Add to list"))
self.removeFromList = user.Append(wx.NewId(), _(u"R&emove from list"))
self.removeFromList.Enable(False)
self.viewLists = user.Append(wx.NewId(), _(u"&View lists"))
self.viewLists.Enable(False)
self.details = user.Append(wx.NewId(), _(u"Show user &profile"))