From f54d9394b75f4a8d5abb95c79670a16dacb64c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Cort=C3=A9z?= Date: Wed, 12 Nov 2014 20:41:29 -0600 Subject: [PATCH] The next generation branch has been added --- src/Conf.defaults | 51 - src/accessible_output2/outputs/sapi5.py | 2 +- src/app-configuration.defaults | 56 + src/application.py | 4 +- src/audio_services/services.py | 8 - src/config.py | 11 +- src/{gui => controller}/__init__.py | 2 - src/controller/buffersController.py | 279 +++++ src/controller/mainController.py | 349 +++++++ src/controller/messages.py | 9 + src/extra/AudioUploader/gui.py | 1 - .../SpellChecker/{gui.py => spellchecker.py} | 0 src/extra/SpellChecker/wxUI.py | 105 ++ src/extra/translator/__init__.py | 2 - src/extra/translator/{gui.py => wxUI.py} | 11 +- src/gui/buffers/__init__.py | 10 - src/gui/buffers/base.py | 364 ------- src/gui/buffers/dm.py | 48 - src/gui/buffers/events.py | 134 --- src/gui/buffers/favourites.py | 62 -- src/gui/buffers/lists.py | 68 -- src/gui/buffers/people.py | 142 --- src/gui/buffers/trends.py | 51 - src/gui/buffers/tweet_searches.py | 58 -- src/gui/buffers/user_searches.py | 64 -- src/gui/dialogs/__init__.py | 1 - src/gui/dialogs/configuration.py | 424 -------- src/gui/dialogs/follow.py | 151 --- src/gui/dialogs/lists.py | 244 ----- src/gui/dialogs/message.py | 419 -------- src/gui/dialogs/show_user.py | 83 -- src/gui/dialogs/trending.py | 48 - src/gui/dialogs/urlList.py | 71 -- src/gui/dialogs/utils.py | 49 - src/gui/main.py | 965 ------------------ src/issueReporter/__init__.py | 0 src/issueReporter/constants.py | 21 + .../panels.py => issueReporter/get_logs.py} | 31 +- src/issueReporter/gui.py | 124 +++ src/keystrokeEditor/__init__.py | 3 + src/keystrokeEditor/constants.py | 2 +- src/keystrokeEditor/{gui.py => wxUI.py} | 24 +- src/locales/fi/LC_MESSAGES/twblue.mo | Bin 35975 -> 36558 bytes src/locales/fi/LC_MESSAGES/twblue.po | 25 +- src/locales/fr/LC_MESSAGES/twblue.mo | Bin 36978 -> 37514 bytes src/locales/fr/LC_MESSAGES/twblue.po | 24 +- src/locales/it/LC_MESSAGES/twblue.mo | Bin 35418 -> 35982 bytes src/locales/it/LC_MESSAGES/twblue.po | 44 +- src/main.py | 98 +- src/mysc/event.py | 41 - src/mysc/paths.py | 38 - src/mysc/repeating_timer.py | 8 +- src/sessionmanager/__init__.py | 10 +- src/sessionmanager/gui.py | 101 -- src/sessionmanager/manager.py | 29 +- src/sessionmanager/session.py | 269 +++++ src/sessionmanager/sessionManager.py | 52 + src/sessionmanager/session_exceptions.py | 4 + src/sessionmanager/wxUI.py | 60 ++ src/sessions.defaults | 3 - src/sound.py | 92 +- src/twitter/__init__.py | 2 +- src/twitter/authorisationHandler.py | 20 + src/twitter/buffers/indibidual.py | 47 +- src/twitter/buffers/stream.py | 197 ++-- src/twitter/compose.py | 25 +- src/twitter/starting.py | 259 ----- src/twitter/twitter.py | 80 +- src/twitter/utils.py | 12 - src/twython/streaming/api.py | 1 - src/widgetUtils/__init__.py | 3 + src/widgetUtils/wxUtils.py | 17 + src/wxUI/__init__.py | 1 + src/wxUI/buffers/__init__.py | 10 + src/wxUI/buffers/base.py | 32 + src/wxUI/buffers/dm.py | 11 + src/wxUI/buffers/events.py | 15 + src/wxUI/buffers/favourites.py | 8 + src/wxUI/buffers/lists.py | 9 + src/wxUI/buffers/panels.py | 18 + src/wxUI/buffers/people.py | 16 + src/wxUI/buffers/tweet_searches.py | 8 + src/wxUI/buffers/user_searches.py | 14 + src/wxUI/dialogs/__init__.py | 1 + src/wxUI/dialogs/baseDialog.py | 16 + src/wxUI/dialogs/configuration.py | 182 ++++ src/wxUI/dialogs/follow.py | 66 ++ src/wxUI/dialogs/lists.py | 123 +++ src/wxUI/dialogs/message.py | 163 +++ src/{gui => wxUI}/dialogs/search.py | 22 +- src/wxUI/dialogs/show_user.py | 28 + src/{gui => wxUI}/dialogs/update_profile.py | 52 +- src/wxUI/dialogs/urlList.py | 35 + src/wxUI/dialogs/utils.py | 29 + src/{gui => wxUI}/sysTrayIcon.py | 0 src/wxUI/view.py | 175 ++++ 96 files changed, 2629 insertions(+), 4517 deletions(-) create mode 100644 src/app-configuration.defaults rename src/{gui => controller}/__init__.py (52%) create mode 100644 src/controller/buffersController.py create mode 100644 src/controller/mainController.py create mode 100644 src/controller/messages.py rename src/extra/SpellChecker/{gui.py => spellchecker.py} (100%) create mode 100644 src/extra/SpellChecker/wxUI.py rename src/extra/translator/{gui.py => wxUI.py} (89%) delete mode 100644 src/gui/buffers/__init__.py delete mode 100644 src/gui/buffers/base.py delete mode 100644 src/gui/buffers/dm.py delete mode 100644 src/gui/buffers/events.py delete mode 100644 src/gui/buffers/favourites.py delete mode 100644 src/gui/buffers/lists.py delete mode 100644 src/gui/buffers/people.py delete mode 100644 src/gui/buffers/trends.py delete mode 100644 src/gui/buffers/tweet_searches.py delete mode 100644 src/gui/buffers/user_searches.py delete mode 100644 src/gui/dialogs/__init__.py delete mode 100644 src/gui/dialogs/configuration.py delete mode 100644 src/gui/dialogs/follow.py delete mode 100644 src/gui/dialogs/lists.py delete mode 100644 src/gui/dialogs/message.py delete mode 100644 src/gui/dialogs/show_user.py delete mode 100644 src/gui/dialogs/trending.py delete mode 100644 src/gui/dialogs/urlList.py delete mode 100644 src/gui/dialogs/utils.py delete mode 100644 src/gui/main.py create mode 100644 src/issueReporter/__init__.py create mode 100644 src/issueReporter/constants.py rename src/{gui/buffers/panels.py => issueReporter/get_logs.py} (56%) create mode 100644 src/issueReporter/gui.py rename src/keystrokeEditor/{gui.py => wxUI.py} (83%) delete mode 100644 src/mysc/event.py delete mode 100644 src/mysc/paths.py delete mode 100644 src/sessionmanager/gui.py create mode 100644 src/sessionmanager/session.py create mode 100644 src/sessionmanager/sessionManager.py create mode 100644 src/sessionmanager/wxUI.py delete mode 100644 src/sessions.defaults create mode 100644 src/twitter/authorisationHandler.py delete mode 100644 src/twitter/starting.py create mode 100644 src/widgetUtils/__init__.py create mode 100644 src/widgetUtils/wxUtils.py create mode 100644 src/wxUI/__init__.py create mode 100644 src/wxUI/buffers/__init__.py create mode 100644 src/wxUI/buffers/base.py create mode 100644 src/wxUI/buffers/dm.py create mode 100644 src/wxUI/buffers/events.py create mode 100644 src/wxUI/buffers/favourites.py create mode 100644 src/wxUI/buffers/lists.py create mode 100644 src/wxUI/buffers/panels.py create mode 100644 src/wxUI/buffers/people.py create mode 100644 src/wxUI/buffers/tweet_searches.py create mode 100644 src/wxUI/buffers/user_searches.py create mode 100644 src/wxUI/dialogs/__init__.py create mode 100644 src/wxUI/dialogs/baseDialog.py create mode 100644 src/wxUI/dialogs/configuration.py create mode 100644 src/wxUI/dialogs/follow.py create mode 100644 src/wxUI/dialogs/lists.py create mode 100644 src/wxUI/dialogs/message.py rename src/{gui => wxUI}/dialogs/search.py (52%) create mode 100644 src/wxUI/dialogs/show_user.py rename src/{gui => wxUI}/dialogs/update_profile.py (58%) create mode 100644 src/wxUI/dialogs/urlList.py create mode 100644 src/wxUI/dialogs/utils.py rename src/{gui => wxUI}/sysTrayIcon.py (100%) create mode 100644 src/wxUI/view.py diff --git a/src/Conf.defaults b/src/Conf.defaults index 75fb4238..a28d76e1 100644 --- a/src/Conf.defaults +++ b/src/Conf.defaults @@ -5,23 +5,14 @@ user_name = string(default="") ignored_clients = list(default=list()) [general] -language = string(default="system") relative_times = boolean(default=True) -hide_gui = boolean(default=False) -voice_enabled = boolean(default=False) max_api_calls = integer(default=1) max_tweets_per_call = integer(default=100) reverse_timelines = boolean(default=False) time_to_check_streams = integer(default=30) announce_stream_status = boolean(default=True) -ask_at_exit = boolean(default=True) [sound] -volume = float(default=1.0) -input_device = string(default="Default") -output_device = string(default="Default") -current_soundpack = string(default="default") -global_mute = boolean(default=False) sndup_api_key = string(default="") [other_buffers] @@ -44,45 +35,3 @@ spelling_language = string(default="") [services] dropbox_token=string(default="") -[keymap] -up = string(default="control+win+up") -down = string(default="control+win+down") -left = string(default="control+win+left") -right = string(default="control+win+right") -conversation_up = string(default="control+win+shift+up") -conversation_down = string(default="control+win+shift+down") -show_hide = string(default="control+win+m") -compose = string(default="control+win+n") -reply = string(default="control+win+r") -retweet = string(default="control+win+shift+r") -dm = string(default="control+win+d") -fav = string(default="alt+win+f") -unfav = string(default="alt+shift+win+f") -action = string(default="control+win+s") -details = string(default="control+win+alt+n") -view = string(default="control+win+v") -close = string(default="control+win+f4") -open_timeline = string(default="control+win+i") -delete_buffer = string(default="control+win+shift+i") -url = string(default="control+win+return") -audio = string(default="control+win+alt+return") -volume_up = string(default="control+win+alt+up") -volume_down = string(default="control+win+alt+down") -go_home = string(default="control+win+home") -go_end = string(default="control+win+end") -go_page_up = string(default="control+win+pageup") -go_page_down = string(default="control+win+pagedown") -update_profile = string(default="alt+win+p") -delete = string(default="control+win+delete") -clear_list = string(default="control+win+shift+delete") -repeat_item = string(default="control+win+space") -copy_to_clipboard = string(default="control+win+c") -add_to_list = string(default="control+win+a") -remove_from_list = string(default="control+win+shift+a") -toggle_mute = string(default="control+win+shift+m") -toggle_global_mute = string(default="alt+win+m") -toggle_autoread = string(default="control+win+e") -search = string(default="control+win+-") -edit_keystrokes = string(default="control+win+k") -view_user_lists = string(default="control+win+l") -get_more_items = string(default="alt+win+pageup") diff --git a/src/accessible_output2/outputs/sapi5.py b/src/accessible_output2/outputs/sapi5.py index 9e8a2fa6..0d24fdf9 100644 --- a/src/accessible_output2/outputs/sapi5.py +++ b/src/accessible_output2/outputs/sapi5.py @@ -21,7 +21,7 @@ class SAPI5(Output): priority = 101 def __init__(self): - if config.main["general"]["voice_enabled"] == False: raise OutputError + if config.app["app-settings"]["voice_enabled"] == False: raise OutputError try: self.object = load_com("SAPI.SPVoice") self._voices = self._available_voices() diff --git a/src/app-configuration.defaults b/src/app-configuration.defaults new file mode 100644 index 00000000..bc0f1f43 --- /dev/null +++ b/src/app-configuration.defaults @@ -0,0 +1,56 @@ +[sessions] +current_session = string(default="") +sessions = list(default=list()) + +[app-settings] +language = string(default="system") +hide_gui = boolean(default=False) +voice_enabled = boolean(default=False) +volume = float(default=1.0) +input_device = string(default="Default") +output_device = string(default="Default") +global_mute = boolean(default=False) +current_soundpack = string(default="default") + +[keymap] +up = string(default="control+win+up") +down = string(default="control+win+down") +left = string(default="control+win+left") +right = string(default="control+win+right") +conversation_up = string(default="control+win+shift+up") +conversation_down = string(default="control+win+shift+down") +show_hide = string(default="control+win+m") +compose = string(default="control+win+n") +reply = string(default="control+win+r") +retweet = string(default="control+win+shift+r") +dm = string(default="control+win+d") +fav = string(default="alt+win+f") +unfav = string(default="alt+shift+win+f") +action = string(default="control+win+s") +details = string(default="control+win+alt+n") +view = string(default="control+win+v") +close = string(default="control+win+f4") +open_timeline = string(default="control+win+i") +delete_buffer = string(default="control+win+shift+i") +url = string(default="control+win+return") +audio = string(default="control+win+alt+return") +volume_up = string(default="control+win+alt+up") +volume_down = string(default="control+win+alt+down") +go_home = string(default="control+win+home") +go_end = string(default="control+win+end") +go_page_up = string(default="control+win+pageup") +go_page_down = string(default="control+win+pagedown") +update_profile = string(default="alt+win+p") +delete = string(default="control+win+delete") +clear_list = string(default="control+win+shift+delete") +repeat_item = string(default="control+win+space") +copy_to_clipboard = string(default="control+win+c") +add_to_list = string(default="control+win+a") +remove_from_list = string(default="control+win+shift+a") +toggle_mute = string(default="control+win+shift+m") +toggle_global_mute = string(default="alt+win+m") +toggle_autoread = string(default="control+win+e") +search = string(default="control+win+-") +edit_keystrokes = string(default="control+win+k") +view_user_lists = string(default="control+win+l") +get_more_items = string(default="alt+win+pageup") \ No newline at end of file diff --git a/src/application.py b/src/application.py index 400182d3..7dbcf3ca 100644 --- a/src/application.py +++ b/src/application.py @@ -2,7 +2,7 @@ name = 'TW Blue' snapshot = False if snapshot == False: - version = "0.48" + version = "0.47" update_url = 'http://twblue.com.mx/updates/tw_blue.json' else: version = "4" @@ -13,7 +13,7 @@ copyright = u"copyright (C) 2013-2014, Manuel cortéz" description = u"TW Blue is an app designed to use Twitter in a simple and fast way and avoiding, as far as possible, the consumtion of excessive resources of the machine where it’s running. With this app you’ll have access to most twitter features." translators = [u"Bryner Villalobos (English)", u"Mohammed Al Shara (Arabic)", u"Salva Doménech, Juan Carlos Rivilla(Catalan)", u"Manuel cortéz(Spanish)", u"Sukil Etxenike Arizaleta(Basque)", u"Jani Kinnunen(finnish)", u"Javier Currás, José Manuel Delicado, Alba Quinteiro(Galician)", u"Robert Osztolykan(Hungarian)", u"Paweł Masarczyk(Polish)", u"Odenilton Júnior Santos(Portuguese)", u"Alexander Jaszyn(Russian)", u"Burak (Turkish)"] url = u"http://twblue.com.mx" -#report_bugs_url = "http://twblue.com.mx/errores/api/soap/mantisconnect.php?wsdl" +report_bugs_url = "http://twblue.com.mx/errores/api/soap/mantisconnect.php?wsdl" # Tokens app_key = '8pDLbyOW3saYnvSZ4uLFg' diff --git a/src/audio_services/services.py b/src/audio_services/services.py index 6cb7ced9..9afa47a5 100644 --- a/src/audio_services/services.py +++ b/src/audio_services/services.py @@ -10,14 +10,6 @@ def convert_audioboom(url): audio_id = url.split('.com/')[-1] return 'https://audioboom.com/%s.mp3' % audio_id -@matches_url('http://q-audio.net') -def convert_q_audio(url): - result = re.match("^https?://q-audio.net/(i|d|download)/(?P[a-z0-9]+/?)$", url, re.I) - if not result or result.group("audio_id") is None: - raise TypeError('%r is not a valid URL' % url) - audio_id = result.group("audio_id") - return 'http://q-audio.net/download/%s' % audio_id - @matches_url ('http://soundcloud.com/') def convert_soundcloud (url): client_id = "df8113ca95c157b6c9731f54b105b473" diff --git a/src/config.py b/src/config.py index c4f482c0..420f8433 100644 --- a/src/config.py +++ b/src/config.py @@ -2,15 +2,14 @@ from config_utils import Configuration, ConfigurationResetException import paths -MAINFILE = "session.conf" -MAINSPEC = "Conf.defaults" +MAINFILE = "twblue.conf" +MAINSPEC = "app-configuration.defaults" -main = None +app = None def setup (): - global main + global app try: - main = Configuration(paths.config_path(MAINFILE), paths.app_path(MAINSPEC)) + app = Configuration(paths.config_path(MAINFILE), paths.app_path(MAINSPEC)) except ConfigurationResetException: pass -# return main \ No newline at end of file diff --git a/src/gui/__init__.py b/src/controller/__init__.py similarity index 52% rename from src/gui/__init__.py rename to src/controller/__init__.py index c4cbd802..40a96afc 100644 --- a/src/gui/__init__.py +++ b/src/controller/__init__.py @@ -1,3 +1 @@ # -*- coding: utf-8 -*- -import main, dialogs - diff --git a/src/controller/buffersController.py b/src/controller/buffersController.py new file mode 100644 index 00000000..9bde81e6 --- /dev/null +++ b/src/controller/buffersController.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- +import wx +import widgetUtils +import datetime +import webbrowser +import output +import config +import sound +from twitter import compose, prettydate, utils +from wxUI import buffers, dialogs + +class bufferController(object): + def __init__(self, parent=None, function=None, session=None, *args, **kwargs): + super(bufferController, self).__init__() + self.function = function + self.compose_function = None + self.args = args + self.kwargs = kwargs + self.buffer = None + self.account = "" + + def get_event(self, ev): + if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio" + elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url" + elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down" + elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" + elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" + elif ev.GetKeyCode() == wx.WXK_DELETE: event = "delete_item" + else: + event = None + ev.Skip() + if event != None: +# try: + getattr(self, event)() +# except AttributeError: + #pass + + def volume_down(self): + if config.app["app-settings"]["volume"] > 0.0: + if config.app["app-settings"]["volume"] <= 0.05: + config.app["app-settings"]["volume"] = 0.0 + else: + config.app["app-settings"]["volume"] -=0.05 + if hasattr(sound.URLStream, "stream"): + sound.URLStream.stream.volume = config.app["app-settings"]["volume"] + sound.player.play("volume_changed.ogg") + + def volume_up(self): + if config.app["app-settings"]["volume"] < 1.0: + if config.app["app-settings"]["volume"] >= 0.95: + config.app["app-settings"]["volume"] = 1.0 + else: + config.app["app-settings"]["volume"] +=0.05 + if hasattr(sound.URLStream, "stream"): + sound.URLStream.stream.volume = config.app["app-settings"]["volume"] + sound.player.play("volume_changed.ogg") + + def start_stream(self): + pass + + def put_items_on_list(self, items): + pass + + def remove_buffer(self): + pass + + def remove_item(self, item): + self.buffer.list.remove_item(item) + + def bind_events(self): + pass + + def get_object(self): + return self.buffer + + def set_list_position(self, reversed=False): + if reversed == False: + self.buffer.list.select_item(-1) + else: + self.buffer.list.select_item(0) + +class accountPanel(bufferController): + def __init__(self, parent, name, account): + super(accountPanel, self).__init__(parent, None, name) + self.buffer = buffers.accountPanel(parent, name) + self.type = self.buffer.type + self.compose_function = None + self.id = self.buffer.GetId() + self.account = account + self.buffer.account = account + self.name = name + +class emptyPanel(bufferController): + def __init__(self, parent, name, account): + super(emptyPanel, self).__init__(parent, None, name) + self.buffer = buffers.emptyPanel(parent, name) + self.type = self.buffer.type + self.compose_function = None + self.id = self.buffer.GetId() + self.account = account + self.buffer.account = account + self.name = name + +class baseBufferController(bufferController): + def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs): + super(baseBufferController, self).__init__(parent, function, *args, **kwargs) + if bufferType != None: + self.buffer = getattr(buffers, bufferType)(parent, name) + else: + self.buffer = buffers.basePanel(parent, name) + self.name = name + self.type = self.buffer.type + self.id = self.buffer.GetId() + self.session = sessionObject + self.compose_function = compose.compose_tweet + self.account = account + self.buffer.account = account + self.bind_events() + + def start_stream(self): + val = self.session.call_paged(self.function, *self.args, **self.kwargs) + number_of_items = self.session.order_buffer(self.name, val) + self.put_items_on_list(number_of_items) + + def put_items_on_list(self, number_of_items): + if self.buffer.list.get_count() == 0: + for i in self.session.db[self.name]: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"]) + self.buffer.list.insert_item(False, *tweet) +# self.buffer.set_list_position() + elif self.buffer.list.get_count() > 0: + if self.session.settings["general"]["reverse_timelines"] == False: + for i in self.session.db[self.name][:number_of_items]: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"]) + self.buffer.list.insert_item(False, *tweet) + else: + for i in self.session.db[self.name][0:number_of_items]: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"]) + self.buffer.list.insert_item(True, *tweet) + + def add_new_item(self, item): + tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"]) + if self.session.settings["general"]["reverse_timelines"] == False: + self.buffer.list.insert_item(False, *tweet) + else: + self.buffer.list.insert_item(True, *tweet) + + def bind_events(self): + self.buffer.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocus) + self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) + + def get_tweet(self): + if self.session.db[self.name][self.buffer.list.get_selected()].has_key("retweeted_status"): + tweet = self.session.db[self.name][self.buffer.list.get_selected()]["retweeted_status"] + else: + tweet = self.session.db[self.name][self.buffer.list.get_selected()] + return tweet + + def onFocus(self, ev): + tweet = self.get_tweet() + if self.session.settings["general"]["relative_times"] == True: + original_date = datetime.datetime.strptime(self.session.db[self.name][self.buffer.list.get_selected()]["created_at"], "%a %b %d %H:%M:%S +0000 %Y") + ts = prettydate(original_date) + self.buffer.list.list.SetStringItem(self.buffer.list.get_selected(), 2, ts) + if utils.is_audio(tweet): + sound.player.play("audio.ogg") + + def audio(self): + tweet = self.get_tweet() + urls = utils.find_urls(tweet) + if len(urls) == 1: + sound.URLPlayer.play(urls[0]) + else: + urls_list = dialogs.urlList.urlList() + urls_list.populate_list(urls) + if urls_list.get_response() == widgetUtils.OK: + sound.URLPlayer.play(urls_list.get_string()) + + def url(self): + tweet = self.get_tweet() + urls = utils.find_urls(tweet) + if len(urls) == 1: + output.speak(_(u"Opening URL...")) + webbrowser.open_new_tab(urls[0]) + elif len(urls) > 1: + urls_list = dialogs.urlList.urlList() + urls_list.populate_list(urls) + if urls_list.get_response() == widgetUtils.OK: + output.speak(_(u"Opening URL...")) + webbrowser.open_new_tab(urls_list.get_string()) + + def clear_list(self): + dlg = wx.MessageDialog(None, _(u"Do you really want to empty this buffer? It's tweets will be removed from the list but not from Twitter"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO) + if dlg.ShowModal() == widgetUtils.YES: + self.session.db[self.name] = [] + self.buffer.list.clear() + dlg.Destroy() + + def delete_item(self): + dlg = wx.MessageDialog(None, _(u"Do you really want to delete this message?"), _(u"Delete"), wx.ICON_QUESTION|wx.YES_NO) + if dlg.ShowModal() == widgetUtils.YES: + index = self.buffer.list.get_selected() + try: + self.session.twitter.twitter.destroy_status(id=self.session.db[self.name][index]["id"]) + self.session.db[self.name].pop(index) + self.buffer.list.remove_item(index) + if index > 0: + self.buffer.list.select_item(index-1) + except: + sound.player.play("error.ogg") + +class eventsBufferController(bufferController): + def __init__(self, parent, name, session, account, *args, **kwargs): + super(eventsBufferController, self).__init__(parent, *args, **kwargs) + self.buffer = buffers.eventsPanel(parent, name) + self.name = name + self.account = account + self.id = self.buffer.GetId() + self.compose_function = compose.compose_event + self.session = session + + def add_new_item(self, item): + tweet = self.compose_function(item, self.session.db["user_name"]) + if self.session.settings["general"]["reverse_timelines"] == False: + self.buffer.list.insert_item(False, *tweet) + else: + self.buffer.list.insert_item(True, *tweet) + +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") + self.compose_function = compose.compose_followers_list + + def onFocus(self, ev): + pass + + def delete_item(self): pass + + def start_stream(self): + val = self.session.get_cursored_stream(self.name, self.function, *self.args, **self.kwargs) +# self.session.order_cursored_buffer(self.name, self.session.db[self.name]) + self.put_items_on_list(val) + + def put_items_on_list(self, number_of_items): + if self.buffer.list.get_count() == 0: + for i in self.session.db[self.name]["items"]: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"]) + self.buffer.list.insert_item(False, *tweet) +# self.buffer.set_list_position() + elif self.buffer.list.get_count() > 0: + if self.session.settings["general"]["reverse_timelines"] == False: + for i in self.session.db[self.name]["items"][:number_of_items]: + tweet = self.compose_function(i, self.session.db) + self.buffers.list.insert_item(False, *tweet) + else: + for i in self.session.db[self.name]["items"][0:number_of_items]: + tweet = self.compose_function(i, self.session.db) + self.buffer.list.insert_item(True, *tweet) + +class searchBufferController(baseBufferController): + def start_stream(self): + val = getattr(self.session.twitter.twitter, self.function)(*self.args, **self.kwargs) + number_of_items = self.session.order_buffer(self.name, val["statuses"]) + self.put_items_on_list(number_of_items) + if number_of_items > 0: + sound.player.play("search_updated.ogg") + +class searchPeopleBufferController(searchBufferController): + + def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs): + super(searchPeopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) + self.compose_function = compose.compose_followers_list + + def start_stream(self): + val = getattr(self.session.twitter.twitter, self.function)(*self.args, **self.kwargs) + number_of_items = self.session.order_buffer(self.name, val) + self.put_items_on_list(number_of_items) + if number_of_items > 0: + sound.player.play("search_updated.ogg") diff --git a/src/controller/mainController.py b/src/controller/mainController.py new file mode 100644 index 00000000..12bda429 --- /dev/null +++ b/src/controller/mainController.py @@ -0,0 +1,349 @@ +# -*- coding: utf-8 -*- +from wxUI import (view, dialogs) +import buffersController +from sessionmanager import session +from pubsub import pub +import sound +import output +from mysc.thread_utils import call_threaded +from mysc.repeating_timer import RepeatingTimer +import config +import widgetUtils +import platform +if platform.system() == "Windows": + import keystrokeEditor + +class Controller(object): + + """ Main Controller for TWBlue. It manages the main window and sessions.""" + + def search_buffer(self, name_, user): + + """ Searches a buffer. + name_ str: The name for the buffer + user str: The account for the buffer. + for example you may want to search the home_timeline buffer for the tw_blue2 user. + returns buffersController.buffer object with the result if there is one.""" + for i in self.buffers: + if i.name == name_ and i.account == user: return i + + def get_best_buffer(self): + # Gets the parent buffer to know what account is doing an action + view_buffer = self.view.get_current_buffer() + # If the account has no session attached, we will need to search the home_timeline for that account to use its session. + if view_buffer.type == "account" or view_buffer.type == "empty": + buffer = self.search_buffer("home_timeline", view_buffer.account) + else: + buffer = self.search_buffer(view_buffer.name, view_buffer.account) + return buffer + + def bind_stream_events(self): + pub.subscribe(self.manage_home_timelines, "item-in-home") + pub.subscribe(self.manage_mentions, "mention") + pub.subscribe(self.manage_direct_messages, "direct-message") + pub.subscribe(self.manage_sent_dm, "sent-dm") + pub.subscribe(self.manage_sent_tweets, "sent-tweet") + pub.subscribe(self.manage_events, "event") + pub.subscribe(self.manage_followers, "follower") + pub.subscribe(self.manage_friend, "friend") + pub.subscribe(self.manage_unfollowing, "unfollowing") + pub.subscribe(self.manage_favourite, "favourite") + pub.subscribe(self.manage_unfavourite, "unfavourite") + pub.subscribe(self.manage_blocked_user, "blocked-user") + pub.subscribe(self.manage_unblocked_user, "unblocked-user") + pub.subscribe(self.manage_item_in_timeline, "item-in-timeline") + widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit) + + def bind_other_events(self): + pub.subscribe(self.editing_keystroke, "editing_keystroke") + + def __init__(self): + super(Controller, self).__init__() + self.view = view.mainFrame(self) + self.buffers = [] + self.view.prepare() + self.bind_stream_events() + self.bind_other_events() + self.do_work() + + def do_work(self): + for i in session.sessions: + self.create_buffers(session.sessions[i]) + sound.player.play("tweet_timeline.ogg") + + def create_buffers(self, session): + session.get_user_info() + account = buffersController.accountPanel(self.view.nb, session.db["user_name"], session.db["user_name"]) + self.buffers.append(account) + self.view.add_buffer(account.buffer , name=session.db["user_name"]) + home = buffersController.baseBufferController(self.view.nb, "get_home_timeline", "home_timeline", session, session.db["user_name"]) + self.buffers.append(home) + home.start_stream() + self.view.insert_buffer(home.buffer, name=_(u"Home"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + mentions = buffersController.baseBufferController(self.view.nb, "get_mentions_timeline", "mentions", session, session.db["user_name"]) + self.buffers.append(mentions) + mentions.start_stream() + self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + sound.player.play("mention_received.ogg") + dm = buffersController.baseBufferController(self.view.nb, "get_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel") + self.buffers.append(dm) + dm.start_stream() + self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + sound.player.play("dm_received.ogg") + sent_dm = buffersController.baseBufferController(self.view.nb, "get_sent_messages", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel") + self.buffers.append(sent_dm) + sent_dm.start_stream() + self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + sent_tweets = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "sent_tweets", session, session.db["user_name"], bufferType="dmPanel", screen_name=session.db["user_name"]) + self.buffers.append(sent_tweets) + sent_tweets.start_stream() + self.view.insert_buffer(sent_tweets.buffer, name=_(u"Sent tweets"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + if session.settings["other_buffers"]["show_favourites"] == True: + favourites = buffersController.baseBufferController(self.view.nb, "get_favorites", "favourites", session, session.db["user_name"]) + self.buffers.append(favourites) + favourites.start_stream() + self.view.insert_buffer(favourites.buffer, name=_(u"Favourites"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + if session.settings["other_buffers"]["show_followers"] == True: + followers = buffersController.peopleBufferController(self.view.nb, "get_followers_list", "followers", session, session.db["user_name"], screen_name=session.db["user_name"]) + self.buffers.append(followers) + followers.start_stream() + self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + if session.settings["other_buffers"]["show_friends"] == True: + friends = buffersController.peopleBufferController(self.view.nb, "get_friends_list", "friends", session, session.db["user_name"], screen_name=session.db["user_name"]) + self.buffers.append(friends) + friends.start_stream() + self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + if session.settings["other_buffers"]["show_blocks"] == True: + blocks = buffersController.peopleBufferController(self.view.nb, "list_blocks", "blocked", session, session.db["user_name"]) + self.buffers.append(blocks) + blocks.start_stream() + self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + if session.settings["other_buffers"]["show_muted_users"] == True: + muted = buffersController.peopleBufferController(self.view.nb, "get_muted_users_list", "muted", session, session.db["user_name"]) + self.buffers.append(muted) + muted.start_stream() + self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + if session.settings["other_buffers"]["show_events"] == True: + events = buffersController.eventsBufferController(self.view.nb, "events", session, session.db["user_name"], bufferType="dmPanel", screen_name=session.db["user_name"]) + self.buffers.append(events) + self.view.insert_buffer(events.buffer, name=_(u"Events"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + timelines = buffersController.emptyPanel(self.view.nb, "timelines", session.db["user_name"]) + self.buffers.append(timelines) + self.view.insert_buffer(timelines.buffer , name=_(u"Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["timelines"]: + tl = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], bufferType=None, screen_name=i) + self.buffers.append(tl) + tl.start_stream() + self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}".format(i)), pos=self.view.search("timelines", session.db["user_name"])) + searches = buffersController.emptyPanel(self.view.nb, "searches", session.db["user_name"]) + self.buffers.append(searches) + self.view.insert_buffer(searches.buffer , name=_(u"Searches"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["tweet_searches"]: + tl = buffersController.searchBufferController(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", q=i) + self.buffers.append(tl) + tl.start_stream() + self.view.insert_buffer(tl.buffer, name=_(u"Search for {}".format(i)), pos=self.view.search("searches", session.db["user_name"])) + tl.timer = RepeatingTimer(180, tl.start_stream) + tl.timer.start() + session.start_streaming() + + def search(self, event=None): + dlg = dialogs.search.searchDialog() + if dlg.get_response() == widgetUtils.OK: + term = dlg.get("term") + buffer = self.get_best_buffer() + if dlg.get("tweets") == True: + if term not in buffer.session.settings["other_buffers"]["tweet_searches"]: + buffer.session.settings["other_buffers"]["tweet_searches"].append(term) + search = buffersController.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", q=term) + else: + return + elif dlg.get("users") == True: + search = buffersController.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, q=term) + self.buffers.append(search) + search.start_stream() + self.view.insert_buffer(search.buffer, name=_(u"Search for {}".format(term)), pos=self.view.search("searches", buffer.session.db["user_name"])) + search.timer = RepeatingTimer(180, search.start_stream) + search.timer.start() + dlg.Destroy() + + def edit_keystrokes(self, event=None): + dlg = keystrokeEditor.keystrokeEditor() + dlg.put_keystrokes(**config.app["keymap"]) + dlg.ShowModal() + dlg.Destroy() + + def view_user_lists(self, users): + pass + + def add_to_list(self, user): + pass + + def remove_from_list(self, user): + pass + + def lists_manager(self): + pass + + def configuration(self): + pass + + def update_profile(self): + pass + + def show_document(self, document): + pass + + def report_error(self): + pass + + def check_for_updates(self, show_msg=True): + pass + + def show_details_for_user(self, user): + pass + + def delete(self): + pass + + def exit(self, event=None): + for item in session.sessions: + session.sessions[item].settings.write() + session.sessions[item].main_stream.disconnect() + session.sessions[item].timelinesStream.disconnect() + sound.player.cleaner.cancel() + widgetUtils.exit_application() + + def action(self, do_action): + pass + + def post_tweet(self): + pass + + def post_reply(self): + pass + + def send_dm(self, user): + pass + + def post_retweet(self): + pass + + def viewTweet(self): + pass + + def add_to_favourites(self): + pass + + def remove_from_favourites(self): + pass + + def open_timeline(self, user, timeline_tipe): + pass + + def remove_buffer(self): + pass + + def show_hide(self): + pass + + def toggle_global_mute(self): + pass + + def toggle_mute(self): + pass + + def toggle_autoread(self): + pass + + def go_conversation(self, orientation): + pass + + def notify(self, play_sound=None, message=None, notification=False): + if play_sound != None: + sound.player.play(play_sound) + if message != None: + output.speak(message) + + def manage_home_timelines(self, data, user): + buffer = self.search_buffer("home_timeline", user) + play_sound = "tweet_received.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def manage_mentions(self, data, user): + buffer = self.search_buffer("mentions", user) + play_sound = "mention_received.ogg" + buffer.add_new_item(data) + message = _(u"New mention") + self.notify(play_sound=play_sound, message=message) + + def manage_direct_messages(self, data, user): + buffer = self.search_buffer("direct_messages", user) + play_sound = "dm_received.ogg" + buffer.add_new_item(data) + message = _(u"New direct message") + self.notify(play_sound=play_sound, message=message) + + def manage_sent_dm(self, data, user): + buffer = self.search_buffer("sent_direct_messages", user) + play_sound = "dm_sent.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def manage_sent_tweets(self, data, user): + buffer = self.search_buffer("sent_tweets", user) + play_sound = "tweet_send.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def manage_events(self, data, user): + buffer = self.search_buffer("events", user) + play_sound = "new_event.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def manage_followers(self, data, user): + buffer = self.search_buffer("followers", user) + play_sound = "update_followers.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def manage_friend(self, data, user): + buffer = self.search_buffer("friends", user) + buffer.add_new_item(data) + + def manage_unfollowing(self, item, user): + buffer = self.search_buffer("friends", user) + play_sound = "new_event.ogg" + buffer.remove_item(item) + + def manage_favourite(self, data, user): + buffer = self.search_buffer("favourites", user) + play_sound = "favourite.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def manage_unfavourite(self, item, user): + buffer = self.search_buffer("favourites", user) + buffer.remove_item(item) + + def manage_blocked_user(self, data, user): + buffer = self.search_buffer("blocked", user) + buffer.add_new_item(data) + + def manage_unblocked_user(self, item, user): + buffer = self.search_buffer("blocked", user) + buffer.remove_item(item) + + def manage_item_in_timeline(self, data, user, who): + buffer = self.search_buffer("%i-timeline" % (who,), user) + play_sound = "tweet_timeline.ogg" + buffer.add_new_item(data) + self.notify(play_sound=play_sound) + + def editing_keystroke(self, action, parentDialog): + print "i've pressed" + + def __del__(self): + config.app.write() \ No newline at end of file diff --git a/src/controller/messages.py b/src/controller/messages.py new file mode 100644 index 00000000..88aaeeea --- /dev/null +++ b/src/controller/messages.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +import widgetUtils +from wxUI.dialogs import message + +class tweet(object): + def __init__(self, session): + super(tweet, self).__init__() + self.message = message.tweet(_(u"Write the tweet here"), _(u"tweet - 0 characters"), "") + \ No newline at end of file diff --git a/src/extra/AudioUploader/gui.py b/src/extra/AudioUploader/gui.py index eaacd59f..0388fa65 100644 --- a/src/extra/AudioUploader/gui.py +++ b/src/extra/AudioUploader/gui.py @@ -68,7 +68,6 @@ class audioDialog(wx.Dialog): services = [] if config.main["services"]["dropbox_token"] != "": services.append("Dropbox") - services.append("TwUp") services.append("SNDUp") return services diff --git a/src/extra/SpellChecker/gui.py b/src/extra/SpellChecker/spellchecker.py similarity index 100% rename from src/extra/SpellChecker/gui.py rename to src/extra/SpellChecker/spellchecker.py diff --git a/src/extra/SpellChecker/wxUI.py b/src/extra/SpellChecker/wxUI.py new file mode 100644 index 00000000..801559d5 --- /dev/null +++ b/src/extra/SpellChecker/wxUI.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +############################################################ +# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program. If not, see . +# +############################################################ +import wx +import output +import config +import languageHandler +from enchant.checker import SpellChecker +from enchant.errors import DictNotFoundError + +class spellCheckerDialog(wx.Dialog): + def __init__(self, text, dictionary): + super(spellCheckerDialog, self).__init__(None, 1) + try: + if config.main["general"]["language"] == "system": self.checker = SpellChecker() + else: self.checker = SpellChecker(languageHandler.getLanguage()) + self.checker.set_text(text) + except DictNotFoundError: + wx.MessageDialog(None, _(u"A bug has happened. There are no dictionaries available for the selected language in TW Blue"), _(u"Error"), wx.ICON_ERROR).ShowModal() + self.Destroy() + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + word = wx.StaticText(panel, -1, _(u"Mis-spelled word")) + self.word = wx.TextCtrl(panel, -1) + wordBox = wx.BoxSizer(wx.HORIZONTAL) + wordBox.Add(word) + wordBox.Add(self.word) + context = wx.StaticText(panel, -1, _(u"Context")) + self.context = wx.TextCtrl(panel, -1) + contextBox = wx.BoxSizer(wx.HORIZONTAL) + contextBox.Add(context) + contextBox.Add(self.context) + suggest = wx.StaticText(panel, -1, _(u"Suggestions")) + self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE) + suggestionsBox = wx.BoxSizer(wx.HORIZONTAL) + suggestionsBox.Add(suggest) + suggestionsBox.Add(self.suggestions) + ignore = wx.Button(panel, -1, _(u"Ignore")) + self.Bind(wx.EVT_BUTTON, self.onIgnore, ignore) + ignoreAll = wx.Button(panel, -1, _(u"Ignore all")) + self.Bind(wx.EVT_BUTTON, self.onIgnoreAll, ignoreAll) + replace = wx.Button(panel, -1, _(u"Replace")) + self.Bind(wx.EVT_BUTTON, self.onReplace, replace) + replaceAll = wx.Button(panel, -1, _(u"Replace all")) + self.Bind(wx.EVT_BUTTON, self.onReplaceAll, replaceAll) + close = wx.Button(panel, wx.ID_CANCEL) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(ignore) + btnBox.Add(ignoreAll) + btnBox.Add(replace) + btnBox.Add(replaceAll) + btnBox.Add(close) + sizer.Add(wordBox) + sizer.Add(contextBox) + sizer.Add(suggestionsBox) + sizer.Add(btnBox) + panel.SetSizerAndFit(sizer) + self.check() + + def check(self): + try: + self.checker.next() + textToSay = _(u"Mis-spelled word: %s") % (self.checker.word,) + context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10)) + self.SetTitle(textToSay) + output.speak(textToSay) + self.word.SetValue(self.checker.word) + self.context.ChangeValue(context) + self.suggestions.Set(self.checker.suggest()) + self.suggestions.SetFocus() + except StopIteration: + wx.MessageDialog(self, _(u"The spelling review has finished."), _("Finished"), style=wx.OK).ShowModal() + self.EndModal(wx.ID_OK) + except AttributeError: + pass + + def onIgnore(self, ev): + self.check() + + def onIgnoreAll(self, ev): + self.checker.ignore_always(word=self.checker.word) + self.check() + + def onReplace(self, ev): + self.checker.replace(self.suggestions.GetStringSelection()) + self.check() + + def onReplaceAll(self, ev): + self.checker.replace_always(self.suggestions.GetStringSelection()) + self.check() \ No newline at end of file diff --git a/src/extra/translator/__init__.py b/src/extra/translator/__init__.py index 446fa201..40a96afc 100644 --- a/src/extra/translator/__init__.py +++ b/src/extra/translator/__init__.py @@ -1,3 +1 @@ # -*- coding: utf-8 -*- -from translator import * -import gui \ No newline at end of file diff --git a/src/extra/translator/gui.py b/src/extra/translator/wxUI.py similarity index 89% rename from src/extra/translator/gui.py rename to src/extra/translator/wxUI.py index 655c2850..14f93c66 100644 --- a/src/extra/translator/gui.py +++ b/src/extra/translator/wxUI.py @@ -17,11 +17,11 @@ # ############################################################ import wx -import translator +from wxUI.dialogs import baseDialog -class translateDialog(wx.Dialog): +class translateDialog(baseDialog.BaseDialog): def __init__(self): - wx.Dialog.__init__(self, None, -1, title=_(u"Translate message")) + super(translateDialog, self).__init__(None, -1, title=_(u"Translate message")) panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) staticSource = wx.StaticText(panel, -1, _(u"Source language")) @@ -38,7 +38,4 @@ class translateDialog(wx.Dialog): ok = wx.Button(panel, wx.ID_OK) ok.SetDefault() cancel = wx.Button(panel, wx.ID_CANCEL) - self.SetEscapeId(wx.ID_CANCEL) - - def onOk(self, ev): - self.EndModal(wx.ID_OK) + self.SetEscapeId(wx.ID_CANCEL) \ No newline at end of file diff --git a/src/gui/buffers/__init__.py b/src/gui/buffers/__init__.py deleted file mode 100644 index 15f935aa..00000000 --- a/src/gui/buffers/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -from panels import accountPanel, emptyPanel -from base import * -from dm import * -from events import * -from favourites import * -from lists import * -from people import * -from tweet_searches import * -from user_searches import * \ No newline at end of file diff --git a/src/gui/buffers/base.py b/src/gui/buffers/base.py deleted file mode 100644 index 619a20f2..00000000 --- a/src/gui/buffers/base.py +++ /dev/null @@ -1,364 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import gui.dialogs -import twitter -import webbrowser -import config -import sound -import url_shortener -import logging as original_logger -import output -import platform -import datetime -from twitter import prettydate -from multiplatform_widgets import widgets -from mysc import event -from mysc.thread_utils import call_threaded -from twython import TwythonError -log = original_logger.getLogger("buffers.base") - -class basePanel(wx.Panel): - - def bind_events(self): - self.Bind(event.MyEVT_OBJECT, self.update) - self.Bind(event.MyEVT_DELETED, self.Remove) - self.list.list.Bind(wx.EVT_CHAR_HOOK, self.interact) - if self.system == "Windows": - self.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocus) - else: - self.list.list.Bind(wx.EVT_LISTBOX, self.onFocus) - - def get_message(self, dialog=False): - if dialog == False: return " ".join(self.compose_function(self.db.settings[self.name_buffer][self.list.get_selected()], self.db)) - else: - list = self.compose_function(self.db.settings[self.name_buffer][self.list.get_selected()], self.db) - return " ".join(list[1:-2]) - - def create_list(self): - self.list = widgets.list(self, _(u"User"), _(u"Text"), _(u"Date"), _(u"Client"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) - if self.system == "Windows": - self.list.set_windows_size(0, 30) - self.list.set_windows_size(1, 160) - self.list.set_windows_size(2, 55) - self.list.set_windows_size(3, 42) - self.list.set_size() - - def __init__(self, parent, window, name_buffer, function=None, argumento=None, sound="", timeline=False): - if timeline == False: - self.type = "buffer" - elif timeline == True: - self.type = "timeline" - self.db = window.db - self.twitter = window.twitter - self.name_buffer = name_buffer - self.function = function - self.argumento = argumento - self.sound = sound - self.parent = window - self.compose_function = twitter.compose.compose_tweet - self.system = platform.system() - wx.Panel.__init__(self, parent) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.create_list() - self.btn = wx.Button(self, -1, _(u"Tweet")) - self.btn.Bind(wx.EVT_BUTTON, self.post_status) - self.retweetBtn = wx.Button(self, -1, _(u"Retweet")) - self.retweetBtn.Bind(wx.EVT_BUTTON, self.onRetweet) - self.responseBtn = wx.Button(self, -1, _(u"Reply")) - self.responseBtn.Bind(wx.EVT_BUTTON, self.onResponse) - self.dmBtn = wx.Button(self, -1, _(u"Direct message")) - self.dmBtn.Bind(wx.EVT_BUTTON, self.onDm) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer.Add(self.btn, 0, wx.ALL, 5) - btnSizer.Add(self.retweetBtn, 0, wx.ALL, 5) - btnSizer.Add(self.responseBtn, 0, wx.ALL, 5) - btnSizer.Add(self.dmBtn, 0, wx.ALL, 5) - self.sizer.Add(btnSizer, 0, wx.ALL, 5) - self.sizer.Add(self.list.list, 0, wx.ALL, 5) - self.bind_events() - self.SetSizer(self.sizer) - - def remove_buffer(self): - if self.type == "timeline": - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this timeline?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - names = config.main["other_buffers"]["timelines"] - user = self.name_buffer - log.info(u"Deleting %s's timeline" % user) - if user in names: - names.remove(user) - self.db.settings.pop(user) - pos = self.db.settings["buffers"].index(user) - self.db.settings["buffers"].remove(user) - return pos - elif self.type == "buffer": - output.speak(_(u"This buffer is not a timeline; it can't be deleted.")) - return None - - def remove_invalid_buffer(self): - if self.type == "timeline": - names = config.main["other_buffers"]["timelines"] - user = self.name_buffer - log.info(u"Deleting %s's timeline" % user) - if user in names: - names.remove(user) - self.db.settings.pop(user) - pos = self.db.settings["buffers"].index(user) - self.db.settings["buffers"].remove(user) - return pos - - def Remove(self, ev): -# try: - self.list.remove_item(ev.GetItem()) -# except: -# log.error(u"Cannot delete the %s item from list " % str(ev.GetItem())) - - def destroy_status(self, ev): - index = self.list.get_selected() - try: - self.twitter.twitter.destroy_status(id=self.db.settings[self.name_buffer][index]["id"]) - self.db.settings[self.name_buffer].pop(index) - self.list.remove_item(index) - if index > 0: - self.list.select_item(index-1) - except: - sound.player.play("error.ogg") - - def onFocus(self, ev): - if self.db.settings[self.name_buffer][self.list.get_selected()].has_key("retweeted_status"): tweet = self.db.settings[self.name_buffer][self.list.get_selected()]["retweeted_status"] - else: tweet = self.db.settings[self.name_buffer][self.list.get_selected()] - if config.main["general"]["relative_times"] == True: - # On windows we need only put the new date on the column, but under linux and mac it isn't possible. - if self.system == "Windows": - original_date = datetime.datetime.strptime(tweet["created_at"], "%a %b %d %H:%M:%S +0000 %Y") - date = original_date-datetime.timedelta(seconds=-self.db.settings["utc_offset"]) - ts = prettydate(original_date) - self.list.list.SetStringItem(self.list.get_selected(), 2, ts) - else: - self.list.list.SetString(self.list.get_selected(), " ".join(self.compose_function(self.db.settings[self.name_buffer][self.list.get_selected()], self.db))) - if twitter.utils.is_audio(tweet): - sound.player.play("audio.ogg", False) - - def start_streams(self): - if self.name_buffer == "sent": - num = twitter.starting.start_sent(self.db, self.twitter, self.name_buffer, self.function, param=self.argumento) - else: -# try: - if self.argumento != None: - num = twitter.starting.start_stream(self.db, self.twitter, self.name_buffer, self.function, param=self.argumento) - else: - num = twitter.starting.start_stream(self.db, self.twitter, self.name_buffer, self.function) -# except TwythonError: -# raise TwythonError -# self.parent.delete_invalid_timeline() - if self.sound != "" and num > 0 and self.name_buffer != "home_timeline" and self.name_buffer != "sent": sound.player.play(self.sound) - return num - - def get_more_items(self): - if config.main["general"]["reverse_timelines"] == False: - last_id = self.db.settings[self.name_buffer][0]["id"] - else: - last_id = self.db.settings[self.name_buffer][-1]["id"] - try: - items = twitter.starting.get_more_items(self.function, self.twitter, count=config.main["general"]["max_tweets_per_call"], max_id=last_id, screen_name=self.argumento) - except TwythonError as e: - output.speak(e.message) - for i in items: - if config.main["general"]["reverse_timelines"] == False: - self.db.settings[self.name_buffer].insert(0, i) - else: - self.db.settings[self.name_buffer].append(i) - if config.main["general"]["reverse_timelines"] == False: - for i in items: - tweet = self.compose_function(i, self.db) - self.list.insert_item(True, *tweet) - else: - for i in items: - tweet = self.compose_function(i, self.db) - self.list.insert_item(False, *tweet) - output.speak(_(u"%s items retrieved") % (len(items))) - - def put_items(self, num): - if self.list.get_count() == 0: - for i in self.db.settings[self.name_buffer]: - tweet = self.compose_function(i, self.db) - self.list.insert_item(False, *tweet) - self.set_list_position() - elif self.list.get_count() > 0: - if config.main["general"]["reverse_timelines"] == False: - for i in self.db.settings[self.name_buffer][:num]: - tweet = self.compose_function(i, self.db) - self.list.insert_item(False, *tweet) - else: - for i in self.db.settings[self.name_buffer][0:num]: - tweet = self.compose_function(i, self.db) - self.list.insert_item(True, *tweet) - - def onDm(self, ev): - if self.name_buffer == "sent": return - if self.name_buffer == "direct_messages": - self.onResponse(ev) - else: - user = self.db.settings[self.name_buffer][self.list.get_selected()]["user"]["screen_name"] - dlg = gui.dialogs.message.dm(_("Direct message to %s") % (user,), _(u"New direct message"), "", self) - if dlg.ShowModal() == wx.ID_OK: - call_threaded(self.twitter.api_call, call_name="send_direct_message", _sound="dm_sent.ogg", text=dlg.text.GetValue(), screen_name=dlg.cb.GetValue()) -# dlg.Destroy() - if ev != None: - self.list.list.SetFocus() - - def post_status(self, ev=None): - text = gui.dialogs.message.tweet(_(u"Write the tweet here"), _(u"Tweet"), "", self) - if text.ShowModal() == wx.ID_OK: - if text.image == None: - call_threaded(self.twitter.api_call, call_name="update_status", _sound="tweet_send.ogg", status=text.text.GetValue()) - else: - call_threaded(self.twitter.api_call, call_name="update_status_with_media", _sound="tweet_send.ogg", status=text.text.GetValue(), media=text.file) -# text.Destroy() - if ev != None: self.list.list.SetFocus() - - def onRetweet(self, ev): - if self.name_buffer != "direct_messages": - id=self.db.settings[self.name_buffer][self.list.get_selected()]["id"] - ask = wx.MessageDialog(self.parent, _(u"Would you like to add a comment to this tweet?"), _("Retweet"), wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) - response = ask.ShowModal() - if response == wx.ID_YES: - dlg = gui.dialogs.message.retweet(_(u"Add your comment to the tweet"), _(u"Retweet"), u"“@%s: %s ”" % (self.db.settings[self.name_buffer][self.list.get_selected()]["user"]["screen_name"], self.db.settings[self.name_buffer][self.list.get_selected()]["text"]), self) - if dlg.ShowModal() == wx.ID_OK: - if dlg.image == None: - call_threaded(self.twitter.api_call, call_name="update_status", _sound="retweet_send.ogg", status=dlg.text.GetValue(), in_reply_to_status_id=dlg.in_reply_to) - else: - call_threaded(self.twitter.call_api, call_name="update_status_with_media", _sound="retweet_send.ogg", status=dlg.text.GetValue(), in_reply_to_status_id=text.in_reply_to, media=dlg.file) -# dlg.Destroy() - if ev != None: - self.list.list.SetFocus() - elif response == wx.ID_NO: - call_threaded(self.twitter.api_call, call_name="retweet", _sound="retweet_send.ogg", id=id) - if ev != None: self.list.list.SetFocus() - ask.Destroy() - - def onResponse(self, ev): - if self.name_buffer == "sent": return - dlg = gui.dialogs.message.reply(_(u"Reply to %s") % (self.db.settings[self.name_buffer][self.list.get_selected()]["user"]["screen_name"]), _(u"Reply"), u"@%s " % (self.db.settings[self.name_buffer][self.list.get_selected()]["user"]["screen_name"]), self) - if dlg.ShowModal() == wx.ID_OK: - if dlg.image == None: - call_threaded(self.twitter.api_call, call_name="update_status", _sound="reply_send.ogg", in_reply_to_status_id=dlg.in_reply_to, status=dlg.text.GetValue()) - else: - call_threaded(self.twitter.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", in_reply_to_status_id=dlg.in_reply_to, status=dlg.text.GetValue(), media=dlg.file) -# dlg.Destroy() - if ev != None: self.list.list.SetFocus() - - def update(self, ev): - data = ev.GetItem() - announce = ev.GetAnnounce() - if config.main["general"]["reverse_timelines"] == False: self.db.settings[self.name_buffer].append(data) - else: self.db.settings[self.name_buffer].insert(0, data) - tweet = self.compose_function(data, self.db) - self.list.insert_item(config.main["general"]["reverse_timelines"], *tweet) - if self.name_buffer not in config.main["other_buffers"]["muted_buffers"]: - if self.sound != "": sound.player.play(self.sound) - if announce != "": output.speak(announce) - if self.name_buffer in config.main["other_buffers"]["autoread_buffers"]: - output.speak(" ".join(tweet[:2])) - - def interact(self, ev): - try: - if self.db.settings[self.name_buffer][self.list.get_selected()].has_key("retweeted_status"): tweet = self.db.settings[self.name_buffer][self.list.get_selected()]["retweeted_status"] - else: tweet = self.db.settings[self.name_buffer][self.list.get_selected()] - urls = twitter.utils.find_urls_in_text(tweet["text"]) - except: - urls = [] - if type(ev) is str: event = ev - else: - if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio" - elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url" - elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down" - elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" - elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" - elif ev.GetKeyCode() == wx.WXK_DELETE: event = "delete_item" - else: - ev.Skip() - return - if event == "audio" and len(urls) > 0: - self.streamer(urls[0]) - elif event == "url": - if len(urls) == 0: return - elif len(urls) == 1: - output.speak(_(u"Opening URL..."), True) - webbrowser.open(urls[0]) - elif len(urls) > 1: - gui.dialogs.urlList.urlList(urls).ShowModal() - elif event == "volume_down": - if config.main["sound"]["volume"] > 0.05: - config.main["sound"]["volume"] = config.main["sound"]["volume"]-0.05 - sound.player.play("volume_changed.ogg", False) - if hasattr(self.parent, "audioStream"): - self.parent.audioStream.stream.volume = config.main["sound"]["volume"] - elif event == "volume_up": - if config.main["sound"]["volume"] < 0.95: - config.main["sound"]["volume"] = config.main["sound"]["volume"]+0.05 - sound.player.play("volume_changed.ogg", False) - if hasattr(self.parent, "audioStream"): - self.parent.audioStream.stream.volume = config.main["sound"]["volume"] - elif event == "clear_list" and self.list.get_count() > 0: - dlg = wx.MessageDialog(self, _(u"Do you really want to empty this buffer? It's tweets will be removed from the list but not from Twitter"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - self.db.settings[self.name_buffer] = [] - self.list.clear() - elif event == "delete_item": - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this message?"), _(u"Delete"), wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - self.destroy_status(wx.EVT_MENU) - else: - return - try: - ev.Skip() - except: - pass - - def streamer(self, url): - if hasattr(self.parent, "audioStream"): - if self.parent.audioStream.stream.is_active() == 0: - output.speak(_(u"Playing...")) - self.parent.audioStream = sound.urlStream(url) - try: - self.parent.audioStream.prepare() - self.parent.audioStream.play() - except: - del self.parent.audioStream - output.speak(_(u"Unable to play audio.")) - else: - output.speak(_(u"Audio stopped.")) - self.parent.audioStream.stream.stop() - else: - output.speak(_(u"Playing...")) - self.parent.audioStream = sound.urlStream(url) - try: - self.parent.audioStream.prepare() - self.parent.audioStream.play() - except: - output.speak(_(u"Unable to play audio.")) - del self.parent.audioStream - - def set_list_position(self): - if config.main["general"]["reverse_timelines"] == False: - self.list.select_item(len(self.db.settings[self.name_buffer])-1) - else: - self.list.select_item(0) diff --git a/src/gui/buffers/dm.py b/src/gui/buffers/dm.py deleted file mode 100644 index 468d2f5a..00000000 --- a/src/gui/buffers/dm.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import sound -import gui.dialogs -import logging as original_logger -from base import basePanel -from mysc.thread_utils import call_threaded -log = original_logger.getLogger("buffers.base") - -class dmPanel(basePanel): - def __init__(self, parent, window, name_buffer, function, argumento=None, sound=""): - """ Class to DM'S. Reply and retweet buttons are not showed and they have your delete method for dm's.""" - super(dmPanel, self).__init__(parent, window, name_buffer, function, argumento=argumento, sound=sound) - self.retweetBtn.Disable() - self.responseBtn.Disable() - - def destroy_status(self, ev): - index = self.list.get_selected() - try: - self.twitter.twitter.destroy_direct_message(id=self.db.settings[self.name_buffer][index]["id"]) - self.db.settings[self.name_buffer].pop(index) - self.remove_item(index) - except: - sound.player.play("error.ogg") - - def onResponse(self, ev): - dlg = gui.dialogs.message.dm(_("Direct message to %s") % (self.db.settings[self.name_buffer][self.list.get_selected()]["sender"]["screen_name"]), _(u"New direct message"), "", self) - if dlg.ShowModal() == wx.ID_OK: - call_threaded(self.twitter.api_call, call_name="send_direct_message", _sound="dm_sent.ogg", text=dlg.text.GetValue(), screen_name=dlg.cb.GetValue()) - if ev != None: - self.list.list.SetFocus() \ No newline at end of file diff --git a/src/gui/buffers/events.py b/src/gui/buffers/events.py deleted file mode 100644 index 0b67d697..00000000 --- a/src/gui/buffers/events.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import sound -import config -import platform -import gui.dialogs -import output -import logging as original_logger -from multiplatform_widgets import widgets -from mysc import event -from mysc.thread_utils import call_threaded -log = original_logger.getLogger("buffers.base") - -class eventsPanel(wx.Panel): - """ Buffer to show events. Different than tweets or people.""" - - def get_more_items(self): - output.speak(_(u"This action is not supported for this buffer")) - - def bind_events(self): - self.Bind(event.MyEVT_OBJECT, self.update) - - def put_items(self, items): - pass - - def get_selected_text(self): - if self.list.get_count() == 0: return _(u"Empty") - if self.system == "Windows": - return "%s. %s" % (self.list.list.GetItemText(self.list.get_selected()), self.list.list.GetItemText(self.list.get_selected(), 1)) - else: - return self.list.list.GetStringSelection() - - def get_message(self, dialog=False): - return self.get_selected_text() - - def __init__(self, parent, window, sound=""): - self.type = "event" - self.system = platform.system() - self.name_buffer = "events" - self.parent = window - self.sound = "new_event.ogg" - wx.Panel.__init__(self, parent) - sizer = wx.BoxSizer() - self.list = widgets.list(self, _(u"Date"), _(u"Event"), size=(600,600), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) - self.tweet = wx.Button(self, -1, _(u"Tweet")) - self.tweet.Bind(wx.EVT_BUTTON, self.post_status) - self.delete_event = wx.Button(self, -1, _(u"Remove event")) - self.delete_event.Bind(wx.EVT_BUTTON, self.on_delete_event) - self.bind_events() - - def on_delete_event(self, ev): - self.list.remove_item(self.get_selected()) - - def remove_buffer(self): - return None - - def start_streams(self): - return 0 - - def post_status(self, ev=None): - text = gui.dialogs.message.tweet(_(u"Write the tweet here"), _(u"Tweet"), "", self.parent) - if text.ShowModal() == wx.ID_OK: - if text.image == None: - call_threaded(self.parent.twitter.api_call, call_name="update_status", _sound="tweet_send.ogg", status=text.text.GetValue()) - else: - call_threaded(self.parent.twitter.api_call, call_name="update_status_with_media", _sound="tweet_send.ogg", status=text.text.GetValue(), media=text.file) -# text.Destroy() - if ev != None: self.list.list.SetFocus() - - def update(self, ev): - tweet = ev.GetItem() - announce = ev.GetAnnounce() - self.list.insert_item(config.main["general"]["reverse_timelines"], *tweet) - if self.list.get_count() == 1: - self.list.select_item(0) - if self.name_buffer not in config.main["other_buffers"]["muted_buffers"]: - if self.sound != "": sound.player.play(self.sound) -# if announce != "": output.speak(announce) - if self.name_buffer in config.main["other_buffers"]["autoread_buffers"]: - output.speak(" ".join(tweet)) - - def interact(self, ev): - if type(ev) is str: event = ev - else: - if ev.GetKeyCode() == wx.WXK_F5: event = "volume_down" - elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" - elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" - elif ev.GetKeyCode() == wx.WXK_DELETE: event = "delete_item" - else: - ev.Skip() - return - if event == "volume_down": - if config.main["sound"]["volume"] > 0.05: - config.main["sound"]["volume"] = config.main["sound"]["volume"]-0.05 - sound.player.play("volume_changed.ogg", False) - if hasattr(self.parent, "audioStream"): - self.parent.audioStream.stream.volume = config.main["sound"]["volume"] - elif event == "volume_up": - if config.main["sound"]["volume"] < 0.95: - config.main["sound"]["volume"] = config.main["sound"]["volume"]+0.05 - sound.player.play("volume_changed.ogg", False) - if hasattr(self.parent, "audioStream"): - self.parent.audioStream.stream.volume = config.main["sound"]["volume"] - elif event == "clear_list" and self.get_count() > 0: - dlg = wx.MessageDialog(self, _(u"Do you really want to empty this buffer? It's tweets will be removed from the list but not from Twitter"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - self.list.clear() - elif event == "delete_item": - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this message?"), _(u"Delete"), wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - self.list.remove_item(self.list.get_selected()) - else: - return - try: - ev.Skip() - except: - pass \ No newline at end of file diff --git a/src/gui/buffers/favourites.py b/src/gui/buffers/favourites.py deleted file mode 100644 index e9dea0fd..00000000 --- a/src/gui/buffers/favourites.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import twitter -import config -import sound -import logging as original_logger -from base import basePanel -log = original_logger.getLogger("buffers.base") - -class favsPanel(basePanel): - def __init__(self, parent, window, name_buffer, argumento=None, sound=""): - super(favsPanel, self).__init__(parent, window, name_buffer, function="", argumento=argumento, sound=sound) - self.type = "favourites_timeline" - - def start_streams(self): - num = twitter.starting.get_favourites_timeline(self.db, self.twitter, self.name_buffer, param=self.argumento, count=200) - if self.sound != "" and num > 0: - sound.player.play(self.sound) - if self.list.get_count() > 0: self.put_items(num) - return num - return num - - def remove_buffer(self): - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this favourites timeline?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - names = config.main["other_buffers"]["favourites_timelines"] - user = self.argumento - log.info(u"Deleting %s's timeline" % user) - if user in names: - names.remove(user) - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos - - def remove_invalid_buffer(self): - names = config.main["other_buffers"]["favourites_timelines"] - user = self.name_buffer[:-5] - log.info(u"Deleting %s's timeline" % user) - if user in names: - names.remove(user) - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos \ No newline at end of file diff --git a/src/gui/buffers/lists.py b/src/gui/buffers/lists.py deleted file mode 100644 index 1440391f..00000000 --- a/src/gui/buffers/lists.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import sound -import config -import twitter -import gui.dialogs -import logging as original_logger -from base import basePanel -from mysc.thread_utils import call_threaded -log = original_logger.getLogger("buffers.base") - -class listPanel(basePanel): - def __init__(self, parent, window, name_buffer, argumento="", sound=""): - super(listPanel, self).__init__(parent, window, name_buffer, argumento=argumento, sound=sound) - self.type = "list" - self.users = [] - self.sound = "list_tweet.ogg" - - def start_streams(self): - self.retrieve_ids() - num = twitter.starting.start_list(self.db, self.twitter, self.name_buffer, list_id=self.argumento) - return num - - def retrieve_ids(self): - self.users = twitter.starting.get_users_list(self.twitter, self.argumento) - - def remove_buffer(self): - if self.type == "list": - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this list?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - names = config.main["other_buffers"]["lists"] - user = self.name_buffer[:-5] - log.info(u"Deleting %s's list" % user) - if user in names: - names.remove(user) - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos - - def remove_invalid_buffer(self): - if self.type == "list": - names = config.main["other_buffers"]["lists"] - user = self.name_buffer[:-5] - log.info(u"Deleting %s's list" % user) - if user in names: - names.remove(user) - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos \ No newline at end of file diff --git a/src/gui/buffers/people.py b/src/gui/buffers/people.py deleted file mode 100644 index b2e0a8d5..00000000 --- a/src/gui/buffers/people.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import sound -import config -import twitter -import gui.dialogs -import logging as original_logger -import output -from multiplatform_widgets import widgets -from mysc import event -from base import basePanel -from mysc.thread_utils import call_threaded -from twython import TwythonError -log = original_logger.getLogger("buffers.base") - -class peoplePanel(basePanel): - """ Buffer used to show people.""" - def bind_events(self): - self.Bind(event.MyEVT_OBJECT, self.update) - self.Bind(event.MyEVT_DELETED, self.Remove) - self.list.list.Bind(wx.EVT_CHAR_HOOK, self.interact) - - def create_list(self): - self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) - - def __init__(self, parent, window, name_buffer, function, argumento=None, sound="", timeline=False): - self.type = "people" - super(peoplePanel, self).__init__(parent, window, name_buffer, function, argumento=argumento, sound=sound) - self.responseBtn.SetLabel(_(u"Mention")) - self.retweetBtn.Disable() - self.compose_function = twitter.compose.compose_followers_list - - def onDm(self, ev): - if self.name_buffer == "sent": return - if self.name_buffer == "direct_messages": - self.onResponse(ev) - else: - user = self.db.settings[self.name_buffer][self.list.get_selected()]["screen_name"] - dlg = gui.dialogs.message.dm(_("Direct message to %s") % (user,), _(u"New direct message"), "", self) - if dlg.ShowModal() == wx.ID_OK: - call_threaded(self.twitter.api_call, call_name="send_direct_message", _sound="dm_sent.ogg", text=dlg.text.GetValue(), screen_name=dlg.cb.GetValue()) -# dlg.Destroy() - if ev != None: - self.list.list.SetFocus() - - def onResponse(self, ev): - dlg = gui.dialogs.message.reply(_(u"Mention to %s") % (self.db.settings[self.name_buffer][self.list.get_selected()]["screen_name"]), _(u"Mention"), u"@%s " % (self.db.settings[self.name_buffer][self.list.get_selected()]["screen_name"]), self) - if dlg.ShowModal() == wx.ID_OK: - if dlg.image == None: - call_threaded(self.twitter.api_call, call_name="update_status", _sound="reply_send.ogg", in_reply_to_status_id=dlg.in_reply_to, status=dlg.text.GetValue()) - else: - call_threaded(self.twitter.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", in_reply_to_status_id=dlg.in_reply_to, status=dlg.text.GetValue(), media=dlg.file) -# dlg.Destroy() - if ev != None: self.list.list.SetFocus() - - def Remove(self, ev): - try: - index = self.list.get_selected() - self.list.remove_item(ev.GetItem()) - except: - log.error("Unable to delete element %s from the list %s" % (str(ev.GetItem(), self.name_buffer))) - - def start_streams(self): - num = twitter.starting.start_followers(self.db, self.twitter, self.name_buffer, self.function, param=self.argumento) -# sound.player.play(self.sound) - return num - - def put_items(self, num): - if self.list.get_count() > 0: - self.list.clear() - for i in self.db.settings[self.name_buffer]: - f = self.compose_function(i, self.db) - self.list.insert_item(False, *f) - self.set_list_position() - - def get_more_items(self): - if self.name_buffer == "followers": cursor = twitter.starting.followers_cursor - elif self.name_buffer == "friends": cursor = twitter.starting.friends_cursor - try: - items = twitter.starting.get_more_items(self.function, self.twitter, users=True, name=self.name_buffer, count=config.main["general"]["max_tweets_per_call"], cursor=cursor) - except TwythonError as e: - output.speak(e.message) - return - for i in items: - if config.main["general"]["reverse_timelines"] == False: - self.db.settings[self.name_buffer].insert(0, i) - else: - self.db.settings[self.name_buffer].append(i) - if config.main["general"]["reverse_timelines"] == False: - for i in items: - tweet = self.compose_function(i, self.db) - self.list.insert_item(True, *tweet) - else: - for i in items: - tweet = self.compose_function(i, self.db) - self.list.insert_item(False, *tweet) - output.speak(_(u"%s items retrieved") % (len(items))) - - def interact(self, ev): - if type(ev) is str: event = ev - else: - if ev.GetKeyCode() == wx.WXK_RETURN: - event = "url" - elif ev.GetKeyCode() == wx.WXK_F5: - event = "volume_down" - elif ev.GetKeyCode() == wx.WXK_F6: - event = "volume_down" - else: - ev.Skip() - return - if event == "url": - gui.dialogs.show_user.showUserProfile(self.parent.twitter, self.db.settings[self.name_buffer][self.list.get_selected()]["screen_name"]).ShowModal() - elif event == "volume_down": - if config.main["sound"]["volume"] > 0.05: - config.main["sound"]["volume"] = config.main["sound"]["volume"]-0.05 - sound.player.play("volume_changed.ogg") - elif event == "volume_up": - if config.main["sound"]["volume"] < 0.95: - config.main["sound"]["volume"] = config.main["sound"]["volume"]+0.05 - sound.player.play("volume_changed.ogg") - if type(ev) is not str: ev.Skip() - - def remove_buffer(self): - pos = None - return pos diff --git a/src/gui/buffers/trends.py b/src/gui/buffers/trends.py deleted file mode 100644 index 1b04de9d..00000000 --- a/src/gui/buffers/trends.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import sound -import config -import twitter -import gui.dialogs -import logging as original_logger -from base import basePanel -log = original_logger.getLogger("buffers.base") - -class trendPanel(basePanel): - def __init__(self, parent, window, name_buffer, *args, **kwargs): - super(searchPanel, self).__init__(parent, window, name_buffer, sound) - self.type = "trend" - self.args = kwargs - - def start_streams(self): - num = twitter.starting.search(self.db, self.twitter, self.name_buffer, **self.args) - if num > 0: sound.player.play("search_updated.ogg") - self.put_items(num) - return num - - def remove_buffer(self): - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this search term?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - names = config.main["other_buffers"]["tweet_searches"] - user = self.name_buffer[:-7] - log.info(u"Deleting %s's search term" % user) - if user in names: - names.remove(user) - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos \ No newline at end of file diff --git a/src/gui/buffers/tweet_searches.py b/src/gui/buffers/tweet_searches.py deleted file mode 100644 index b82cc5c9..00000000 --- a/src/gui/buffers/tweet_searches.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import sound -import config -import twitter -import gui.dialogs -import output -import logging as original_logger -from base import basePanel -log = original_logger.getLogger("buffers.base") - -class searchPanel(basePanel): - def __init__(self, parent, window, name_buffer, *args, **kwargs): - super(searchPanel, self).__init__(parent, window, name_buffer, sound) - self.type = "search" - self.args = kwargs - - def load_search(self): - num = self.start_streams() - self.put_items(num) - - def start_streams(self): - num = twitter.starting.search(self.db, self.twitter, self.name_buffer, **self.args) - if num > 0: sound.player.play("search_updated.ogg") - return num - - def remove_buffer(self): - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this search term?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - names = config.main["other_buffers"]["tweet_searches"] - user = self.name_buffer[:-7] - log.info(u"Deleting %s's search term" % user) - if user in names: - names.remove(user) - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos - - def get_more_items(self): - output.speak(_(u"This action is not supported for this buffer")) \ No newline at end of file diff --git a/src/gui/buffers/user_searches.py b/src/gui/buffers/user_searches.py deleted file mode 100644 index 83748936..00000000 --- a/src/gui/buffers/user_searches.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import twitter -import logging as original_logger -import sound -from people import peoplePanel -from mysc import event -from multiplatform_widgets import widgets -log = original_logger.getLogger("buffers.base") - -class searchUsersPanel(peoplePanel): - def create_list(self): - """ Returns the list for put the tweets here.""" - self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) - -# def bind_events(self): -# self.Bind(event.MyEVT_OBJECT, self.update) -# self.list.list.Bind(wx.EVT_CHAR_HOOK, self.interact) - - def __init__(self, parent, window, name_buffer, *args, **kwargs): - super(searchUsersPanel, self).__init__(parent, window, name_buffer, function=None) - self.compose_function = twitter.compose.compose_followers_list - self.create_list() - self.args = args - self.kwargs = kwargs - self.type = "timeline" - - def start_streams(self): - num = twitter.starting.search_users(self.db, self.twitter, self.name_buffer, **self.kwargs) - if num > 0: sound.player.play("search_updated.ogg") -# self.put_items(num) - return num - - def load_search(self): - num = self.start_streams() - self.put_items(num) - - def remove_buffer(self): - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this search term?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - self.db.settings.pop(self.name_buffer) - pos = self.db.settings["buffers"].index(self.name_buffer) - self.db.settings["buffers"].remove(self.name_buffer) - return pos - - def get_more_items(self): - output.speak(_(u"This action is not supported for this buffer")) \ No newline at end of file diff --git a/src/gui/dialogs/__init__.py b/src/gui/dialogs/__init__.py deleted file mode 100644 index a888a3a1..00000000 --- a/src/gui/dialogs/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import message, urlList, follow, utils, show_user, update_profile, configuration, lists, search \ No newline at end of file diff --git a/src/gui/dialogs/configuration.py b/src/gui/dialogs/configuration.py deleted file mode 100644 index 782ea44d..00000000 --- a/src/gui/dialogs/configuration.py +++ /dev/null @@ -1,424 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import config -#import gui -from gui import buffers -import sound as snd -import sound_lib -import languageHandler -import logging as original_logger -import os -import webbrowser -import paths -import platform -from mysc import restart -log = original_logger.getLogger("configuration") - -system = platform.system() -class general(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - sizer = wx.BoxSizer(wx.VERTICAL) - language = wx.StaticText(self, -1, _(u"Language")) - self.langs = languageHandler.getAvailableLanguages() - langs = [] - [langs.append(i[1]) for i in self.langs] - self.codes = [] - [self.codes.append(i[0]) for i in self.langs] - self.language = wx.ListBox(self, -1, choices=langs) - id = self.codes.index(config.main["general"]["language"]) - self.language.SetSelection(id) - self.language.SetSize(self.language.GetBestSize()) - langBox = wx.BoxSizer(wx.HORIZONTAL) - langBox.Add(language, 0, wx.ALL, 5) - langBox.Add(self.language, 0, wx.ALL, 5) - sizer.Add(langBox, 0, wx.ALL, 5) - self.ask_at_exit = wx.CheckBox(self, -1, _(U"ask before exiting TwBlue?")) - self.ask_at_exit.SetValue(config.main["general"]["ask_at_exit"]) - sizer.Add(self.ask_at_exit, 0, wx.ALL, 5) - self.relative_time = wx.CheckBox(self, -1, _(U"Relative times")) - self.relative_time.SetValue(config.main["general"]["relative_times"]) - sizer.Add(self.relative_time, 0, wx.ALL, 5) - if platform.system() == "Windows": - self.disable_sapi5 = wx.CheckBox(self, -1, _(u"Activate Sapi5 when any other screen reader is not being run")) - self.disable_sapi5.SetValue(config.main["general"]["voice_enabled"]) - sizer.Add(self.disable_sapi5, 0, wx.ALL, 5) - self.show_gui = wx.CheckBox(self, -1, _(u"Activate the auto-start of the invisible interface")) - self.show_gui.SetValue(config.main["general"]["hide_gui"]) - sizer.Add(self.show_gui, 0, wx.ALL, 5) - apiCallsBox = wx.BoxSizer(wx.HORIZONTAL) - apiCallsBox.Add(wx.StaticText(self, -1, _(u"API calls when the stream is started (One API call equals to 200 tweetts, two API calls equals 400 tweets, etc):")), 0, wx.ALL, 5) - self.apiCalls = wx.SpinCtrl(self, -1) - self.apiCalls.SetRange(1, 10) - self.apiCalls.SetValue(config.main["general"]["max_api_calls"]) - self.apiCalls.SetSize(self.apiCalls.GetBestSize()) - apiCallsBox.Add(self.apiCalls, 0, wx.ALL, 5) - sizer.Add(apiCallsBox, 0, wx.ALL, 5) - tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL) - tweetsPerCallBox.Add(wx.StaticText(self, -1, _(u"Items on each API call")), 0, wx.ALL, 5) - self.itemsPerApiCall = wx.SpinCtrl(self, -1) - self.itemsPerApiCall.SetRange(0, 200) - self.itemsPerApiCall.SetValue(config.main["general"]["max_tweets_per_call"]) - self.itemsPerApiCall.SetSize(self.itemsPerApiCall.GetBestSize()) - tweetsPerCallBox.Add(self.itemsPerApiCall, 0, wx.ALL, 5) - sizer.Add(tweetsPerCallBox, 0, wx.ALL, 5) - self.reverse_timelines = wx.CheckBox(self, -1, _(u"Inverted buffers: The newest tweets will be shown at the beginning of the lists while the oldest at the end")) - self.reverse_timelines.SetValue(config.main["general"]["reverse_timelines"]) - sizer.Add(self.reverse_timelines, 0, wx.ALL, 5) - self.SetSizer(sizer) - -class other_buffers(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - sizer = wx.BoxSizer(wx.VERTICAL) - self.followers_value = config.main["other_buffers"]["show_followers"] - self.friends_value = config.main["other_buffers"]["show_friends"] - self.favs_value = config.main["other_buffers"]["show_favourites"] - self.events_value = config.main["other_buffers"]["show_events"] - self.blocks_value = config.main["other_buffers"]["show_blocks"] - self.mutes_value = config.main["other_buffers"]["show_muted_users"] - self.followers = wx.CheckBox(self, -1, _(u"Show followers")) - self.followers.SetValue(config.main["other_buffers"]["show_followers"]) - sizer.Add(self.followers, 0, wx.ALL, 5) - self.friends = wx.CheckBox(self, -1, _(u"Show friends")) - self.friends.SetValue(config.main["other_buffers"]["show_friends"]) - sizer.Add(self.friends, 0, wx.ALL, 5) - self.favs = wx.CheckBox(self, -1, _(u"Show favourites")) - self.favs.SetValue(config.main["other_buffers"]["show_favourites"]) - sizer.Add(self.favs, 0, wx.ALL, 5) - self.blocks = wx.CheckBox(self, -1, _(u"Show blocked users")) - self.blocks.SetValue(config.main["other_buffers"]["show_blocks"]) - sizer.Add(self.blocks, 0, wx.ALL, 5) - self.mutes = wx.CheckBox(self, -1, _(u"Show muted users")) - self.mutes.SetValue(config.main["other_buffers"]["show_muted_users"]) - sizer.Add(self.mutes, 0, wx.ALL, 5) - self.events = wx.CheckBox(self, -1, _(u"Show events")) - self.events.SetValue(config.main["other_buffers"]["show_events"]) - sizer.Add(self.events, 0, wx.ALL, 5) - self.SetSizer(sizer) - -class ignoredClients(wx.Panel): - def __init__(self, parent): - super(ignoredClients, self).__init__(parent=parent) - sizer = wx.BoxSizer(wx.VERTICAL) - choices = config.main["twitter"]["ignored_clients"] - label = wx.StaticText(self, -1, _(u"Ignored clients")) - self.clients = wx.ListBox(self, -1, choices=choices) - self.clients.SetSize(self.clients.GetBestSize()) - clientsBox = wx.BoxSizer(wx.HORIZONTAL) - clientsBox.Add(label, 0, wx.ALL, 5) - clientsBox.Add(self.clients, 0, wx.ALL, 5) - add = wx.Button(self, -1, _(u"Add client")) - remove = wx.Button(self, -1, _(u"Remove client")) - self.Bind(wx.EVT_BUTTON, self.add, add) - self.Bind(wx.EVT_BUTTON, self.remove, remove) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(add, 0, wx.ALL, 5) - btnBox.Add(remove, 0, wx.ALL, 5) - sizer.Add(clientsBox, 0, wx.ALL, 5) - sizer.Add(btnBox, 0, wx.ALL, 5) - self.SetSizer(sizer) - - def add(self, ev): - entry = wx.TextEntryDialog(self, _(u"Enter the name of the client here"), _(u"Add a new ignored client")) - if entry.ShowModal() == wx.ID_OK: - client = entry.GetValue() - if client not in config.main["twitter"]["ignored_clients"]: - config.main["twitter"]["ignored_clients"].append(client) - self.clients.Append(client) - - def remove(self, ev): - if self.clients.GetCount() == 0: return - id = self.clients.GetSelection() - config.main["twitter"]["ignored_clients"].pop(id) - self.clients.Delete(id) - -class sound(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - sizer = wx.BoxSizer(wx.VERTICAL) - volume = wx.StaticText(self, -1, _(u"Volume")) - self.volumeCtrl = wx.Slider(self) - self.volumeCtrl.SetRange(0, 100) - self.volumeCtrl.SetValue(config.main["sound"]["volume"]*100) - self.volumeCtrl.SetSize(self.volumeCtrl.GetBestSize()) - volumeBox = wx.BoxSizer(wx.HORIZONTAL) - volumeBox.Add(volume, 0, wx.ALL, 5) - volumeBox.Add(self.volumeCtrl, 0, wx.ALL, 5) - sizer.Add(volumeBox, 0, wx.ALL, 5) - self.global_mute = wx.CheckBox(self, -1, _(u"Global mute")) - self.global_mute.SetValue(config.main["sound"]["global_mute"]) - sizer.Add(self.global_mute, 0, wx.ALL, 5) - self.output_devices = sound_lib.output.Output.get_device_names() - output_label = wx.StaticText(self, -1, _(u"Output device")) - self.output = wx.ComboBox(self, -1, choices=self.output_devices, style=wx.CB_READONLY) - self.output.SetValue(config.main["sound"]["output_device"]) - self.output.SetSize(self.output.GetBestSize()) - outputBox = wx.BoxSizer(wx.HORIZONTAL) - outputBox.Add(output_label, 0, wx.ALL, 5) - outputBox.Add(self.output, 0, wx.ALL, 5) - sizer.Add(outputBox, 0, wx.ALL, 5) - self.input_devices = sound_lib.input.Input.get_device_names() - input_label = wx.StaticText(self, -1, _(u"Input device")) - self.input = wx.ComboBox(self, -1, choices=self.input_devices, style=wx.CB_READONLY) - self.input.SetValue(config.main["sound"]["input_device"]) - self.input.SetSize(self.input.GetBestSize()) - inputBox = wx.BoxSizer(wx.HORIZONTAL) - inputBox.Add(input_label, 0, wx.ALL, 5) - inputBox.Add(self.input, 0, wx.ALL, 5) - sizer.Add(inputBox, 0, wx.ALL, 5) - soundBox = wx.BoxSizer(wx.VERTICAL) - self.soundpacks = [] - [self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(paths.sound_path(i)) == True ] - soundpack_label = wx.StaticText(self, -1, _(u"Sound pack")) - self.soundpack = wx.ComboBox(self, -1, choices=self.soundpacks, style=wx.CB_READONLY) - self.soundpack.SetValue(config.main["sound"]["current_soundpack"]) - self.soundpack.SetSize(self.soundpack.GetBestSize()) - soundBox.Add(soundpack_label, 0, wx.ALL, 5) - soundBox.Add(self.soundpack, 0, wx.ALL, 5) - sizer.Add(soundBox, 0, wx.ALL, 5) - self.SetSizer(sizer) - -class audioServicesPanel(wx.Panel): - def __init__(self, parent): - super(audioServicesPanel, self).__init__(parent) - mainSizer = wx.BoxSizer(wx.VERTICAL) - apiKeyLabel = wx.StaticText(self, -1, _(u"If you've got a SndUp account, enter your API Key here. Whether the API Key is wrong, the App will fail to upload anything to the server. Whether there's no API Key here, then the audio files will be uploaded anonimously")) - self.apiKey = wx.TextCtrl(self, -1) - self.apiKey.SetValue(config.main["sound"]["sndup_api_key"]) - dc = wx.WindowDC(self.apiKey) - dc.SetFont(self.apiKey.GetFont()) - self.apiKey.SetSize(dc.GetTextExtent("0"*100)) - apiKeyBox = wx.BoxSizer(wx.HORIZONTAL) - apiKeyBox.Add(apiKeyLabel, 0, wx.ALL, 5) - apiKeyBox.Add(self.apiKey, 0, wx.ALL, 5) - mainSizer.Add(apiKeyBox, 0, wx.ALL, 5) - first_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.dropbox = wx.Button(self, -1) - if len(config.main["services"]["dropbox_token"]) > 0: - self.dropbox.SetLabel(_(u"Unlink your Dropbox account")) - else: - self.dropbox.SetLabel(_(u"Link your Dropbox account")) - self.dropbox.Bind(wx.EVT_BUTTON, self.onLink_unlink) - first_sizer.Add(self.dropbox, 0, wx.ALL, 5) - mainSizer.Add(first_sizer, 0, wx.ALL, 5) - self.SetSizer(mainSizer) - - def setup_dropbox(self): - from extra.AudioUploader import dropbox_transfer - auth = dropbox_transfer.dropboxLogin() - url = auth.get_url() - wx.MessageDialog(self, _(u"The authorisation request will be shown on your browser. Copy the code tat Dropbox will provide and, in the text box that will appear on TW Blue, paste it. This code is necessary to continue. You only need to do it once."), _(u"Authorisation"), wx.OK).ShowModal() - webbrowser.open(url) - dlg = wx.TextEntryDialog(self, _(u"Enter the code here."), _(u"Verification code")) - if dlg.ShowModal() == wx.ID_CANCEL: - return False - resp = dlg.GetValue() - if resp == "": - self.dropbox.SetLabel(_(u"Link your Dropbox account")) - return False - else: - try: - auth.authorise(resp) - self.dropbox.SetLabel(_(u"Unlink your Dropbox account")) - except: - wx.MessageDialog(self, _(u"Error during authorisation. Try again later."), _(u"Error!"), wx.ICON_ERROR).ShowModal() - self.dropbox.SetLabel(_(u"Link your Dropbox account")) - return False - - def onLink_unlink(self, ev): - if self.dropbox.GetLabel() == _(u"Link your Dropbox account"): - self.setup_dropbox() - else: - self.disconnect_dropbox() - - def disconnect_dropbox(self): - config.main["services"]["dropbox_token"] = "" - self.dropbox.SetLabel(_(u"Link your Dropbox account")) - -class configurationDialog(wx.Dialog): - def __init__(self, parent): - self.parent = parent - wx.Dialog.__init__(self, None, -1) - panel = wx.Panel(self) - self.SetTitle(_(u"TW Blue preferences")) - sizer = wx.BoxSizer(wx.VERTICAL) - notebook = wx.Notebook(panel) - self.general = general(notebook) - notebook.AddPage(self.general, _(u"General")) - self.general.SetFocus() - self.buffers = other_buffers(notebook) - notebook.AddPage(self.buffers, _(u"Show other buffers")) - self.ignored_clients = ignoredClients(notebook) - notebook.AddPage(self.ignored_clients, _(u"Ignored clients")) - self.sound = sound(notebook) - notebook.AddPage(self.sound, _(u"Sound")) - self.services = audioServicesPanel(notebook) - notebook.AddPage(self.services, _(u"Audio Services")) - sizer.Add(notebook, 0, wx.ALL, 5) - ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL) - ok = wx.Button(panel, wx.ID_OK, _(u"Save")) - ok.Bind(wx.EVT_BUTTON, self.onSave) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - self.SetEscapeId(cancel.GetId()) - ok_cancel_box.Add(ok, 0, wx.ALL, 5) - ok_cancel_box.Add(cancel, 0, wx.ALL, 5) - sizer.Add(ok_cancel_box, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) - - def check_followers_change(self): - if self.buffers.followers.GetValue() != self.buffers.followers_value: - if self.buffers.followers.GetValue() == True: - log.debug("Creating followers list...") - followers = buffers.peoplePanel(self.parent.nb, self.parent, "followers", self.parent.twitter.twitter.get_followers_list, argumento=self.parent.db.settings["user_name"]) - self.parent.nb.InsertSubPage(self.parent.db.settings["buffers"].index(self.parent.db.settings["user_name"]), followers, _(u"Followers")) - num = followers.start_streams() - followers.put_items(num) - self.parent.db.settings["buffers"].append("followers") - elif self.buffers.followers.GetValue() == False: - self.parent.nb.DeletePage(self.parent.db.settings["buffers"].index("followers")) - self.parent.db.settings.pop("followers") - self.parent.db.settings["buffers"].remove("followers") - - def check_friends_change(self): - if self.buffers.friends.GetValue() != self.buffers.friends_value: - if self.buffers.friends.GetValue() == True: - log.debug("Creating friends list...") - friends = buffers.peoplePanel(self.parent.nb, self.parent, "friends", self.parent.twitter.twitter.get_friends_list, argumento=self.parent.db.settings["user_name"]) - self.parent.nb.InsertSubPage(self.parent.db.settings["buffers"].index(self.parent.db.settings["user_name"]), friends, _(u"friends")) - num = friends.start_streams() - friends.put_items(num) - self.parent.db.settings["buffers"].append("friends") - elif self.buffers.friends.GetValue() == False: - self.parent.nb.DeletePage(self.parent.db.settings["buffers"].index("friends")) - self.parent.db.settings.pop("friends") - self.parent.db.settings["buffers"].remove("friends") - - def check_favs_change(self): - if self.buffers.favs.GetValue() != self.buffers.favs_value: - if self.buffers.favs.GetValue() == True: - log.debug("Creating favorites...") - favs = buffers.basePanel(self.parent.nb, self.parent, "favs", self.parent.twitter.twitter.get_favorites) - self.parent.nb.InsertSubPage(self.parent.db.settings["buffers"].index(self.parent.db.settings["user_name"]), favs, _(u"Favorites")) - num = favs.start_streams() - favs.put_items(num) - self.parent.db.settings["buffers"].append("favs") - elif self.buffers.favs.GetValue() == False: - self.parent.nb.DeletePage(self.parent.db.settings["buffers"].index("favs")) - self.parent.db.settings.pop("favs") - self.parent.db.settings["buffers"].remove("favs") - - def check_events_change(self): - if self.buffers.events.GetValue() != self.buffers.events_value: - if self.buffers.events.GetValue() == True: - log.debug("Creating events...") - events = buffers.eventsPanel(self.parent.nb, self.parent) - self.parent.nb.InsertSubPage(self.parent.db.settings["buffers"].index(self.parent.db.settings["user_name"]), events, _(u"Events")) - self.parent.db.settings["buffers"].append("events") - elif self.buffers.events.GetValue() == False: - self.parent.nb.DeletePage(self.parent.db.settings["buffers"].index("events")) - self.parent.db.settings["buffers"].remove("events") - - def check_blocks_change(self): - if self.buffers.blocks.GetValue() != self.buffers.blocks_value: - if self.buffers.blocks.GetValue() == True: - log.debug("Creating blocked users list...") - blocks = buffers.peoplePanel(self.parent.nb, self.parent, "blocks", self.parent.twitter.twitter.list_blocks) - self.parent.nb.InsertSubPage(self.parent.db.settings["buffers"].index(self.parent.db.settings["user_name"]), blocks, _(u"Blocked users")) - num = blocks.start_streams() - blocks.put_items(num) - self.parent.db.settings["buffers"].append("blocks") - elif self.buffers.blocks.GetValue() == False: - self.parent.nb.DeletePage(self.parent.db.settings["buffers"].index("blocks")) - self.parent.db.settings.pop("blocks") - self.parent.db.settings["buffers"].remove("blocks") - - def check_mutes_change(self): - if self.buffers.mutes.GetValue() != self.buffers.mutes_value: - if self.buffers.mutes.GetValue() == True: - log.debug("Creating muted users list...") - mutes = buffers.peoplePanel(self.parent.nb, self.parent, "muteds", self.parent.twitter.twitter.get_muted_users_list) - self.parent.nb.InsertSubPage(self.parent.db.settings["buffers"].index(self.parent.db.settings["user_name"]), mutes, _(u"Muted users")) - num = mutes.start_streams() - mutes.put_items(num) - self.parent.db.settings["buffers"].append("muteds") - elif self.buffers.mutes.GetValue() == False: - self.parent.nb.DeletePage(self.parent.db.settings["buffers"].index("muteds")) - self.parent.db.settings.pop("muteds") - self.parent.db.settings["buffers"].remove("muteds") - - def onSave(self, ev): - need_restart = False - # Check general settings - if config.main["general"]["language"] != self.general.langs[self.general.language.GetSelection()][0]: - if self.general.langs[self.general.language.GetSelection()][0] in self.general.codes: config.main["general"]["language"] = self.general.langs[self.general.language.GetSelection()][0] - languageHandler.setLanguage(config.main["general"]["language"]) - need_restart = True - if platform.system() == "Windows": - config.main["general"]["voice_enabled"] = self.general.disable_sapi5.GetValue() - config.main["general"]["ask_at_exit"] = self.general.ask_at_exit.GetValue() - config.main["general"]["hide_gui"] = self.general.show_gui.GetValue() - config.main["general"]["max_api_calls"] = self.general.apiCalls.GetValue() - config.main["general"]["max_tweets_per_call"] = self.general.itemsPerApiCall.GetValue() - if config.main["general"]["relative_times"] != self.general.relative_time.GetValue(): - config.main["general"]["relative_times"] = self.general.relative_time.GetValue() - need_restart = True - if config.main["general"]["reverse_timelines"] != self.general.reverse_timelines.GetValue(): - config.main["general"]["reverse_timelines"] = self.general.reverse_timelines.GetValue() - need_restart = True - - ## Check buffers settings - config.main["other_buffers"]["show_followers"] = self.buffers.followers.GetValue() - self.check_followers_change() - config.main["other_buffers"]["show_friends"] = self.buffers.friends.GetValue() - self.check_friends_change() - config.main["other_buffers"]["show_favourites"] = self.buffers.favs.GetValue() - self.check_favs_change() - config.main["other_buffers"]["show_events"] = self.buffers.events.GetValue() - self.check_events_change() - config.main["other_buffers"]["show_blocks"] = self.buffers.blocks.GetValue() - self.check_blocks_change() - config.main["other_buffers"]["show_muted_users"] = self.buffers.mutes.GetValue() - self.check_mutes_change() - - ## Check sound settings - config.main["sound"]["volume"] = self.sound.volumeCtrl.GetValue()/100.0 - config.main["sound"]["global_mute"] = self.sound.global_mute.GetValue() - if system == "Windows": - config.main["sound"]["output_device"] = self.sound.output.GetStringSelection() - config.main["sound"]["input_device"] = self.sound.input.GetValue() - try: - snd.player.input.set_device(snd.player.input.find_device_by_name(config.main["sound"]["input_device"])) - snd.player.output.set_device(snd.player.output.find_device_by_name(config.main["sound"]["output_device"])) - except: - config.main["sound"]["output_device"] = "Default" - config.main["sound"]["input_device"] = "Default" - config.main["sound"]["sndup_api_key"] = self.services.apiKey.GetValue() - config.main["sound"]["current_soundpack"] = self.sound.soundpack.GetStringSelection() - snd.player.check_soundpack() - if need_restart == True: - config.main.write() - wx.MessageDialog(None, _(u"The application requires to be restarted to save these changes. Press OK to do it now."), _("Restart TW Blue"), wx.OK).ShowModal() - restart.restart_program() - - config.main.write() - self.EndModal(wx.ID_OK) diff --git a/src/gui/dialogs/follow.py b/src/gui/dialogs/follow.py deleted file mode 100644 index e5f2a9a6..00000000 --- a/src/gui/dialogs/follow.py +++ /dev/null @@ -1,151 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import config -from mysc import event -import twitter -from twitter import utils -from twython import TwythonError -import output - -class follow(wx.Dialog): - def __init__(self, parent, default="follow"): - self.parent = parent - wx.Dialog.__init__(self, None, -1) - panel = wx.Panel(self) - userSizer = wx.BoxSizer() - self.SetTitle(_(u"Action")) - if self.parent.name_buffer == "followers" or self.parent.name_buffer == "friends": - list = [self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()]["screen_name"]] - else: - try: list =twitter.utils.get_all_users(self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()], self.parent.db) - except KeyError: list = [self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()]["screen_name"]] - self.cb = wx.ComboBox(panel, -1, choices=list, value=list[0]) - self.cb.SetFocus() - userSizer.Add(self.cb) - actionSizer = wx.BoxSizer(wx.VERTICAL) - label2 = wx.StaticText(panel, -1, _(u"Action")) - self.follow = wx.RadioButton(panel, -1, _(u"Follow"), style=wx.RB_GROUP) - self.unfollow = wx.RadioButton(panel, -1, _(u"Unfollow")) - self.mute = wx.RadioButton(panel, -1, _(u"Mute")) - self.unmute = wx.RadioButton(panel, -1, _(u"Unmute")) - self.block = wx.RadioButton(panel, -1, _(u"Block")) - self.unblock = wx.RadioButton(panel, -1, _(u"Unblock")) - self.reportSpam = wx.RadioButton(panel, -1, _(u"Report as spam")) - self.setup_default(default) - actionSizer.Add(label2) - actionSizer.Add(self.follow) - actionSizer.Add(self.unfollow) - actionSizer.Add(self.mute) - actionSizer.Add(self.unmute) - actionSizer.Add(self.block) - actionSizer.Add(self.unblock) - actionSizer.Add(self.reportSpam) - sizer = wx.BoxSizer(wx.VERTICAL) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.Bind(wx.EVT_BUTTON, self.onok) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok) - btnsizer.Add(cancel) - sizer.Add(userSizer) - sizer.Add(actionSizer) - sizer.Add(btnsizer) - panel.SetSizer(sizer) - self.Bind(wx.EVT_CHAR_HOOK, self.onEscape, self.cb) - - def onEscape(self, ev): - if ev.GetKeyCode() == wx.WXK_RETURN: - self.onok(wx.EVT_BUTTON) - ev.Skip() - - def onok(self, ev): - if self.follow.GetValue() == True: - try: - self.parent.twitter.twitter.create_friendship(screen_name=self.cb.GetValue()) - self.Destroy() - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - elif self.unfollow.GetValue() == True: - try: - id = self.parent.twitter.twitter.destroy_friendship(screen_name=self.cb.GetValue()) - self.Destroy() - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - elif self.mute.GetValue() == True: - try: - id = self.parent.twitter.twitter.create_mute(screen_name=self.cb.GetValue()) - if config.main["other_buffers"]["show_muted_users"] == True: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(id) - wx.PostEvent(self.parent.parent.nb.GetPage(self.parent.db.settings["buffers"].index("muteds")), tweet_event) - self.parent.db.settings["muted_users"].append(id["id"]) - self.Destroy() - output.speak(_(u"You've muted to %s") % (id["screen_name"])) - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - elif self.unmute.GetValue() == True: - try: - id = self.parent.twitter.twitter.destroy_mute(screen_name=self.cb.GetValue()) - if config.main["other_buffers"]["show_muted_users"] == True: - item = utils.find_item(id, self.parent.db.settings["muteds"]) - if item > 0: - deleted_event = event.event(event.EVT_DELETED, 1) - deleted_event.SetItem(item) - wx.PostEvent(self.parent.parent.nb.GetPage(self.parent.db.settings["buffers"].index("muteds")), deleted_event) - if id["id"] in self.parent.db.settings["muted_users"]: self.parent.db.settings["muted_users"].remove(id["id"]) - self.Destroy() - output.speak(_(u"You've unmuted to %s") % (id["screen_name"])) - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - elif self.reportSpam.GetValue() == True: - try: - self.parent.twitter.twitter.report_spam(screen_name=self.cb.GetValue()) - self.Destroy() - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - elif self.block.GetValue() == True: - try: - self.parent.twitter.twitter.create_block(screen_name=self.cb.GetValue()) - self.Destroy() - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - elif self.unblock.GetValue() == True: - try: - self.parent.twitter.twitter.destroy_block(screen_name=self.cb.GetValue()) - self.Destroy() - except TwythonError as err: - output.speak("Error %s: %s" % (err.error_code, err.msg), True) - - def setup_default(self, default): - if default == "follow": - self.follow.SetValue(True) - elif default == "unfollow": - self.unfollow.SetValue(True) - elif default == "mute": - self.mute.SetValue(True) - elif default == "unmute": - self.unmute.SetValue(True) - elif default == "report": - self.reportSpam.SetValue(True) - elif default == "block": - self.block.SetValue(True) - elif default == "unblock": - self.unblock.SetValue(True) \ No newline at end of file diff --git a/src/gui/dialogs/lists.py b/src/gui/dialogs/lists.py deleted file mode 100644 index 0b3e3e94..00000000 --- a/src/gui/dialogs/lists.py +++ /dev/null @@ -1,244 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import platform -import output -import config -import gui -from multiplatform_widgets import widgets -from twython import TwythonError -from twitter import compose, utils - -class listViewer(wx.Dialog): - - def __init__(self, parent): - self.twitter = parent.twitter - self.db = parent.db - self.nb = parent.nb - self.parent = parent - wx.Dialog.__init__(self, None) - self.SetTitle(_(u"Lists manager")) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Lists")) - self.lista = widgets.list(panel, _(u"List"), _(u"Description"), _(u"Owner"), _(u"Members"), _(u"mode"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) - self.lista.list.SetFocus() - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(label) - sizer.Add(self.lista.list) - self.createBtn = wx.Button(panel, wx.NewId(), _(u"Create a new list")) - self.createBtn.Bind(wx.EVT_BUTTON, self.onGo) - self.editBtn = wx.Button(panel, -1, _(u"Edit")) - self.Bind(wx.EVT_BUTTON, self.onEdit, self.editBtn) - self.deleteBtn = wx.Button(panel, -1, _(u"Remove")) - self.Bind(wx.EVT_BUTTON, self.onDelete, self.deleteBtn) - self.view = wx.Button(panel, -1, _(u"Open in buffer")) - self.Bind(wx.EVT_BUTTON, self.onView, self.view) -# self.members = wx.Button(panel, -1, _(u"View members")) -# self.members.Disable() -# self.subscriptors = wx.Button(panel, -1, _(u"View subscribers")) -# self.subscriptors.Disable() -# self.get_linkBtn = wx.Button(panel, -1, _(u"Get link for the list")) -# self.get_linkBtn.Bind(wx.EVT_BUTTON, self.onGetLink) - self.cancelBtn = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(self.createBtn) - btnSizer.Add(self.editBtn) - btnSizer.Add(self.cancelBtn) - panel.SetSizer(sizer) - self.populate_list() - self.lista.select_item(0) - - def onGo(self, ev): - ev.Skip() - dlg = createListDialog() - if dlg.ShowModal() == wx.ID_OK: - name = dlg.name.GetValue() - description = dlg.description.GetValue() - if dlg.public.GetValue() == True: mode = "public" - else: mode = "private" - try: - new_list = self.twitter.twitter.create_list(name=name, description=description, mode=mode) - self.db.settings["lists"].append(new_list) - self.lista.insert_item(False, *compose.compose_list(new_list)) - except TwythonError as e: - output.speak("error %s: %s" % (e.status_code, e.msg)) - else: - return - dlg.Destroy() - - def onEdit(self, ev): - ev.Skip() - if self.lista.get_count() == 0: return - list = self.db.settings["lists"][self.lista.get_selected()] - dlg = editListDialog(list) - if dlg.ShowModal() == wx.ID_OK: - name = dlg.name.GetValue() - description = dlg.description.GetValue() - if dlg.public.GetValue() == True: mode = "public" - else: mode = "private" - try: - self.twitter.twitter.update_list(list_id=self.lists[self.get_selected()]["id"], name=name, description=description, mode=mode) - except TwythonError as e: - output.speak("error %s: %s" % (e.error_code, e.msg)) - else: - return - dlg.Destroy() - - def onDelete(self, ev): - ev.Skip() - if self.lista.get_count() == 0: return - list = self.db.settings["lists"][self.lista.get_selected()]["id"] - dlg = wx.MessageDialog(self, _("Do you really want to delete this list?"), _("Delete"), wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - try: - self.twitter.twitter.delete_list(list_id=list) - self.db.settings["lists"].pop(self.lista.get_selected()) - self.remove_item(self.lista.get_selected()) - except TwythonError as e: - output.speak("error %s: %s" % (e.error_code, e.msg)) - dlg.Destroy() - - def onView(self, ev): - ev.Skip() - if self.lista.get_count() == 0: return - list_id = self.db.settings["lists"][self.lista.get_selected()]["id"] - list_updated = self.twitter.twitter.get_specific_list(list_id=list_id) - self.db.settings["lists"][self.lista.get_selected()] = list_updated - if list_updated["slug"] not in config.main["other_buffers"]["lists"]: - config.main["other_buffers"]["lists"].append(list_updated["slug"]) - output.speak(_(u"List opened")) - else: - output.speak(_(u"This list is arready opened.")) - return - listUI = gui.buffers.lists.listPanel(self.nb, self.parent, list_updated["slug"]+"-list", argumento=utils.find_list(list_updated["slug"], self.db.settings["lists"])) - self.nb.AddPage(listUI, _(u"List for %s") % (list_updated["slug"],)) - self.db.settings["buffers"].append(list_updated["slug"]+"-list") - num = listUI.start_streams() - listUI.put_items(num) - listUI.sound = "tweet_timeline.wav" - self.parent.stream2.disconnect() - del self.parent.stream2 - self.parent.get_tls() - - def populate_list(self): - for i in self.db.settings["lists"]: - item = compose.compose_list(i) - self.lista.insert_item(False, *item) - -class userListViewer(listViewer): - def __init__(self, parent, username): - self.username = username - super(userListViewer, self).__init__(parent) - self.SetTitle(_(u"Viewing lists for %s") % (self.username)) - self.createBtn.SetLabel(_(u"Subscribe")) - self.deleteBtn.SetLabel(_(u"Unsubscribe")) - self.editBtn.Disable() - self.view.Disable() - - def populate_list(self): - self.lists = self.twitter.twitter.show_owned_lists(screen_name=self.username, count=200)["lists"] - for i in self.lists: - item = compose.compose_list(i) - self.lista.insert_item(False, *item) - - def onGo(self, ev): - list_id = self.lists[self.lista.get_selected()]["id"] - try: - list = self.twitter.twitter.subscribe_to_list(list_id=list_id) - item = utils.find_item(list["id"], self.db.settings["lists"]) - self.db.settings["lists"].append(list) - except TwythonError as e: - output.speak("error %s: %s" % (e.status_code, e.msg)) - -class createListDialog(wx.Dialog): - - def __init__(self): - wx.Dialog.__init__(self, None, size=(450, 400)) - self.SetTitle(_(u"Create a new list")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - name = wx.StaticText(panel, -1, _(u"Name (20 characters maximun)")) - self.name = wx.TextCtrl(panel, -1) - nameSizer = wx.BoxSizer(wx.HORIZONTAL) - nameSizer.Add(name) - nameSizer.Add(self.name) - description = wx.StaticText(panel, -1, _(u"Description")) - self.description = wx.TextCtrl(panel, -1) - descriptionSizer = wx.BoxSizer(wx.HORIZONTAL) - descriptionSizer.Add(description) - descriptionSizer.Add(self.description) - mode = wx.StaticText(panel, -1, _(u"Mode")) - self.public = wx.RadioButton(panel, -1, _(u"Public"), style=wx.RB_GROUP) - self.private = wx.RadioButton(panel, -1, _(u"Private")) - modeBox = wx.BoxSizer(wx.HORIZONTAL) - modeBox.Add(mode) - modeBox.Add(self.public) - modeBox.Add(self.private) - ok = wx.Button(panel, wx.ID_OK) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(ok) - btnBox.Add(cancel) - sizer.Add(nameSizer) - sizer.Add(descriptionSizer) - sizer.Add(modeBox) - sizer.Add(btnBox) - -class editListDialog(createListDialog): - - def __init__(self, list): - createListDialog.__init__(self) - self.SetTitle(_(u"Editing the list %s") % (list["name"])) - self.name.ChangeValue(list["name"]) - self.description.ChangeValue(list["description"]) - if list["mode"] == "public": - self.public.SetValue(True) - else: - self.private.SetValue(True) - -class addUserListDialog(listViewer): - def __init__(self, parent): - listViewer.__init__(self, parent) - self.SetTitle(_(u"Select a list to add the user")) - self.createBtn.SetLabel(_(u"Add")) - self.createBtn.SetDefault() - self.editBtn.Disable() - self.view.Disable() -# self.subscriptors.Disable() -# self.members.Disable() - self.deleteBtn.Disable() - - def onGo(self, ev): - self.EndModal(wx.ID_OK) - -class removeUserListDialog(listViewer): - def __init__(self, parent): - listViewer.__init__(self, parent) - self.SetTitle(_(u"Select a list to remove the user")) - self.createBtn.SetLabel(_(u"Remove")) - self.createBtn.SetDefault() - self.editBtn.Disable() - self.view.Disable() -# self.subscriptors.Disable() -# self.members.Disable() - self.deleteBtn.Disable() - - def onGo(self, ev): - self.EndModal(wx.ID_OK) \ No newline at end of file diff --git a/src/gui/dialogs/message.py b/src/gui/dialogs/message.py deleted file mode 100644 index 894814bd..00000000 --- a/src/gui/dialogs/message.py +++ /dev/null @@ -1,419 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import twitter -import config -import output -import sound -import urlList -import url_shortener -import json -from mysc.thread_utils import call_threaded -from mysc.repeating_timer import RepeatingTimer -from twython import TwythonError -from extra import translator, AudioUploader -import platform -from extra.AudioUploader import transfer -if platform.system() != "Darwin": - from extra.AudioUploader import dropbox_transfer - from extra.SpellChecker import gui as spellCheckerGUI - -class textLimited(wx.Dialog): - def __init__(self, message, title, text, parent): - wx.Dialog.__init__(self, parent) - self.twitter = parent.twitter - self.parent = parent - self.title = title - self.SetTitle(_(u"%s - %s of 140 characters") % (self.title, str(len(text)))) - self.panel = wx.Panel(self) - - def createTextArea(self, message, text): - self.label = wx.StaticText(self.panel, -1, message) - self.text = wx.TextCtrl(self.panel, -1, text) - font = self.text.GetFont() - dc = wx.WindowDC(self.text) - dc.SetFont(font) - x, y = dc.GetTextExtent("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - self.text.SetSize((x, y)) - self.text.SetFocus() - if platform.system() != "Darwin": - self.text.Bind(wx.EVT_TEXT, self.onTimer) - self.textBox = wx.BoxSizer(wx.HORIZONTAL) - self.textBox.Add(self.label, 0, wx.ALL, 5) - self.textBox.Add(self.text, 0, wx.ALL, 5) - - def onCheck(self, ev): - if platform.system() == "Darwin": - return - text = self.text.GetValue() - dlg = spellCheckerGUI.spellCheckerDialog(text, "") - if dlg.ShowModal() == wx.ID_OK: - self.text.ChangeValue(dlg.checker.get_text()) - dlg.Destroy() - - def onAttach(self, ev): - ev.Skip() - self.recording = AudioUploader.gui.audioDialog(self.parent) - if self.recording.ShowModal() != wx.ID_OK: - self.recording.cleanup() - return - self.recording.postprocess() - output.speak(_(u"Attaching...")) - self.uploaderDialog = AudioUploader.transfer_dialogs.UploadDialog(parent=self.parent, title=_(u"Uploading..."), filename=self.recording.file) - if self.recording.services.GetValue() == "Dropbox" and platform.system() != "Darwin": - self.uploader = dropbox_transfer.dropboxUploader(filename=self.recording.file, completed_callback=self.upload_completed, wxDialog=self.uploaderDialog) - elif self.recording.services.GetValue() == "SNDUp": - base_url = 'http://sndup.net/post.php' - if len(config.main["sound"]["sndup_api_key"]) > 0: - url = base_url + '?apikey=' + config.main['sound']['sndup_api_key'] - else: - url = base_url - self.uploader = transfer.Upload(field='file', url=url, filename=self.recording.file, completed_callback=self.upload_completed, wxDialog=self.uploaderDialog) - elif self.recording.services.GetValue() == "TwUp": - url = 'http://api.twup.me/post.json' - self.uploader = transfer.Upload(field='file', url=url, filename=self.recording.file, completed_callback=self.upload_completed, wxDialog=self.uploaderDialog) - self.uploaderDialog.Show() - self.uploader.perform_threaded() - - def upload_completed(self): - url = self.uploader.get_url() - self.uploaderDialog.Destroy() - if url != 0: - self.text.SetValue(self.text.GetValue()+url+" #audio") - else: - output.speak(_(u"Unable to upload the audio")) - - def onTranslate(self, ev): - dlg = translator.gui.translateDialog() - selection = dlg.ShowModal() - if selection != wx.ID_CANCEL: - text_to_translate = self.text.GetValue().encode("utf-8") - source = [x[0] for x in translator.available_languages()][dlg.source_lang.GetSelection()] - dest = [x[0] for x in translator.available_languages()][dlg.dest_lang.GetSelection()] - t = translator.translator.Translator() - t.from_lang = source - t.to_lang = dest - msg = t.translate(text_to_translate) - self.text.ChangeValue(msg) - output.speak(_(u"Translated")) - self.text.SetFocus() - else: - return - dlg.Destroy() - - def onSelect(self, ev): - self.text.SelectAll() - - def onShorten(self, ev): - urls = twitter.utils.find_urls_in_text(self.text.GetValue()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be shortened")) - elif len(urls) == 1: - self.text.SetValue(self.text.GetValue().replace(urls[0], url_shortener.shorten(urls[0]))) - output.speak(_(u"URL shortened")) - elif len(urls) > 1: - urlList.shorten(urls, self).ShowModal() - self.text.SetFocus() - - def onUnshorten(self, ev): - urls = twitter.utils.find_urls_in_text(self.text.GetValue()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be expanded")) - elif len(urls) == 1: - self.text.SetValue(self.text.GetValue().replace(urls[0], url_shortener.unshorten(urls[0]))) - output.speak(_(u"URL expanded")) - elif len(urls) > 1: - urlList.unshorten(urls, self).ShowModal() - self.text.SetFocus() - - def onTimer(self, ev): - self.SetTitle(_(u"%s - %s of 140 characters") % (self.title, str(len(self.text.GetValue())))) - if len(self.text.GetValue()) > 1: - self.shortenButton.Enable() - self.unshortenButton.Enable() - else: - self.shortenButton.Disable() - self.unshortenButton.Disable() - if len(self.text.GetValue()) > 140: - sound.player.play("max_length.ogg") - self.okButton.Disable() - elif len(self.text.GetValue()) <= 140: - self.okButton.Enable() - - def onCancel(self, ev): - self.Destroy() - - -class tweet(textLimited): - def createControls(self, message, title, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, text) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.upload_image = wx.Button(self.panel, -1, _(u"Upload a picture"), size=wx.DefaultSize) - self.upload_image.Bind(wx.EVT_BUTTON, self.onUpload_image) - if platform.system() != "Darwin": - self.spellcheck = wx.Button(self.panel, -1, _("Spelling correction"), size=wx.DefaultSize) - self.spellcheck.Bind(wx.EVT_BUTTON, self.onCheck) - self.attach = wx.Button(self.panel, -1, _(u"Attach audio"), size=wx.DefaultSize) - self.attach.Bind(wx.EVT_BUTTON, self.onAttach) - self.shortenButton = wx.Button(self.panel, -1, _(u"Shorten URL"), size=wx.DefaultSize) - self.shortenButton.Bind(wx.EVT_BUTTON, self.onShorten) - self.unshortenButton = wx.Button(self.panel, -1, _(u"Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Bind(wx.EVT_BUTTON, self.onUnshorten) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"Translate message"), size=wx.DefaultSize) - self.translateButton.Bind(wx.EVT_BUTTON, self.onTranslate) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Send"), size=wx.DefaultSize) - self.okButton.Bind(wx.EVT_BUTTON, self.onSend) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize) - cancelButton.Bind(wx.EVT_BUTTON, self.onCancel) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 5) - if platform.system() != "Darwin": - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 5) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 5) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 5) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 5) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 5) - self.mainBox.Add(self.ok_cancelSizer) - selectId = wx.NewId() - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) - - def __init__(self, message, title, text, parent): - super(tweet, self).__init__(message, title, text, parent) - self.image = None - self.createControls(message, title, text) - self.onTimer(wx.EVT_CHAR_HOOK) - self.SetClientSize(self.mainBox.CalcMin()) - - def onUpload_image(self, ev): - if self.upload_image.GetLabel() == _(u"Discard image"): - self.image = None - del self.file - output.speak(_(u"Discarded")) - self.upload_image.SetLabel(_(u"Upload a picture")) - else: - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return - self.file = open(openFileDialog.GetPath(), "rb") - self.image = True - self.upload_image.SetLabel(_(u"Discard image")) - ev.Skip() - - def onSend(self, ev): - self.EndModal(wx.ID_OK) - -class retweet(tweet): - def __init__(self, message, title, text, parent): - super(retweet, self).__init__(message, title, text, parent) -# self.createControls(message, title, text) - self.in_reply_to = parent.db.settings[parent.name_buffer][parent.list.get_selected()]["id"] - self.text.SetInsertionPoint(0) - - def onSend(self, ev): - self.EndModal(wx.ID_OK) - -class dm(textLimited): - def createControls(self, message, title, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - if self.parent.name_buffer == "followers" or self.parent.name_buffer == "friends": - list = [self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()]["screen_name"]] - else: - list =twitter.utils.get_all_users(self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()], self.parent.db) - label = wx.StaticText(self.panel, -1, _(u"Recipient")) - self.cb = wx.ComboBox(self.panel, -1, choices=list, value=list[0], size=wx.DefaultSize) - self.createTextArea(message, text) - self.mainBox.Add(self.cb, 0, wx.ALL, 5) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - if platform.system() != "Darwin": - self.spellcheck = wx.Button(self.panel, -1, _("Spelling correction"), size=wx.DefaultSize) - self.spellcheck.Bind(wx.EVT_BUTTON, self.onCheck) - self.attach = wx.Button(self.panel, -1, _(u"Attach audio"), size=wx.DefaultSize) - self.attach.Bind(wx.EVT_BUTTON, self.onAttach) - self.shortenButton = wx.Button(self.panel, -1, _(u"Shorten URL"), size=wx.DefaultSize) - self.shortenButton.Bind(wx.EVT_BUTTON, self.onShorten) - self.unshortenButton = wx.Button(self.panel, -1, _(u"Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Bind(wx.EVT_BUTTON, self.onUnshorten) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"Translate message"), size=wx.DefaultSize) - self.translateButton.Bind(wx.EVT_BUTTON, self.onTranslate) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Send"), size=wx.DefaultSize) - self.okButton.Bind(wx.EVT_BUTTON, self.onSend) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize) - cancelButton.Bind(wx.EVT_BUTTON, self.onCancel) - self.buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - if platform.system() != "Darwin": - self.buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - self.buttonsBox.Add(self.attach, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox, 0, wx.ALL, 5) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.shortenButton, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.unshortenButton, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) - self.buttonsBox3 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox3.Add(self.okButton, 0, wx.ALL, 5) - self.buttonsBox3.Add(cancelButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox3, 0, wx.ALL, 5) - self.panel.SetSizer(self.mainBox) - - def __init__(self, message, title, text, parent): - super(dm, self).__init__(message, title, text, parent) - self.parent = parent - self.image = None - self.createControls(message, title, text) - self.onTimer(wx.EVT_CHAR_HOOK) - self.SetClientSize(self.mainBox.CalcMin()) - - def onSend(self, ev): - self.EndModal(wx.ID_OK) - -class reply(tweet): - def __init__(self, message, title, text, parent): - super(reply, self).__init__(message, title, text, parent) - self.in_reply_to = parent.db.settings[parent.name_buffer][parent.list.get_selected()]["id"] - self.text.SetInsertionPoint(len(self.text.GetValue())) - self.mentionAll = wx.Button(self, -1, _(u"Mention to all"), size=wx.DefaultSize) - self.mentionAll.Disable() - self.mentionAll.Bind(wx.EVT_BUTTON, self.mentionAllUsers) - self.buttonsBox1.Add(self.mentionAll, 0, wx.ALL, 5) - self.buttonsBox1.Layout() - self.mainBox.Layout() - self.check_if_users() - self.SetClientSize(self.mainBox.CalcMin()) - - def check_if_users(self): - try: - if len(self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()]["entities"]["user_mentions"]) > 0: - self.mentionAll.Enable() - except KeyError: - pass - - def mentionAllUsers(self, ev): - self.text.SetValue(self.text.GetValue()+twitter.utils.get_all_mentioned(self.parent.db.settings[self.parent.name_buffer][self.parent.list.get_selected()], self.parent.db)) - self.text.SetInsertionPoint(len(self.text.GetValue())) - self.text.SetFocus() - - def onSend(self, ev): - self.EndModal(wx.ID_OK) - -class viewTweet(wx.Dialog): - def __init__(self, tweet): - super(viewTweet, self).__init__(None, size=(850,850)) - self.SetTitle(_(u"Tweet - %i characters ") % (len(tweet))) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Tweet")) - self.text = wx.TextCtrl(panel, -1, tweet, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.text) - dc.SetFont(self.text.GetFont()) - (x, y, z) = dc.GetMultiLineTextExtent("0"*140) - self.text.SetSize((x, y)) - self.text.SetFocus() - textBox = wx.BoxSizer(wx.HORIZONTAL) - textBox.Add(label, 0, wx.ALL, 5) - textBox.Add(self.text, 1, wx.EXPAND, 5) - mainBox = wx.BoxSizer(wx.VERTICAL) - mainBox.Add(textBox, 0, wx.ALL, 5) - if platform.system() != "Darwin": - spellcheck = wx.Button(panel, -1, _("Spelling correction"), size=wx.DefaultSize) - spellcheck.Bind(wx.EVT_BUTTON, self.onCheck) - self.unshortenButton = wx.Button(panel, -1, _(u"Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Bind(wx.EVT_BUTTON, self.onUnshorten) - self.unshortenButton.Disable() - translateButton = wx.Button(panel, -1, _(u"Translate message"), size=wx.DefaultSize) - translateButton.Bind(wx.EVT_BUTTON, self.onTranslate) - cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize) - cancelButton.SetDefault() - buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - if platform.system() != "Darwin": - buttonsBox.Add(spellcheck, 0, wx.ALL, 5) - buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) - buttonsBox.Add(translateButton, 0, wx.ALL, 5) - buttonsBox.Add(cancelButton, 0, wx.ALL, 5) - mainBox.Add(buttonsBox, 0, wx.ALL, 5) - selectId = wx.NewId() - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - panel.SetSizer(mainBox) - self.check_urls() - self.SetClientSize(mainBox.CalcMin()) - - def check_urls(self): - if len(twitter.utils.find_urls_in_text(self.text.GetValue())) > 0: - self.unshortenButton.Enable() - - def onCheck(self, ev): - if platform.system() != "Darwin": return - text = self.text.GetValue() - dlg = spellCheckerGUI.spellCheckerDialog(text, "") - if dlg.ShowModal() == wx.ID_OK: - self.text.ChangeValue(dlg.checker.get_text()) - dlg.Destroy() - - def onTranslate(self, ev): - dlg = translator.gui.translateDialog() - selection = dlg.ShowModal() - if selection != wx.ID_CANCEL: - text_to_translate = self.text.GetValue().encode("utf-8") - source = [x[0] for x in translator.available_languages()][dlg.source_lang.GetSelection()] - dest = [x[0] for x in translator.available_languages()][dlg.dest_lang.GetSelection()] - t = translator.translator.Translator() - t.from_lang = source - t.to_lang = dest - msg = t.translate(text_to_translate) - self.text.ChangeValue(msg) - output.speak(_(u"Translated")) - self.text.SetFocus() - else: - return - dlg.Destroy() - - def onSelect(self, ev): - self.text.SelectAll() - - def onUnshorten(self, ev): - urls = twitter.utils.find_urls_in_text(self.text.GetValue()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be expanded")) - elif len(urls) == 1: - self.text.SetValue(self.text.GetValue().replace(urls[0], url_shortener.unshorten(urls[0]))) - output.speak(_(u"URL expanded")) - elif len(urls) > 1: - urlList.unshorten(urls, self).ShowModal() - self.text.SetFocus() - diff --git a/src/gui/dialogs/show_user.py b/src/gui/dialogs/show_user.py deleted file mode 100644 index cea5b35b..00000000 --- a/src/gui/dialogs/show_user.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx, twitter, config, gui.dialogs, sound, webbrowser - -class showUserProfile(wx.Dialog): - def __init__(self, twitter, screen_name): - self.twitter = twitter - self.screen_name = screen_name - wx.Dialog.__init__(self, None, -1) - self.SetTitle(_(u"Information for %s") % (screen_name)) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.get_data() - static = wx.StaticText(panel, -1, _(u"Details")) - sizer.Add(static, 0, wx.ALL, 5) - text = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY) -# dc = wx.WindowDC(text) -# dc.SetFont(text.GetFont()) -# (x, y, z) = dc.GetMultiLineTextExtent("0"*10000) -# text.SetSize((x, y)) - text.SetFocus() - sizer.Add(text, 0, wx.ALL|wx.EXPAND, 5) - self.url = wx.Button(panel, -1, _(u"Go to URL"), size=wx.DefaultSize) - self.url.Bind(wx.EVT_BUTTON, self.onUrl) - self.url.Disable() - close = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - close.Bind(wx.EVT_BUTTON, self.onClose) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer.Add(self.url, 0, wx.ALL, 5) - btnSizer.Add(close, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - text.ChangeValue(self.compose_string()) - text.SetSize(text.GetBestSize()) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) - - def onUrl(self, ev): - webbrowser.open(self.data["url"]) - - def onClose(self, ev): - self.Destroy() - - def get_data(self): - try: - self.data = self.twitter.twitter.show_user(screen_name=self.screen_name) - except: - wx.MessageDialog(self, _(u"This user does not exist on Twitter"), _(u"Error"), wx.ICON_ERROR).ShowModal() - self.EndModal() - - def compose_string(self): - string = u"" - string = string + _(u"Username: @%s\n") % (self.data["screen_name"]) - string = string + _(u"Name: %s\n") % (self.data["name"]) - if self.data["location"] != "": - string = string + _(u"Location: %s\n") % (self.data["location"]) - if self.data["url"] != None: - string = string+ _(u"URL: %s\n") % (self.data["url"]) - self.url.Enable() - if self.data["description"] != "": - string = string+ _(u"Bio: %s\n") % (self.data["description"]) - if self.data["protected"] == True: protected = _(u"Yes") - else: protected = _(u"No") - string = string+ _(u"Protected: %s\n") % (protected) - string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data["followers_count"], self.data["friends_count"]) - string = string+ _(u"Tweets: %s\n") % (self.data["statuses_count"]) - string = string+ _(u"Favourites: %s") % (self.data["favourites_count"]) - return string \ No newline at end of file diff --git a/src/gui/dialogs/trending.py b/src/gui/dialogs/trending.py deleted file mode 100644 index 157ac85d..00000000 --- a/src/gui/dialogs/trending.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx - -class trendingTopicsDialog(wx.Dialog): - def __init__(self): - super(searchDialog, self).__init__(None, -1) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle(_(u"Search on Twitter")) - label = wx.StaticText(panel, -1, _(u"Search")) - self.term = wx.TextCtrl(panel, -1,) - dc = wx.WindowDC(self.term) - dc.SetFont(self.term.GetFont()) - self.term.SetSize(dc.GetTextExtent("0"*40)) - sizer.Add(label, 0, wx.ALL, 5) - sizer.Add(self.term, 0, wx.ALL, 5) - self.tweets = wx.RadioButton(panel, -1, _(u"Tweets"), style=wx.RB_GROUP) - self.users = wx.RadioButton(panel, -1, _(u"Users")) - radioSizer = wx.BoxSizer(wx.HORIZONTAL) - radioSizer.Add(self.tweets, 0, wx.ALL, 5) - radioSizer.Add(self.users, 0, wx.ALL, 5) - sizer.Add(radioSizer, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) diff --git a/src/gui/dialogs/urlList.py b/src/gui/dialogs/urlList.py deleted file mode 100644 index 65aac035..00000000 --- a/src/gui/dialogs/urlList.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import webbrowser -import url_shortener - -class urlList(wx.Dialog): - def __init__(self, urls): - self.urls = urls - super(urlList, self).__init__(parent=None, title=_(u"Select an URL")) - panel = wx.Panel(self) -# label = wx.StaticText(panel, -1, _(u"Select a URL")) - self.lista = wx.ListBox(panel, -1) - self.lista.SetFocus() - self.populate_list() - self.lista.SetSelection(0) - self.lista.SetSize(self.lista.GetBestSize()) - sizer = wx.BoxSizer(wx.VERTICAL) -# sizer.Add(label, 0, wx.ALL, 5) - sizer.Add(self.lista, 0, wx.ALL, 5) - goBtn = wx.Button(panel, wx.ID_OK) - goBtn.SetDefault() - goBtn.Bind(wx.EVT_BUTTON, self.onGo) - cancelBtn = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(goBtn, 0, wx.ALL, 5) - btnSizer.Add(cancelBtn, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) - - def onGo(self, ev): - webbrowser.open(self.lista.GetStringSelection()) - self.Destroy() - - def populate_list(self): - for i in self.urls: - self.lista.Append(i) - -class shorten(urlList): - def __init__(self, urls, parent): - urlList.__init__(self, urls) - self.parent = parent - - def onGo(self, ev): - self.parent.text.SetValue(self.parent.text.GetValue().replace(self.lista.GetStringSelection(), url_shortener.shorten(self.lista.GetStringSelection()))) - self.Destroy() - -class unshorten(shorten): - def __init__(self, urls, parent): - shorten.__init__(self, urls, parent) - - def onGo(self, ev): - self.parent.text.SetValue(self.parent.text.GetValue().replace(self.lista.GetStringSelection(), url_shortener.unshorten(self.lista.GetStringSelection()))) - self.Destroy() \ No newline at end of file diff --git a/src/gui/dialogs/utils.py b/src/gui/dialogs/utils.py deleted file mode 100644 index 1f033cb8..00000000 --- a/src/gui/dialogs/utils.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx, twitter, gui.dialogs, sound, config -from mysc.repeating_timer import RepeatingTimer - -class selectUserDialog(wx.Dialog): - def __init__(self, parent, title): - self.parent = parent - wx.Dialog.__init__(self, None, -1) - panel = wx.Panel(self) - userSizer = wx.BoxSizer() - self.SetTitle(title) - if self.parent.nb.GetCurrentPage().name_buffer == "followers" or self.parent.nb.GetCurrentPage().name_buffer == "friends": - list = [self.parent.db.settings[self.parent.nb.GetCurrentPage().name_buffer][self.parent.nb.GetCurrentPage().list.get_selected()]["screen_name"]] - else: - try: list =twitter.utils.get_all_users(self.parent.db.settings[self.parent.nb.GetCurrentPage().name_buffer][self.parent.nb.GetCurrentPage().list.get_selected()], self.parent.db) - except KeyError: list = [self.parent.db.settings[self.parent.nb.GetCurrentPage().name_buffer][self.parent.nb.GetCurrentPage().list.get_selected()]["screen_name"]] - self.cb = wx.ComboBox(panel, -1, choices=list, value=list[0], size=wx.DefaultSize) - self.cb.SetFocus() - userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) - userSizer.Add(self.cb) - sizer = wx.BoxSizer(wx.VERTICAL) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() -# ok.Bind(wx.EVT_BUTTON, self.onok) - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(userSizer, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) \ No newline at end of file diff --git a/src/gui/main.py b/src/gui/main.py deleted file mode 100644 index 6de271f1..00000000 --- a/src/gui/main.py +++ /dev/null @@ -1,965 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ -import wx -import dialogs -import buffers -import config -import twitter -import db -import webbrowser -import sound -import updater -import application -import os -import logging as original_logger -import output -import platform -import urllib2 -import sysTrayIcon -import languageHandler -from sessionmanager import manager -from mysc import event -from mysc.thread_utils import call_threaded -from twython import TwythonError -from urllib2 import URLError -from mysc.repeating_timer import RepeatingTimer -from mysc import localization -if platform.system() == "Windows" or platform.system() == "Linux": - from keyboard_handler.wx_handler import WXKeyboardHandler -from extra import SoundsTutorial -from keystrokeEditor import gui as keystrokeEditorGUI -log = original_logger.getLogger("gui.main") - -class mainFrame(wx.Frame): - """ Main class of the Frame. This is the Main Window.""" - - ### MENU - def makeMenus(self): - """ Creates, bind and returns the menu bar for the application. Also in this function, the accel table is created.""" - menuBar = wx.MenuBar() - - # Application menu - app = wx.Menu() - updateProfile = app.Append(wx.NewId(), _(u"&Update profile")) - self.Bind(wx.EVT_MENU, self.update_profile, updateProfile) - show_hide = app.Append(wx.NewId(), _(u"&Hide window")) - self.Bind(wx.EVT_MENU, self.show_hide, show_hide) - search = app.Append(wx.NewId(), _(u"&Search")) - self.Bind(wx.EVT_MENU, self.search, search) - lists = app.Append(wx.NewId(), _(u"&Lists manager")) - self.Bind(wx.EVT_MENU, self.list_manager, lists) - sounds_tutorial = app.Append(wx.NewId(), _(u"Sounds &tutorial")) - self.Bind(wx.EVT_MENU, self.learn_sounds, sounds_tutorial) - keystroke_editor = app.Append(wx.NewId(), _(u"&Edit keystrokes")) - self.Bind(wx.EVT_MENU, self.edit_keystrokes, keystroke_editor) - prefs = app.Append(wx.ID_PREFERENCES, _(u"&Preferences")) - self.Bind(wx.EVT_MENU, self.preferences, prefs) - close = app.Append(wx.ID_EXIT, _(u"E&xit")) - self.Bind(wx.EVT_MENU, self.close, close) - - # Tweet menu - tweet = wx.Menu() - compose = tweet.Append(wx.NewId(), _(u"&Tweet")) - self.Bind(wx.EVT_MENU, self.compose, compose) - response = tweet.Append(wx.NewId(), _(u"Re&ply")) - self.Bind(wx.EVT_MENU, self.reply, response) - retweet = tweet.Append(wx.NewId(), _(u"&Retweet")) - self.Bind(wx.EVT_MENU, self.retweet, retweet) - fav = tweet.Append(wx.NewId(), _(u"Add to &favourites")) - self.Bind(wx.EVT_MENU, self.fav, fav) - unfav = tweet.Append(wx.NewId(), _(u"Remove from favo&urites")) - self.Bind(wx.EVT_MENU, self.unfav, unfav) - view = tweet.Append(wx.NewId(), _(u"&Show tweet")) - self.Bind(wx.EVT_MENU, self.view, view) - delete = tweet.Append(wx.NewId(), _(u"&Delete")) - self.Bind(wx.EVT_MENU, self.delete, delete) - - # User menu - user = wx.Menu() - follow = user.Append(wx.NewId(), _(u"&Follow")) - self.Bind(wx.EVT_MENU, self.onFollow, follow) - unfollow = user.Append(wx.NewId(), _(u"&Unfollow")) - self.Bind(wx.EVT_MENU, self.onUnfollow, unfollow) - mute = user.Append(wx.NewId(), _(u"&Mute")) - self.Bind(wx.EVT_MENU, self.onMute, mute) - unmute = user.Append(wx.NewId(), _(u"U&nmute")) - self.Bind(wx.EVT_MENU, self.onUnmute, unmute) - report = user.Append(wx.NewId(), _(u"&Report as spam")) - self.Bind(wx.EVT_MENU, self.onReport, report) - block = user.Append(wx.NewId(), _(u"&Block")) - self.Bind(wx.EVT_MENU, self.onBlock, block) - unblock = user.Append(wx.NewId(), _(u"Unb&lock")) - self.Bind(wx.EVT_MENU, self.onUnblock, unblock) - dm = user.Append(wx.NewId(), _(u"Direct me&ssage")) - self.Bind(wx.EVT_MENU, self.dm, dm) - addToList = user.Append(wx.NewId(), _(u"&Add to list")) - self.Bind(wx.EVT_MENU, self.add_to_list, addToList) - removeFromList = user.Append(wx.NewId(), _(u"R&emove from list")) - self.Bind(wx.EVT_MENU, self.remove_from_list, removeFromList) - viewLists = user.Append(wx.NewId(), _(u"&View lists")) - self.Bind(wx.EVT_MENU, self.view_user_lists, viewLists) - details = user.Append(wx.NewId(), _(u"Show user &profile")) - self.Bind(wx.EVT_MENU, self.details, details) - timeline = user.Append(wx.NewId(), _(u"&Timeline")) - self.Bind(wx.EVT_MENU, self.open_timeline, timeline) - favs = user.Append(wx.NewId(), _(u"V&iew favourites")) - self.Bind(wx.EVT_MENU, self.favs_timeline, favs) - - # buffer menu - buffer = wx.Menu() - load_previous_items = buffer.Append(wx.NewId(), _(u"&Load previous items")) - self.Bind(wx.EVT_MENU, self.get_more_items, load_previous_items) - mute = buffer.Append(wx.NewId(), _(u"&Mute")) - self.Bind(wx.EVT_MENU, self.toggle_mute, mute) - autoread = buffer.Append(wx.NewId(), _(u"&Autoread tweets for this buffer")) - self.Bind(wx.EVT_MENU, self.toggle_autoread, autoread) - clear = buffer.Append(wx.NewId(), _(u"&Clear buffer")) - self.Bind(wx.EVT_MENU, self.clear_list, clear) - deleteTl = buffer.Append(wx.NewId(), _(u"&Remove buffer")) - self.Bind(wx.EVT_MENU, self.delete_buffer, deleteTl) - - # Help Menu - help = wx.Menu() - doc = help.Append(-1, _(u"&Documentation")) - self.Bind(wx.EVT_MENU, self.onManual, doc) - changelog = help.Append(wx.NewId(), _(u"&What's new in this version?")) - self.Bind(wx.EVT_MENU, self.onChangelog, changelog) - check_for_updates = help.Append(wx.NewId(), _(u"&Check for updates")) - self.Bind(wx.EVT_MENU, self.onCheckForUpdates, check_for_updates) - reportError = help.Append(wx.NewId(), _(u"&Report an error")) - self.Bind(wx.EVT_MENU, self.onReportBug, reportError) - visit_website = help.Append(-1, _(u"TW Blue &website")) - self.Bind(wx.EVT_MENU, self.onVisit_website, visit_website) - about = help.Append(-1, _(u"About &TW Blue")) - self.Bind(wx.EVT_MENU, self.onAbout, about) - - # Add all to the menu Bar - menuBar.Append(app, _(u"&Application")) - menuBar.Append(tweet, _(u"&Tweet")) - menuBar.Append(user, _(u"&User")) - menuBar.Append(buffer, _(u"&Buffer")) - menuBar.Append(help, _(u"&Help")) - - downID = wx.NewId() - upID = wx.NewId() - leftID = wx.NewId() - rightID = wx.NewId() - if platform.system() == "Darwin": - self.Bind(wx.EVT_MENU, self.down, id=downID) - self.Bind(wx.EVT_MENU, self.up, id=upID) - self.Bind(wx.EVT_MENU, self.left, id=leftID) - self.Bind(wx.EVT_MENU, self.right, id=rightID) - - # Creates the acceleration table. - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('N'), compose.GetId()), -(wx.ACCEL_CTRL, ord('R'), response.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('R'), retweet.GetId()), -(wx.ACCEL_CTRL, ord('F'), fav.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('F'), unfav.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('V'), view.GetId()), -(wx.ACCEL_CTRL, ord('D'), dm.GetId()), - -(wx.ACCEL_CTRL, ord('Q'), close.GetId()), -(wx.ACCEL_CTRL, ord('S'), follow.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('S'), unfollow.GetId()), -(wx.ACCEL_CTRL, ord('K'), block.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('K'), report.GetId()), -(wx.ACCEL_CTRL, ord('I'), timeline.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('I'), deleteTl.GetId()), -(wx.ACCEL_CTRL, ord('M'), show_hide.GetId()), -(wx.ACCEL_CTRL, ord('P'), updateProfile.GetId()), -(wx.ACCEL_CTRL, wx.WXK_DOWN, downID), -(wx.ACCEL_CTRL, wx.WXK_UP, upID), -(wx.ACCEL_CTRL, wx.WXK_LEFT, leftID), -(wx.ACCEL_CTRL, wx.WXK_RIGHT, rightID), - ]) - - self.SetAcceleratorTable(self.accel_tbl) - return menuBar - - ### MAIN - def __init__(self, authorised=True, user_key=None, user_secret=None): - """ Main function of this class.""" - if authorised == False: - self.user_key = user_key - self.user_secret = user_secret - else: - self.user_key = self.user_secret = None - log.debug("Loading temporal database...") - self.db = db.db() - # Gets the twitter object for future calls to the twitter Rest API. - log.debug("Getting Twitter's Rest API...") - self.twitter = twitter.twitter.twitter() - super(mainFrame, self).__init__(None, -1, "TW Blue", size=(1600, 1600)) - self.Bind(wx.EVT_QUERY_END_SESSION, self.exit) - self.Bind(wx.EVT_END_SESSION, self.exit) - log.debug(u"Creating the system tray icon... ") - sysTray=sysTrayIcon.SysTrayIcon(self) - panel = wx.Panel(self) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle("TW Blue") - try: - updater.update_manager.check_for_update() - except: - pass - self.SetMenuBar(self.makeMenus()) - self.setup_twitter(panel) - - def logging_in_twblue(self, panel): - log.debug("Retrieving username...") - twitter.starting.start_user_info(config=self.db, twitter=self.twitter) - config.main["twitter"]["user_name"] = self.db.settings["user_name"] - self.SetTitle(u"@%s. - TW Blue" % (self.db.settings["user_name"])) - self.nb = wx.Treebook(panel, -1) - self.Bind(wx.EVT_CLOSE, self.close) - self.nb.Bind(wx.EVT_TREEBOOK_PAGE_CHANGED, self.onPageChanged) - # Gets the tabs for home, mentions, send and direct messages. - log.debug("Creating buffers...") - self.db.settings["buffers"] = [] - account = buffers.accountPanel(self.nb) - self.nb.AddPage(account, self.db.settings["user_name"]) - self.db.settings["buffers"].append(self.db.settings["user_name"]) - account_index = self.db.settings["buffers"].index(self.db.settings["user_name"]) - home = buffers.basePanel(self.nb, self, "home_timeline", self.twitter.twitter.get_home_timeline, sound="tweet_received.ogg") - self.nb.InsertSubPage(account_index, home, _(u"Home")) - self.db.settings["buffers"].append("home_timeline") - self.nb.SetSelection(1) - self.nb.GetPage(1).list.list.SetFocus() - mentionsP = buffers.basePanel(self.nb, self, "mentions", self.twitter.twitter.get_mentions_timeline, sound="mention_received.ogg") - self.nb.InsertSubPage(account_index, mentionsP, _("Mentions")) - self.db.settings["buffers"].append("mentions") - dms = buffers.dmPanel(self.nb, self, "direct_messages", self.twitter.twitter.get_direct_messages, sound="dm_received.ogg") - self.nb.InsertSubPage(account_index, dms, _(u"Direct messages")) - self.db.settings["buffers"].append("direct_messages") - sent = buffers.basePanel(self.nb, self, "sent", self.twitter.twitter.get_user_timeline, argumento=self.db.settings["user_name"]) - self.nb.InsertSubPage(account_index, sent, _(u"Sent")) - self.db.settings["buffers"].append("sent") -# If the user has enabled favs from config. - if config.main["other_buffers"]["show_favourites"] == True: - log.debug("Getting Favorited tweets...") - favs = buffers.basePanel(self.nb, self, "favs", self.twitter.twitter.get_favorites) - self.nb.InsertSubPage(account_index, favs, _(u"Favourites")) - self.db.settings["buffers"].append("favs") -# If followers are enabled from config. - if config.main["other_buffers"]["show_followers"] == True: - log.debug("Getting followers...") - followers = buffers.peoplePanel(self.nb, self, "followers", self.twitter.twitter.get_followers_list, argumento=self.db.settings["user_name"], sound="update_followers.ogg") - self.nb.InsertSubPage(account_index, followers, _(u"Followers")) - self.db.settings["buffers"].append("followers") - # Same here but for friends. - if config.main["other_buffers"]["show_friends"] == True: - log.debug("Getting friends...") - friends = buffers.peoplePanel(self.nb, self, "friends", self.twitter.twitter.get_friends_list, argumento=self.db.settings["user_name"]) - self.nb.InsertSubPage(account_index, friends, _(u"Friends")) - self.db.settings["buffers"].append("friends") - if config.main["other_buffers"]["show_blocks"] == True: - blocked = buffers.peoplePanel(self.nb, self, "blocks", self.twitter.twitter.list_blocks) - self.nb.InsertSubPage(account_index, blocked, _(u"Blocked users")) - self.db.settings["buffers"].append("blocks") - if config.main["other_buffers"]["show_muted_users"] == True: - muteds = buffers.peoplePanel(self.nb, self, "muteds", self.twitter.twitter.get_muted_users_list) - self.nb.InsertSubPage(account_index, muteds, _(u"Muted users")) - self.db.settings["buffers"].append("muteds") - if config.main["other_buffers"]["show_events"] == True: - evt = buffers.eventsPanel(self.nb, self, sound="new_event.ogg") - self.nb.InsertSubPage(account_index, evt, _(u"Events")) - self.db.settings["buffers"].append("events") - searches = buffers.emptyPanel(self.nb) - self.nb.InsertSubPage(account_index, searches, _(u"Searches")) - self.db.settings["buffers"].append("searches") - - for i in config.main["other_buffers"]["tweet_searches"]: - self.nb.InsertSubPage(self.db.settings["buffers"].index("searches"), buffers.searchPanel(self.nb, self, "%s-search" % (i,), q=i, count=100), _(u"Search for %s" % (i,))) - self.db.settings["buffers"].append("%s-search" % (i,)) - timelines = buffers.emptyPanel(self.nb) - self.nb.InsertSubPage(account_index, timelines, _(u"Timelines")) - self.db.settings["buffers"].append("timelines") - for i in config.main["other_buffers"]["timelines"]: - self.nb.InsertSubPage(self.db.settings["buffers"].index("timelines"), buffers.basePanel(self.nb, self, i, self.twitter.twitter.get_user_timeline, argumento=i, timeline=True, sound="tweet_timeline.ogg"), _(u"Timeline for %s") % i) - self.db.settings["buffers"].append(i) - lists = buffers.emptyPanel(self.nb) - self.nb.InsertSubPage(account_index, lists, _(u"Lists")) - self.db.settings["buffers"].append("lists") - for i in config.main["other_buffers"]["lists"]: - self.nb.InsertSubPage(self.db.settings["buffers"].index("lists"), buffers.listPanel(self.nb, self, i+"-list", argumento=twitter.utils.find_list(i, self.db.settings["lists"])), _(u"List for %s") % i) - self.db.settings["buffers"].append(i+"-list") - - ## favourites timelines - favs_timelines = buffers.emptyPanel(self.nb) - self.nb.InsertSubPage(account_index, favs_timelines, _(U"Favourites timelines")) - self.db.settings["buffers"].append("favourites_timelines") - for i in config.main["other_buffers"]["favourites_timelines"]: - self.nb.InsertSubPage(self.db.settings["buffers"].index("favourites_timelines"), buffers.favsPanel(self.nb, self, i+"favs", argumento=i, sound="favourites_timeline_updated.ogg"), _(u"Favourites for %s") % i,) - self.db.settings["buffers"].append(i+"favs") - self.fav_stream = RepeatingTimer(180, self.get_fav_buffers) - self.fav_stream.start() - self.sizer.Add(self.nb, 0, wx.ALL, 5) - panel.SetSizer(self.sizer) - self.SetClientSize(self.sizer.CalcMin()) - self.Bind(event.MyEVT_STARTED, self.onInit) - self.Bind(event.EVT_RESULT, self.onMemberAdded) - call_threaded(self.init, run_streams=True) - - def init(self, run_streams=False): - """ Calls the start_stream function for each stream tab.""" - deleted = 0 - for i in range(0, self.nb.GetPageCount()): - if self.nb.GetPage(i).type == "account" or self.nb.GetPage(i).type == "empty": continue - if i == self.nb.GetPageCount() and deleted > 0: - i = i-1 - deleted = deleted-1 - log.debug("Starting stream for %s..." % self.nb.GetPage(i).name_buffer) - info_event = event.infoEvent(event.EVT_STARTED, 1) - try: - if self.nb.GetPage(i).type == "search": - self.nb.GetPage(i).timer = RepeatingTimer(180, self.nb.GetPage(i).load_search) - self.nb.GetPage(i).timer.start() - num = self.nb.GetPage(i).start_streams() - info_event.SetItem(i, num) - wx.PostEvent(self, info_event) - except TwythonError as e: - continue - except UnicodeDecodeError: # This happens when there is a bad internet connection - continue - output.speak(_(u"Ready")) - - if run_streams == True: - self.get_home() - self.get_tls() - self.check_streams = RepeatingTimer(config.main["general"]["time_to_check_streams"], self.check_stream_up) - self.check_streams.start() - # If all it's done, then play a nice sound saying that all it's OK. - sound.player.play("ready.ogg") - - def remove_list(self, id): - for i in range(0, self.nb.GetPageCount()): - if self.nb.GetPage(i).type == "list": - if self.nb.GetPage(i).argumento == id: - pos = self.nb.GetCurrentPage().remove_invalid_buffer() - if pos != None: - self.nb.DeletePage(pos) - self.onMemberAdded() - - def onMemberAdded(self, ev): - self.stream2.disconnect() - del self.stream2 - self.get_tls() - - def get_fav_buffers(self): - for i in config.main["other_buffers"]["favourites_timelines"]: - num = self.nb.GetPage(self.db.settings["buffers"].index(i+"favs")).start_streams() - if num > 0: output.speak(_(u"%s favourites from %s") % (nun, i)) - - def setup_twitter(self, panel): - """ Setting up the connection for twitter, or authenticate if the config file has valid credentials.""" - try: - self.twitter.login(self.user_key, self.user_secret) - self.logging_in_twblue(panel) - log.info("Authorized in Twitter.") - del self.user_key; del self.user_secret - except: - dlg1 = wx.MessageDialog(panel, _(u"Connection error. Try again later."), _(u"Error!"), wx.ICON_ERROR) - dlg1.ShowModal() - self.Close(True) - - def get_home(self): - """ Gets the home stream, that manages home timeline, mentions, direct messages and sent.""" - try: - self.stream = twitter.buffers.stream.streamer(application.app_key, application.app_secret, config.main["twitter"]["user_key"], config.main["twitter"]["user_secret"], parent=self) - call_threaded(self.stream.user) - except: - self.stream.disconnect() - - def start_lists(self): - for i in range(0, self.nb.GetPageCount()): - if self.nb.GetPage(i).type == "list": self.nb.GetPage(i).retrieve_ids() - - def get_tls(self): - """ Setting the stream for individual user timelines.""" -# try: - self.stream2 = twitter.buffers.indibidual.streamer(application.app_key, application.app_secret, config.main["twitter"]["user_key"], config.main["twitter"]["user_secret"], parent=self) - # The self.ids contains all IDS for the follow argument of the stream. - ids = "" - # If we have more than 0 items on a list, then. - for i in config.main["other_buffers"]["timelines"]: - ids = ids+self.db.settings[i][0]["user"]["id_str"]+", " - for i in range(0, self.nb.GetPageCount()): - if self.nb.GetPage(i).type == "list": - for z in self.nb.GetPage(i).users: - ids+= str(z)+", " - if ids != "": - # try: - call_threaded(self.stream2.statuses.filter, follow=ids) - # except: - # pass -# except: -# self.stream2.disconnect() - - def check_stream_up(self): - try: - urllib2.urlopen("http://74.125.228.231", timeout=5) - except urllib2.URLError: - if self.stream.connected == True: self.stream.disconnect() - if hasattr(self, "stream2") and self.stream2.connected: self.stream2.disconnect() - if config.main["general"]["announce_stream_status"] == True: output.speak(_(u"Streams disconnected. TW Blue will try to reconnect in a minute.")) - return - if self.stream.connected == False: - del self.stream - if config.main["general"]["announce_stream_status"] == True: output.speak(_(u"Reconnecting streams...")) - call_threaded(self.init) - self.get_home() - if hasattr(self, "stream2") and self.stream2.connected == False: - log.debug("Trying reconnects the timelines stream...") - del self.stream2 - self.get_tls() - - ### Events - - def edit_keystrokes(self, ev=None): - if hasattr(self, "keyboard_handler"): - dlg = keystrokeEditorGUI.keystrokeEditor(parent=self, keyboard_handler=self.keyboard_handler) - else: - dlg = keystrokeEditorGUI.keystrokeEditor(parent=self) - dlg.ShowModal() - dlg.Destroy() - - def search(self, ev=None): - dlg = dialogs.search.searchDialog() - if dlg.ShowModal() == wx.ID_OK: - term = dlg.term.GetValue() - if dlg.tweets.GetValue() == True: - search =buffers.searchPanel(self.nb, self, "%s-search" % (term,), q=term, count=100) - self.nb.InsertSubPage(self.db.settings["buffers"].index("searches"), search, _(u"search for %s") % (term,)) - self.db.settings["buffers"].append("%s-search" % (term,)) - config.main["other_buffers"]["tweet_searches"].append(term) - elif dlg.users.GetValue() == True: - search =buffers.searchUsersPanel(self.nb, self, "%s_search" % (term,), q=term, count=20) - self.nb.InsertSubPage(self.db.settings["buffers"].index("searches"), search, _(u"search users for %s") % (term,)) - self.db.settings["buffers"].append("%s_search" % (term,)) - timer = RepeatingTimer(180, search.load_search) - timer.start() - num = search.start_streams() - search.put_items(num) - dlg.Destroy() - - def learn_sounds(self, ev): - SoundsTutorial.gui.soundsTutorial().ShowModal() - - def view_user_lists(self, ev=None): - userDlg = dialogs.utils.selectUserDialog(parent=self, title=_(u"Select the user")) - if userDlg.ShowModal() == wx.ID_OK: - user = userDlg.cb.GetValue() - else: - return - dlg = dialogs.lists.userListViewer(self, user) - dlg.ShowModal() - userDlg.Destroy() - dlg.Destroy() - - def add_to_list(self, ev=None): - userDlg = dialogs.utils.selectUserDialog(parent=self, title=_(u"Select the user")) - if userDlg.ShowModal() == wx.ID_OK: - user = userDlg.cb.GetValue() - else: - return - dlg = dialogs.lists.addUserListDialog(self) - if dlg.ShowModal() == wx.ID_OK: - try: - list = self.twitter.twitter.add_list_member(list_id=self.db.settings["lists"][dlg.lista.get_selected()]["id"], screen_name=user) - older_list = twitter.utils.find_item(self.db.settings["lists"][dlg.lista.get_selected()]["id"], self.db.settings["lists"]) - if list["mode"] == "private": - self.db.settings["lists"].pop(older_list) - self.db.settings["lists"].append(list) - except TwythonError as e: - output.speak("error %s: %s" % (e.error_code, e.msg)) - userDlg.Destroy() - dlg.Destroy() - - def remove_from_list(self, ev=None): - userDlg = dialogs.utils.selectUserDialog(parent=self, title=_(u"Select the user")) - if userDlg.ShowModal() == wx.ID_OK: - user = userDlg.cb.GetValue() - else: - return - dlg = dialogs.lists.removeUserListDialog(self) - if dlg.ShowModal() == wx.ID_OK: - try: - list = self.twitter.twitter.delete_list_member(list_id=self.db.settings["lists"][dlg.get_selected()]["id"], screen_name=user) - older_list = twitter.utils.find_item(self.db.settings["lists"][dlg.get_selected()]["id"], self.db.settings["lists"]) - if list["mode"] == "private": - self.db.settings["lists"].pop(older_list) - self.db.settings["lists"].append(list) - except TwythonError as e: - output.speak("error %s: %s" % (e.error_code, e.msg)) - userDlg.Destroy() - dlg.Destroy() - - def list_manager(self, ev): - dlg = dialogs.lists.listViewer(self) - dlg.ShowModal() - self.stream2.disconnect() - del self.stream2 - self.get_tls() - dlg.Destroy() - - def onInit(self, ev): - if self.nb.GetPage(ev.GetItem()[0]).type != "search" or self.nb.GetPage(ev.GetItem()[0]).type != "favourites_timeline": self.nb.GetPage(ev.GetItem()[0]).put_items(ev.GetItem()[1]) - - def preferences(self, ev=None): - dlg = dialogs.configuration.configurationDialog(self) - dlg.ShowModal() - dlg.Destroy() - - def update_profile(self, ev=None): - dialogs.update_profile.updateProfile(self).ShowModal() - - def onManual(self, ev): - lang = localization.get("documentation") - os.chdir("documentation/%s" % (lang,)) - webbrowser.open("manual.html") - os.chdir("../../") - - def onChangelog(self, ev): - lang = localization.get("documentation") - os.chdir("documentation/%s" % (lang,)) - webbrowser.open("changes.html") - os.chdir("../../") - - def onVisit_website(self, ev): - webbrowser.open("http://twblue.com.mx") - - def onReportBug(self, ev): - webbrowser.open("https://github.com/manuelcortez/TWBlue/issues") -# issueReporterGUI.reportBug(self.db.settings["user_name"]).ShowModal() - - def onCheckForUpdates(self, ev): - updater.update_manager.check_for_update(msg=True) - - def details(self, ev=None): - """ This function shows details for the selected user.""" - dlg = dialogs.utils.selectUserDialog(parent=self, title=_(u"User details")) - if dlg.ShowModal() == wx.ID_OK: - dialogs.show_user.showUserProfile(self.twitter, dlg.cb.GetValue()).ShowModal() - dlg.Destroy() - - def delete(self, ev=None): - """ Deleting a tweet or direct message.""" - if self.nb.GetCurrentPage().name_buffer != "followers" and self.nb.GetCurrentPage() != "friends" and self.nb.GetCurrentPage().name_buffer != "events": - dlg = wx.MessageDialog(self, _(u"Do you really want to delete this message? It will be eliminated from Twitter as well."), _(u"Delete"), wx.ICON_QUESTION|wx.YES_NO) - if dlg.ShowModal() == wx.ID_YES: - self.nb.GetCurrentPage().destroy_status(wx.EVT_MENU) - else: - return - - def onPageChanged(self, ev): - """ Announces the new title for the tab.""" - if platform.system() == "Darwin": - output.speak(self.nb.GetPageText(self.nb.GetSelection())+",", True) - - def skip_blank_pages(self, forward=True): - if self.nb.GetCurrentPage().type == "account" or self.nb.GetCurrentPage().type == "empty" and (self.showing == False or platform.system() == "Darwin"): - self.nb.AdvanceSelection(forward) - - def close(self, ev=None): - if config.main["general"]["ask_at_exit"] == True: - dlg = wx.MessageDialog(self, _(u"Do you really want to close TW Blue?"), _(u"Exit"), wx.YES_NO|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_YES: - self.exit() - dlg.Destroy() - else: - output.speak(_(u"Exiting...")) - self.exit() - - def exit(self, event=None): - config.main.write() - log.debug("Exiting...") - try: - self.check_streams.cancel() - except AttributeError: - pass - sound.player.cleaner.cancel() - try: - self.stream.disconnect() - log.debug("Stream disconnected.") - except: - pass - try: - self.stream2.disconnect() - log.debug(u"Timelines stream disconnected.") - except: - pass - wx.GetApp().ExitMainLoop() - - def onFollow(self, ev=None): - """ Opens the follow dialog.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "follow").ShowModal() - - def onUnfollow(self, ev=None): - """ Opens the unfollow dialog.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "unfollow").ShowModal() - - def onMute(self, ev=None): - """ Opens the unfollow dialog.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "mute").ShowModal() - - def onUnmute(self, ev=None): - """ Opens the unfollow dialog.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "unmute").ShowModal() - - def onReport(self, ev=None): - """ Opens the report dialog, to report as spam to the specified user.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "report").ShowModal() - - def onBlock(self, ev=None): - """ Opens the "block" dialog, to block the user that you want.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "block").ShowModal() - - def onUnblock(self, ev=None): - """ Opens the "block" dialog, to block the user that you want.""" - dialogs.follow.follow(self.nb.GetCurrentPage(), "unblock").ShowModal() - - def action(self, ev=None): - dialogs.follow.follow(self.nb.GetCurrentPage()).ShowModal() - - def compose(self, ev=None): - """ Opens the new tweet dialog.""" - self.nb.GetCurrentPage().post_status(ev) - - def reply(self, ev=None): - """ Opens the response dialog.""" - self.nb.GetCurrentPage().onResponse(ev) - - def dm(self, ev=None): - """ Opens the DM Dialog.""" - # The direct_messages buffer has a method to post a diret messages while the other tabs does has not it. - if self.nb.GetCurrentPage().name_buffer == "direct_messages": - self.nb.GetCurrentPage().onResponse(ev) - elif self.nb.GetCurrentPage().name_buffer == "events": return - else: -# dialogs.message.dm(_(u"Direct message to %s ") % (self.db.settings[self.nb.GetCurrentPage().name_buffer][self.nb.GetCurrentPage().get_selected()]["user"]["screen_name"]), "", "", self.nb.GetCurrentPage()).ShowModal() - self.nb.GetCurrentPage().onDm(ev) - - def retweet(self, ev=None): - if self.nb.GetCurrentPage().name_buffer != "direct_messages" and self.nb.GetCurrentPage().name_buffer != "followers" and self.nb.GetCurrentPage().name_buffer != "friends" and self.nb.GetCurrentPage().name_buffer != "events": - self.nb.GetCurrentPage().onRetweet(ev) - - def view(self, ev=None): - tweet = self.nb.GetCurrentPage().get_message(dialog=True) - dialogs.message.viewTweet(tweet).ShowModal() - - def fav(self, ev=None): - if self.nb.GetCurrentPage().name_buffer != "direct_messages" and self.nb.GetCurrentPage().name_buffer != "followers" and self.nb.GetCurrentPage().name_buffer != "friends": - try: - self.twitter.twitter.create_favorite(id=self.db.settings[self.nb.GetCurrentPage().name_buffer][self.nb.GetCurrentPage().list.get_selected()]["id"]) - sound.player.play("favourite.ogg") - except TwythonError as e: - output.speak(_(u"Error while adding to favourites."), True) - sound.player.play("error.ogg") - - def unfav(self, ev=None): - if self.nb.GetCurrentPage().name_buffer != "direct_messages" and self.nb.GetCurrentPage().name_buffer != "followers" and self.nb.GetCurrentPage().name_buffer != "friends": - try: - self.twitter.twitter.destroy_favorite(id=self.db.settings[self.nb.GetCurrentPage().name_buffer][self.nb.GetCurrentPage().list.get_selected()]["id"]) - except TwythonError as e: - output.speak(_(u"Error while removing from favourites."), True) - sound.player.play("error.ogg") - - def open_timeline(self, ev=None): - dlg = dialogs.utils.selectUserDialog(self, _(u"Individual timeline")) - if dlg.ShowModal() == wx.ID_OK: - user = twitter.utils.if_user_exists(self.twitter.twitter, dlg.cb.GetValue()) - if user == None: - wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() - dlg.Destroy() - return - if user not in config.main["other_buffers"]["timelines"]: - config.main["other_buffers"]["timelines"].append(user) - else: - wx.MessageDialog(None, _(u"There's currently a timeline for this user. You are not able to open another"), _(u"Existing timeline"), wx.ICON_ERROR).ShowModal() - dlg.Destroy() - return - sound.player.play("create_timeline.ogg") - st = buffers.basePanel(self.nb, self, user, self.twitter.twitter.get_user_timeline, argumento=user, sound="ready.ogg", timeline=True) - num = st.start_streams() - self.db.settings["buffers"].append(user) - if num == 0: - wx.MessageDialog(None, _(u"This user has no tweets. You can't open a timeline for this user"), _(u"Error!"), wx.ICON_ERROR).ShowModal() - self.db.settings.pop(user) -# self.nb.DeletePage(self.db.settings["buffers"].index(user)) - self.db.settings["buffers"].remove(user) - else: - self.nb.InsertSubPage(self.db.settings["buffers"].index("timelines"), st, _(u"Timeline for %s") % (user)) - st.put_items(num) - st.sound = "tweet_timeline.ogg" - self.stream2.disconnect() - del self.stream2 - self.get_tls() - dlg.Destroy() - - def favs_timeline(self, ev=None): - dlg = dialogs.utils.selectUserDialog(self, _(u"List of favourites")) - if dlg.ShowModal() == wx.ID_OK: - user = twitter.utils.if_user_exists(self.twitter.twitter, dlg.cb.GetValue()) - if user == None: - wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() - dlg.Destroy() - return - if user not in config.main["other_buffers"]["favourites_timelines"]: - config.main["other_buffers"]["favourites_timelines"].append(user) - else: - wx.MessageDialog(None, _(u"There's already a list of favourites for this user. You can't create another."), _(u"Existing list"), wx.ICON_ERROR).ShowModal() - dlg.Destroy() - return - sound.player.play("create_timeline.ogg") - st = buffers.favsPanel(self.nb, self, user+"-favs", argumento=user, sound="favourites_timeline_updated.ogg") - self.nb.InsertSubPage(self.db.settings["buffers"].index("favourites_timelines"), st, _(u"Favourites for %s") % (user)) - num = st.start_streams() - self.db.settings["buffers"].append(user+"-favs") - if num == 0: - wx.MessageDialog(None, _(u"This user has no favourites. You can't create a list of favourites for this user."), _(u"Error!"), wx.ICON_ERROR).ShowModal() - self.db.settings.pop(user+"-favs") - self.nb.DeletePage(self.db.settings["buffers"].index(user+"-favs")) - self.db.settings["buffers"].remove(user+"-favs") - st.put_items(num) - dlg.Destroy() - - def onAbout(self, ev=None): - info = wx.AboutDialogInfo() - info.SetName(application.name) - info.SetVersion(application.version) - info.SetDescription(application.description) - info.SetCopyright(application.copyright) - info.SetTranslators(application.translators) -# info.SetLicence(application.licence) - info.AddDeveloper(application.author) - wx.AboutBox(info) - - def delete_buffer(self, ev=None): - pos = self.nb.GetCurrentPage().remove_buffer() - if pos != None: - self.stream2.disconnect() - del self.stream2 - self.nb.DeletePage(self.nb.GetSelection()) - sound.player.play("delete_timeline.ogg") - self.get_tls() - - def delete_invalid_timeline(self): - pos = self.nb.GetCurrentPage().remove_invalid_buffer() - if pos != None: - self.nb.DeletePage(self.nb.GetSelection()) - - ### Hidden Window - def left(self, event=None): - num = self.nb.GetSelection() - if num == 0: - self.nb.ChangeSelection(self.nb.GetPageCount()-1) - else: - self.nb.SetSelection(num-1) - while self.nb.GetCurrentPage().type == "account" or self.nb.GetCurrentPage().type == "empty": self.skip_blank_pages(False) - try: - msg = _(u"%s, %s of %s") % (self.nb.GetPageText(self.nb.GetSelection()), self.nb.GetCurrentPage().list.get_selected()+1, self.nb.GetCurrentPage().list.get_count()) - except: - msg = _(u"%s. Empty") % (self.nb.GetPageText(self.nb.GetSelection())) - output.speak(msg, 1) - - def right(self, event=None): - num = self.nb.GetSelection() - if num+1 == self.nb.GetPageCount(): - self.nb.SetSelection(0) - else: - self.nb.SetSelection(num+1) - while self.nb.GetCurrentPage().type == "account" or self.nb.GetCurrentPage().type == "empty": self.skip_blank_pages(True) - try: - msg = _(u"%s, %s of %s") % (self.nb.GetPageText(self.nb.GetSelection()), self.nb.GetCurrentPage().list.get_selected()+1, self.nb.GetCurrentPage().list.get_count()) - except: - msg = _(u"%s. Empty") % (self.nb.GetPageText(self.nb.GetSelection())) - output.speak(msg, 1) - - def show_hide(self, ev=None): -# if platform.system() == "Linux" or platform.system() == "Darwin": return - keymap = {} - for i in config.main["keymap"]: - if hasattr(self, i): - keymap[config.main["keymap"][i]] = getattr(self, i) - if self.showing == True: - self.keyboard_handler = WXKeyboardHandler(self) - self.keyboard_handler.register_keys(keymap) - self.Hide() - self.showing = False - else: - self.keyboard_handler.unregister_keys(keymap) - del self.keyboard_handler - self.Show() - self.showing = True - - def toggle_global_mute(self, event=None): - if config.main["sound"]["global_mute"] == False: - config.main["sound"]["global_mute"] = True - output.speak(_(u"Global mute on")) - elif config.main["sound"]["global_mute"] == True: - config.main["sound"]["global_mute"] = False - output.speak(_(u"Global mute off")) - - def toggle_mute(self, event=None): - buffer = self.nb.GetCurrentPage().name_buffer - if buffer not in config.main["other_buffers"]["muted_buffers"]: - config.main["other_buffers"]["muted_buffers"].append(buffer) - output.speak(_(u"Buffer mute on")) - elif buffer in config.main["other_buffers"]["muted_buffers"]: - config.main["other_buffers"]["muted_buffers"].remove(buffer) - output.speak(_(u"Buffer mute off")) - - def toggle_autoread(self, event=None): - buffer = self.nb.GetCurrentPage().name_buffer - if buffer not in config.main["other_buffers"]["autoread_buffers"]: - config.main["other_buffers"]["autoread_buffers"].append(buffer) - output.speak(_(u"The auto-reading of new tweets is enabled for this buffer")) - elif buffer in config.main["other_buffers"]["autoread_buffers"]: - config.main["other_buffers"]["autoread_buffers"].remove(buffer) - output.speak(_(u"The auto-reading of new tweets is disabled for this buffer")) - - def repeat_item(self): - output.speak(self.nb.GetCurrentPage().get_message(), 1) - - def copy_to_clipboard(self, event=None): - output.Copy(self.nb.GetCurrentPage().get_message()) - output.speak(_(u"Copied")) - - def clear_list(self, event=None): - self.nb.GetCurrentPage().interact("clear_list") - - def conversation_up(self, evt=None): - if config.main["general"]["reverse_timelines"] == True and evt == None: - self.conversation_down("down") - return - id = self.db.settings[self.nb.GetCurrentPage().name_buffer][self.nb.GetCurrentPage().list.get_selected()]["in_reply_to_status_id_str"] - pos = twitter.utils.find_previous_reply(id, self.db.settings["home_timeline"]) - if pos != None: - self.nb.ChangeSelection(1) - self.nb.GetCurrentPage().list.select_item(pos) - msg = _(u"%s") % (self.nb.GetCurrentPage().get_message()) - output.speak(msg) - - def conversation_down(self, evt=None): - if config.main["general"]["reverse_timelines"] == True and evt == None: - self.conversation_up("up") - return - id = self.db.settings[self.nb.GetCurrentPage().name_buffer][self.nb.GetCurrentPage().list.get_selected()]["id_str"] -# pos = twitter.utils.find_next_reply(id, self.db.settings["home_timeline"]) - pos = twitter.utils.find_next_reply(id, self.db.settings["home_timeline"]) - if pos != None: - self.nb.ChangeSelection(1) - self.nb.GetCurrentPage().list.select_item(pos) - msg = _(u"%s") % (self.nb.GetCurrentPage().get_message()) - output.speak(msg) - - def go_home(self): - self.nb.GetCurrentPage().list.select_item(0) - try: - output.speak(self.nb.GetCurrentPage().get_message(), 1) - except: - pass - - def go_end(self): - self.nb.GetCurrentPage().list.select_item(self.nb.GetCurrentPage().list.get_count()-1) - try: - output.speak(self.nb.GetCurrentPage().get_message(), 1) - except: - pass - - def go_page_up(self): - if self.nb.GetCurrentPage().list.get_selected <= 20: - index = 0 - else: - index = self.nb.GetCurrentPage().list.get_selected() - 20 - self.nb.GetCurrentPage().list.select_item(index) - try: - output.speak(self.nb.GetCurrentPage().get_message(), 1) - except: - pass - - def go_page_down(self): - if self.nb.GetCurrentPage().list.get_selected() >= self.nb.GetCurrentPage().list.get_count() - 20: - index = self.nb.GetCurrentPage().list.get_count()-1 - else: - index = self.nb.GetCurrentPage().list.get_selected() + 20 - self.nb.GetCurrentPage().list.select_item(index) - try: - output.speak(self.nb.GetCurrentPage().get_message(), 1) - except: - pass - - def volume_up(self): - self.nb.GetCurrentPage().interact("volume_up") - - def volume_down(self): - self.nb.GetCurrentPage().interact("volume_down") - - def url(self): - self.nb.GetCurrentPage().interact("url") - - def audio(self): - self.nb.GetCurrentPage().interact("audio") - - def up(self, event=None): - pos = self.nb.GetCurrentPage().list.get_selected() - index = self.nb.GetCurrentPage().list.get_selected()-1 - try: - self.nb.GetCurrentPage().list.select_item(index) - except: - pass - if pos == self.nb.GetCurrentPage().list.get_selected(): - sound.player.play("limit.ogg", False) - try: - output.speak(self.nb.GetCurrentPage().get_message(), 1) - except: - pass - - def down(self, event=None): - index = self.nb.GetCurrentPage().list.get_selected()+1 - pos = self.nb.GetCurrentPage().list.get_selected() - try: - self.nb.GetCurrentPage().list.select_item(index) - except: - pass - if pos == self.nb.GetCurrentPage().list.get_selected(): - sound.player.play("limit.ogg", False) - try: - output.speak(self.nb.GetCurrentPage().get_message(), 1) - except: - pass - - def get_more_items(self, event=None): - self.nb.GetCurrentPage().get_more_items() - - def search_buffer(self, buffer_type=None, name_buffer=None): - page = None - for i in range(0, self.nb.GetPageCount()): - page = self.nb.GetPage(i) - if page.type != buffer_type: - continue - if page.name_buffer == name_buffer: - return page - return page - -### Close App - def Destroy(self): - self.sysTray.Destroy() - super(mainFrame, self).Destroy() diff --git a/src/issueReporter/__init__.py b/src/issueReporter/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/issueReporter/constants.py b/src/issueReporter/constants.py new file mode 100644 index 00000000..c228d285 --- /dev/null +++ b/src/issueReporter/constants.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################ +# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program. If not, see . +# +############################################################ +categories = ["General"] +reproducibilities = ["always", "sometimes", "random", "have not tried", "unable to duplicate"] +severities = ["block", "crash", "major", "minor", "tweak", "text", "trivial", "feature"] diff --git a/src/gui/buffers/panels.py b/src/issueReporter/get_logs.py similarity index 56% rename from src/gui/buffers/panels.py rename to src/issueReporter/get_logs.py index f5002612..faad2b02 100644 --- a/src/gui/buffers/panels.py +++ b/src/issueReporter/get_logs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################ -# Copyright (c) 2014 Manuel Eduardo Cortéz Vallejo +# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,22 +16,17 @@ # along with this program. If not, see . # ############################################################ -import wx -from multiplatform_widgets import widgets +import paths +import os -class accountPanel(wx.Panel): - def __init__(self, parent): - super(accountPanel, self).__init__(parent=parent) - self.type = "account" - sizer = wx.BoxSizer(wx.VERTICAL) - self.list = widgets.list(self, _(u"Announce")) - sizer.Add(self.list.list, 0, wx.ALL, 5) - self.SetSizer(sizer) +def get_logs_files(): + files = {} + for i in os.listdir(paths.logs_path()): + if i == "debug.log": continue + f = open(paths.logs_path(i), "r") + files[i] = f.readlines() + f.close() + try: os.remove(paths.logs_path("tracebacks.log")) + except: pass + return files -class emptyPanel(accountPanel): - def __init__(self, parent): - super(emptyPanel, self).__init__(parent=parent) - self.type = "empty" - - def get_more_items(self): - output.speak(_(u"This action is not supported for this buffer")) \ No newline at end of file diff --git a/src/issueReporter/gui.py b/src/issueReporter/gui.py new file mode 100644 index 00000000..a65693ea --- /dev/null +++ b/src/issueReporter/gui.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +############################################################ +# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program. If not, see . +# +############################################################ +import wx +import application +from suds.client import Client +import constants + +class reportBug(wx.Dialog): + def __init__(self, user_name): + self.user = "informador" + self.user_name = user_name + self.password = "contrasena" + self.url = application.report_bugs_url + self.categories = [_(u"General")] + self.reproducibilities = [_(u"always"), _(u"sometimes"), _(u"random"), _(u"have not tried"), _(u"unable to duplicate")] + self.severities = [_(u"block"), _(u"crash"), _(u"major"), _(u"minor"), _(u"tweak"), _(u"text"), _(u"trivial"), _(u"feature")] + wx.Dialog.__init__(self, None, -1) + self.SetTitle(_(u"Report an error")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + categoryLabel = wx.StaticText(panel, -1, _(u"Select a category"), size=wx.DefaultSize) + self.category = wx.ComboBox(panel, -1, choices=self.categories, style=wx.CB_READONLY) + self.category.SetSize(self.category.GetBestSize()) + self.category.SetSelection(0) + categoryB = wx.BoxSizer(wx.HORIZONTAL) + categoryB.Add(categoryLabel, 0, wx.ALL, 5) + categoryB.Add(self.category, 0, wx.ALL, 5) + self.category.SetFocus() + sizer.Add(categoryB, 0, wx.ALL, 5) + summaryLabel = wx.StaticText(panel, -1, _(u"Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize) + self.summary = wx.TextCtrl(panel, -1) + dc = wx.WindowDC(self.summary) + dc.SetFont(self.summary.GetFont()) + self.summary.SetSize(dc.GetTextExtent("a"*80)) +# self.summary.SetFocus() + summaryB = wx.BoxSizer(wx.HORIZONTAL) + summaryB.Add(summaryLabel, 0, wx.ALL, 5) + summaryB.Add(self.summary, 0, wx.ALL, 5) + sizer.Add(summaryB, 0, wx.ALL, 5) + descriptionLabel = wx.StaticText(panel, -1, _(u"Here, you can describe the bug in detail"), size=wx.DefaultSize) + self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) + dc = wx.WindowDC(self.description) + dc.SetFont(self.description.GetFont()) + (x, y, z) = dc.GetMultiLineTextExtent("0"*2000) + self.description.SetSize((x, y)) + descBox = wx.BoxSizer(wx.HORIZONTAL) + descBox.Add(descriptionLabel, 0, wx.ALL, 5) + descBox.Add(self.description, 0, wx.ALL, 5) + sizer.Add(descBox, 0, wx.ALL, 5) + reproducibilityLabel = wx.StaticText(panel, -1, _(u"how often does this bug happen?"), size=wx.DefaultSize) + self.reproducibility = wx.ComboBox(panel, -1, choices=self.reproducibilities, style=wx.CB_READONLY) + self.reproducibility.SetSelection(3) + self.reproducibility.SetSize(self.reproducibility.GetBestSize()) + reprB = wx.BoxSizer(wx.HORIZONTAL) + reprB.Add(reproducibilityLabel, 0, wx.ALL, 5) + reprB.Add(self.reproducibility, 0, wx.ALL, 5) + sizer.Add(reprB, 0, wx.ALL, 5) + severityLabel = wx.StaticText(panel, -1, _(u"Select the importance that you think this bug has")) + self.severity = wx.ComboBox(panel, -1, choices=self.severities, style=wx.CB_READONLY) + self.severity.SetSize(self.severity.GetBestSize()) + self.severity.SetSelection(3) + severityB = wx.BoxSizer(wx.HORIZONTAL) + severityB.Add(severityLabel, 0, wx.ALL, 5) + severityB.Add(self.severity, 0, wx.ALL, 5) + sizer.Add(severityB, 0, wx.ALL, 5) + self.agree = wx.CheckBox(panel, -1, _(u"I know that the TW Blue bug system will get my Twitter username to contact me and fix the bug quickly")) + self.agree.SetValue(False) + sizer.Add(self.agree, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK, _(u"Send report")) + ok.Bind(wx.EVT_BUTTON, self.onSend) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(ok, 0, wx.ALL, 5) + btnBox.Add(cancel, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def onSend(self, ev): + if self.summary.GetValue() == "" or self.description.GetValue() == "": + wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal() + return + if self.agree.GetValue() == False: + wx.MessageDialog(self, _(u"You need to mark the checkbox to provide us your twitter username to contact to you if is necessary."), _(u"Error"), wx.ICON_ERROR).ShowModal() + return + try: + client = Client(self.url) + issue = client.factory.create('IssueData') + issue.project.name = "TW Blue" + issue.project.id = 0 + issue.summary = self.summary.GetValue(), + issue.description = "Reported by @%s\n\n" % (self.user_name) + self.description.GetValue() + issue.category = constants.categories[self.category.GetSelection()] + issue.reproducibility.name = constants.reproducibilities[self.reproducibility.GetSelection()] + issue.severity.name = constants.severities[self.severity.GetSelection()] + issue.priority.name = "normal" + issue.view_state.name = "public" + issue.resolution.name = "open" + issue.projection.name = "none" + issue.eta.name = "eta" + issue.status.name = "new" + id = client.service.mc_issue_add(self.user, self.password, issue) + wx.MessageDialog(self, _(u"Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You've reported the bug number %i") % (id), _(u"reported"), wx.OK).ShowModal() + self.EndModal(wx.ID_OK) + except: + wx.MessageDialog(self, _(u"Something unexpected occurred while trying to report the bug. Please, try again later"), _(u"Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal() + self.EndModal(wx.ID_CANCEL) \ No newline at end of file diff --git a/src/keystrokeEditor/__init__.py b/src/keystrokeEditor/__init__.py index e69de29b..4723bc5b 100644 --- a/src/keystrokeEditor/__init__.py +++ b/src/keystrokeEditor/__init__.py @@ -0,0 +1,3 @@ +import platform +if platform.system() == "Windows": + from wxUI import * \ No newline at end of file diff --git a/src/keystrokeEditor/constants.py b/src/keystrokeEditor/constants.py index 7dd45689..90758294 100644 --- a/src/keystrokeEditor/constants.py +++ b/src/keystrokeEditor/constants.py @@ -41,5 +41,5 @@ actions = { "search": _(u"Search on twitter"), "edit_keystrokes": _(u"Shows the keystroke editor"), "view_user_lists": _(u"Show lists for a specified user"), -"get_more_items": _(u"loads previous items to any buffer"), +"get_more_items": _(u"Loads more items for the current buffer"), } \ No newline at end of file diff --git a/src/keystrokeEditor/gui.py b/src/keystrokeEditor/wxUI.py similarity index 83% rename from src/keystrokeEditor/gui.py rename to src/keystrokeEditor/wxUI.py index de31b762..4e50d8ee 100644 --- a/src/keystrokeEditor/gui.py +++ b/src/keystrokeEditor/wxUI.py @@ -4,13 +4,12 @@ import wx import constants from multiplatform_widgets import widgets from constants import actions +from pubsub import pub class keystrokeEditor(wx.Dialog): - def __init__(self, parent=None, keyboard_handler=None): - super(keystrokeEditor, self).__init__(parent=parent, id=-1, title=_(u"Keystroke editor")) + def __init__(self): + super(keystrokeEditor, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor")) panel = wx.Panel(self) - self.parent = parent - self.keyboard_handler = keyboard_handler or None self.actions = [] sizer = wx.BoxSizer(wx.VERTICAL) keysText = wx.StaticText(panel, -1, _(u"Select a keystroke to edit")) @@ -30,27 +29,20 @@ class keystrokeEditor(wx.Dialog): sizer.Add(firstSizer) sizer.Add(secondSizer) panel.SetSizerAndFit(sizer) - self.put_keystrokes() - def put_keystrokes(self): - for i in config.main["keymap"]: + def put_keystrokes(self, **keystrokes): + for i in keystrokes: action = actions[i] self.actions.append(i) - keystroke = config.main["keymap"][i] + keystroke = keystrokes[i] self.keys.insert_item(False, *[action, keystroke]) def edit(self, ev): action = self.actions[self.keys.get_selected()] - dlg = editKeystroke(self.parent, action, config.main["keymap"][action], self.keyboard_handler) - if dlg.ShowModal() == wx.ID_OK: - pos = self.keys.get_selected() - self.keys.clear() - self.put_keystrokes() - self.keys.select_item(pos) - # dlg.Destroy() + pub.sendMessage("editing_keystroke", action=action, parentDialog=self) class editKeystroke(wx.Dialog): - def __init__(self, parent, action, keystroke, keyboard_handler): + def __init__(self, action, keystroke, keyboard_handler): super(editKeystroke, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke")) self.parent = parent self.keyboard_handler = keyboard_handler diff --git a/src/locales/fi/LC_MESSAGES/twblue.mo b/src/locales/fi/LC_MESSAGES/twblue.mo index 7ab60055b2eab8214e26bc7d50f48bdb211e5286..eba42b7f36169ec99eb3648fdd92a56c1dab1bff 100644 GIT binary patch delta 12941 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 delta 12446 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\n" +"PO-Revision-Date: 2014-11-11 19:16+0200\n" +"Last-Translator: Jani Kinnunen \n" "Language-Team: Jani Kinnunen \n" "Language: fi\n" "MIME-Version: 1.0\n" @@ -750,9 +750,8 @@ msgstr "Yksityisviesti käyttäjälle %s" #: ../src\gui\buffers\base.py:220 ../src\gui\buffers\dm.py:44 #: ../src\gui\buffers\people.py:56 -#, fuzzy msgid "New direct message" -msgstr "Yksityisviesti" +msgstr "Uusi yksityisviesti" #: ../src\gui\buffers\base.py:228 ../src\gui\buffers\events.py:78 msgid "Write the tweet here" @@ -838,9 +837,8 @@ msgid "Mention" msgstr "Mainitse" #: ../src\gui\buffers\people.py:64 -#, fuzzy msgid "Mention to %s" -msgstr "Mainitse kaikille" +msgstr "Maininta käyttäjälle %s" #: ../src\gui\buffers\trends.py:41 ../src\gui\buffers\tweet_searches.py:45 #: ../src\gui\buffers\user_searches.py:56 @@ -853,7 +851,7 @@ msgstr "Kieli" #: ../src\gui\dialogs\configuration.py:53 msgid "ask before exiting TwBlue?" -msgstr "" +msgstr "Kysy vahvistus ennen sulkemista" #: ../src\gui\dialogs\configuration.py:56 msgid "Relative times" @@ -1222,9 +1220,8 @@ msgid "Select a list to remove the user" msgstr "Valitse lista, jolta käyttäjä poistetaan" #: ../src\gui\dialogs\message.py:43 ../src\gui\dialogs\message.py:146 -#, fuzzy msgid "%s - %s of 140 characters" -msgstr "Twiitti - %i merkkiä" +msgstr "%s - %s / 140 merkkiä" #: ../src\gui\dialogs\message.py:77 msgid "Attaching..." @@ -1534,7 +1531,7 @@ msgstr "&Näytä suosikit" #: ../src\gui\main.py:126 msgid "&Load previous items" -msgstr "" +msgstr "&Lataa edelliset kohteet" #: ../src\gui\main.py:130 msgid "&Autoread tweets for this buffer" @@ -1641,9 +1638,8 @@ msgid "%s favourites from %s" msgstr "%s suosikkia käyttäjältä %s" #: ../src\gui\main.py:378 -#, fuzzy msgid "Connection error. Try again later." -msgstr "Valtuutuksessa tapahtui virhe. Yritä myöhemmin uudelleen." +msgstr "Yhteysvirhe. Yritä myöhemmin uudelleen." #: ../src\gui\main.py:421 msgid "Streams disconnected. TW Blue will try to reconnect in a minute." @@ -1687,9 +1683,8 @@ msgid "Exit" msgstr "Lopeta" #: ../src\gui\main.py:587 -#, fuzzy msgid "Exiting..." -msgstr "Lisätään liitettä..." +msgstr "Suljetaan..." #: ../src\gui\main.py:673 msgid "Error while adding to favourites." @@ -1960,7 +1955,7 @@ msgstr "Näytä valitun käyttäjän listat" #: ../src\keystrokeEditor\constants.py:44 msgid "loads previous items to any buffer" -msgstr "" +msgstr "Lataa edelliset kohteet mihin tahansa puskuriin" #: ../src\keystrokeEditor\gui.py:10 msgid "Keystroke editor" diff --git a/src/locales/fr/LC_MESSAGES/twblue.mo b/src/locales/fr/LC_MESSAGES/twblue.mo index bbf28bd16b2831e717ecab808e39462ee1f54466..d00c3911f6bfe8a626e3ae24c72fc7e3ce52bdd8 100644 GIT binary patch delta 12985 zcmZ|V2Xs|czQ^&CKuAIj384orDTEpz^j-qemEK#*4Fp00Hwi_`Rf;H5#E4Q5z=oe za6E)HuzCx}sfx)M?Kpm?F9pVQCZZnfLp^XlR={Pbxva(N_&Ubo2~5Nr*Z}J!yY@y+ zUW0gFIfFmtVsR`MqqeLw|`9xA&*53*Z|e9 zHCDl%);`+WCt7

N)eU65~57C}?Y+L`~#5)KVFCK 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 delta 12488 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\n" +"PO-Revision-Date: 2014-11-11 15:45+0100\n" +"Last-Translator: Rémy Ruiz \n" "Language-Team: Rémy Ruiz \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.6.10\n" +"X-Generator: Poedit 1.6.8\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop\n" "X-Poedit-Basepath: .\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -752,9 +752,8 @@ msgstr "Message direct à %s" #: ../src\gui\buffers\base.py:220 ../src\gui\buffers\dm.py:44 #: ../src\gui\buffers\people.py:56 -#, fuzzy msgid "New direct message" -msgstr "Un message direct" +msgstr "Nouveau message direct" #: ../src\gui\buffers\base.py:228 ../src\gui\buffers\events.py:78 msgid "Write the tweet here" @@ -854,7 +853,7 @@ msgstr "Langue" #: ../src\gui\dialogs\configuration.py:53 msgid "ask before exiting TwBlue?" -msgstr "" +msgstr "demander avant de sortir de TwBlue ?" #: ../src\gui\dialogs\configuration.py:56 msgid "Relative times" @@ -1227,9 +1226,8 @@ msgid "Select a list to remove the user" msgstr "Sélectionnez une liste pour supprimer l'utilisateur" #: ../src\gui\dialogs\message.py:43 ../src\gui\dialogs\message.py:146 -#, fuzzy msgid "%s - %s of 140 characters" -msgstr "Tweet - %i caractères" +msgstr "%s - %s de 140 caractères" #: ../src\gui\dialogs\message.py:77 msgid "Attaching..." @@ -1539,7 +1537,7 @@ msgstr "V&oir favoris" #: ../src\gui\main.py:126 msgid "&Load previous items" -msgstr "" +msgstr "&Charger les éléments précédents" #: ../src\gui\main.py:130 msgid "&Autoread tweets for this buffer" @@ -1646,9 +1644,8 @@ msgid "%s favourites from %s" msgstr "%s favoris de %s" #: ../src\gui\main.py:378 -#, fuzzy msgid "Connection error. Try again later." -msgstr "Erreur pendant l'autorisation. Réessayez plus tard." +msgstr "Erreur pendant la connexion. Réessayez plus tard." #: ../src\gui\main.py:421 msgid "Streams disconnected. TW Blue will try to reconnect in a minute." @@ -1691,9 +1688,8 @@ msgid "Exit" msgstr "Sortir" #: ../src\gui\main.py:587 -#, fuzzy msgid "Exiting..." -msgstr "Ajout en cours..." +msgstr "Sortie en cours..." #: ../src\gui\main.py:673 msgid "Error while adding to favourites." @@ -1972,7 +1968,7 @@ msgstr "Afficher les listes d'un utilisateur spécifié" #: ../src\keystrokeEditor\constants.py:44 msgid "loads previous items to any buffer" -msgstr "" +msgstr "chargez les éléments précédents à n'importe quel tampon" #: ../src\keystrokeEditor\gui.py:10 msgid "Keystroke editor" diff --git a/src/locales/it/LC_MESSAGES/twblue.mo b/src/locales/it/LC_MESSAGES/twblue.mo index cb6bec9f21eb2e1f7e2ee36847afd6772294c6b7..f0992e3884485db88a2f98a3213f72b089af0bb6 100644 GIT binary patch delta 13275 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

~G{&xszyQ6iNIRHOV(;u86?YpSK&Grn_x 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\n" +"PO-Revision-Date: 2014-11-12 12:03+0100\n" +"Last-Translator: Chris Leo Mameli \n" "Language-Team: Manuel Cortez \n" "Language: it\n" "MIME-Version: 1.0\n" @@ -13,7 +13,7 @@ msgstr "" "X-Poedit-Basepath: .\n" "X-Poedit-SourceCharset: UTF-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.6.10\n" +"X-Generator: Poedit 1.6.3\n" #: ../src\extra\AudioUploader\gui.py:31 ../src\gui\dialogs\message.py:173 #: ../src\gui\dialogs\message.py:261 @@ -752,9 +752,8 @@ msgstr "Messaggio diretto a %s" #: ../src\gui\buffers\base.py:220 ../src\gui\buffers\dm.py:44 #: ../src\gui\buffers\people.py:56 -#, fuzzy msgid "New direct message" -msgstr "Un messaggio diretto" +msgstr "Nuovo messaggio diretto" #: ../src\gui\buffers\base.py:228 ../src\gui\buffers\events.py:78 msgid "Write the tweet here" @@ -854,11 +853,11 @@ msgstr "Lingua" #: ../src\gui\dialogs\configuration.py:53 msgid "ask before exiting TwBlue?" -msgstr "" +msgstr "Richiedere conferma prima di uscire da TwBlue?" #: ../src\gui\dialogs\configuration.py:56 msgid "Relative times" -msgstr "Relative times" +msgstr "Mostra tempo di ricezione trascorso" #: ../src\gui\dialogs\configuration.py:60 msgid "Activate Sapi5 when any other screen reader is not being run" @@ -885,8 +884,8 @@ msgid "" "Inverted buffers: The newest tweets will be shown at the beginning of the " "lists while the oldest at the end" msgstr "" -"Elenco invertito: I più nuovi tweets verranno mostrate all'inizio delle " -"liste, mentre il più antico alla fine" +"Inverti elenco: I nuovi tweets verranno mostrate in cima all'elenco, i " +"precedenti alla fine" #: ../src\gui\dialogs\configuration.py:97 msgid "Show followers" @@ -1224,9 +1223,8 @@ msgid "Select a list to remove the user" msgstr "Seleziona una lista per rimuovere l'utente" #: ../src\gui\dialogs\message.py:43 ../src\gui\dialogs\message.py:146 -#, fuzzy msgid "%s - %s of 140 characters" -msgstr "Tweet -% i caratteri " +msgstr "%s - %s di 140 caratteri" #: ../src\gui\dialogs\message.py:77 msgid "Attaching..." @@ -1440,7 +1438,7 @@ msgstr "&Tutorial dei suoni" #: ../src\gui\main.py:69 msgid "&Edit keystrokes" -msgstr "&Modifica" +msgstr "&Modifica comandi" #: ../src\gui\main.py:71 msgid "&Preferences" @@ -1536,7 +1534,7 @@ msgstr "Visualizza &preferiti" #: ../src\gui\main.py:126 msgid "&Load previous items" -msgstr "" +msgstr "&Carica le voci precedenti" #: ../src\gui\main.py:130 msgid "&Autoread tweets for this buffer" @@ -1643,9 +1641,8 @@ msgid "%s favourites from %s" msgstr "%s preferiti da %s" #: ../src\gui\main.py:378 -#, fuzzy msgid "Connection error. Try again later." -msgstr "Errore durante l'autorizzazione. Riprovare più tardi." +msgstr "Errore durante la connessione. Riprovare più tardi." #: ../src\gui\main.py:421 msgid "Streams disconnected. TW Blue will try to reconnect in a minute." @@ -1688,9 +1685,8 @@ msgid "Exit" msgstr "Esci" #: ../src\gui\main.py:587 -#, fuzzy msgid "Exiting..." -msgstr "Allegando..." +msgstr "Chiusura in corso..." #: ../src\gui\main.py:673 msgid "Error while adding to favourites." @@ -1850,7 +1846,7 @@ msgstr "Rimuovi dai favoriti" #: ../src\keystrokeEditor\constants.py:17 msgid "Open the actions dialogue" -msgstr "Open the actions dialogue" +msgstr "Apre una finestra per selezionare un'azione" #: ../src\keystrokeEditor\constants.py:18 msgid "See user details" @@ -1924,7 +1920,7 @@ msgstr "Ascolta il messaggio corrente" #: ../src\keystrokeEditor\constants.py:35 msgid "Copy to clipboard" -msgstr "Copiato negli appunti" +msgstr "Copia negli appunti" #: ../src\keystrokeEditor\constants.py:36 msgid "Add to list" @@ -1936,7 +1932,7 @@ msgstr "Rimuovi dalla lista" #: ../src\keystrokeEditor\constants.py:38 msgid "Mutes/unmutes the active buffer" -msgstr "Mutes/unmutes the active buffer" +msgstr "Mutes/unmutes il buffer corrente" #: ../src\keystrokeEditor\constants.py:39 msgid "Globally mute/unmute TW Blue" @@ -1962,7 +1958,7 @@ msgstr "Mostra le liste di un utente" #: ../src\keystrokeEditor\constants.py:44 msgid "loads previous items to any buffer" -msgstr "" +msgstr "Carica voci precedenti per tutti i buffer" #: ../src\keystrokeEditor\gui.py:10 msgid "Keystroke editor" @@ -1970,7 +1966,7 @@ msgstr "Modifica comando" #: ../src\keystrokeEditor\gui.py:16 msgid "Select a keystroke to edit" -msgstr "Select a keystroke to edit" +msgstr "Seleziona il comando da modificare:" #: ../src\keystrokeEditor\gui.py:17 msgid "Keystroke" @@ -1978,11 +1974,11 @@ msgstr "Comando" #: ../src\keystrokeEditor\gui.py:54 msgid "Editing keystroke" -msgstr "Editing keystroke" +msgstr "Modifica comando" #: ../src\keystrokeEditor\gui.py:61 msgid "Control" -msgstr "Comandi" +msgstr "Control" #: ../src\keystrokeEditor\gui.py:62 msgid "Alt" diff --git a/src/main.py b/src/main.py index d00f891f..f472b14a 100644 --- a/src/main.py +++ b/src/main.py @@ -1,81 +1,29 @@ # -*- coding: utf-8 -*- -""" TW Blue - -A twitter accessible, easy of use and cross platform application.""" -############################################################ -# Copyright(C)2013-2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ +import languageHandler import wx - -ssmg = None -import gui import paths -import config import commandline -import platform -if platform.system() == "Windows": - from logger import logger as logging -if platform.system() == "Darwin": - import osx_prepare - osx_prepare.setup() -from sessionmanager import manager -from sessionmanager import gui as smGUI -manager.setup() -import sys +import config +import sound +import output -if hasattr(sys, 'frozen'): - sys.stderr = open(paths.logs_path("stderr.log"), 'w') - sys.stdout = open(paths.logs_path("stdout.log"), 'w') - -class app(wx.App): - def __init__(self, *args, **kwargs): - super(app, self).__init__(*args, **kwargs) - if platform.system() != "Darwin": - self.start() - else: - self.mac() - - def mac(self): - self.hold_frame = wx.Frame(title="None", parent=None) - self.hold_frame.Show() - wx.CallLater(10, self.start) - - def start(self): - ssmg = smGUI.sessionManagerWindow() - if ssmg.ShowModal() == wx.ID_OK: - frame = gui.main.mainFrame() - frame.Show() - frame.showing = True - if config.main != None and config.main["general"]["hide_gui"] == True and platform.system() == "Windows": - frame.show_hide() - frame.Hide() - self.SetTopWindow(frame) - if hasattr(self, "frame"): self.hold_frame.Hide() - # If the user press on cancel. - else: - self.Exit() - -ap = app() - ### I should uncomment this -#if platform.system() != "Windows": -# local = wx.Locale(wx.LANGUAGE_DEFAULT) -# local.AddCatalogLookupPathPrefix(paths.locale_path()) -# local.AddCatalog("twblue") -#ap = app(redirect=True, useBestVisual=True, filename=paths.logs_path('tracebacks.log')) -#wx.CallLater(10, start) -ap.MainLoop() +def setup(): + config.setup() + sound.setup() + output.setup() + languageHandler.setLanguage(config.app["app-settings"]["language"]) + from controller import mainController + from sessionmanager import sessionManager + app = wx.App() + sm = sessionManager.sessionManagerController() + sm.fill_list() + if len(sm.sessions) == 0: sm.show() + else: + sm.do_ok() + del sm + r = mainController.Controller() + r.view.Show() + sound.player.play("ready.ogg") + app.MainLoop() +setup() \ No newline at end of file diff --git a/src/mysc/event.py b/src/mysc/event.py deleted file mode 100644 index acc67777..00000000 --- a/src/mysc/event.py +++ /dev/null @@ -1,41 +0,0 @@ -# -- coding: utf-8 -*- -from wx.lib.newevent import NewEvent -import wx -EVT_DELETED = wx.NewEventType() -MyEVT_DELETED = wx.PyEventBinder(EVT_DELETED, 1) -EVT_STARTED = wx.NewEventType() -MyEVT_STARTED = wx.PyEventBinder(EVT_STARTED, 1) -EVT_OBJECT = wx.NewEventType() -MyEVT_OBJECT = wx.PyEventBinder(EVT_OBJECT, 1) - -ResultEvent, EVT_RESULT = NewEvent() -#DeletedEvent, EVT_DELETED = NewEvent() - -class event(wx.PyCommandEvent): - def __init__(self, evtType, id): - self.text = "" - wx.PyCommandEvent.__init__(self, evtType, id) - - def SetItem(self, item): - self.item = item - - def GetItem(self): - return self.item - - def SetAnnounce(self, text ): - self.text = text - - def GetAnnounce(self): - try: return self.text - except: pass - -class infoEvent(event): - def __init__(self, evtType, id): - event.__init__(self, evtType, id) - - def SetItem(self, page, items): - self.page = page - self.items = items - - def GetItem(self): - return [self.page, self.items] \ No newline at end of file diff --git a/src/mysc/paths.py b/src/mysc/paths.py deleted file mode 100644 index c48623cf..00000000 --- a/src/mysc/paths.py +++ /dev/null @@ -1,38 +0,0 @@ -import platform -import os -import sys - -from functools import wraps - -def merge_paths(func): - @wraps(func) - def merge_paths_wrapper(*a): - return unicode(os.path.join(func(), *a)) - return merge_paths_wrapper - -@merge_paths -def app_path(): - if hasattr(sys, "frozen"): - from win32api import GetModuleFileName #We should only be here if using py2exe hence windows - app_path = os.path.dirname(GetModuleFileName(0)) - else: - app_path = os.path.normpath(os.path.dirname(__file__)) - return app_path - -@merge_paths -def config_path(): - path = app_path(u"config") - if not os.path.exists(path): - os.mkdir(path) - return path - -@merge_paths -def data_path(app_name='Blu JM'): -# if platform.system() == "Windows": -# import shlobj -# data_path = os.path.join(shlobj.SHGetFolderPath(0, shlobj.CSIDL_APPDATA), app_name) -# else: - data_path = os.path.join(os.environ['HOME'], ".%s" % app_name) - if not os.path.exists(data_path): - os.mkdir(data_path) - return data_path diff --git a/src/mysc/repeating_timer.py b/src/mysc/repeating_timer.py index e634f344..8c304681 100644 --- a/src/mysc/repeating_timer.py +++ b/src/mysc/repeating_timer.py @@ -27,8 +27,8 @@ class RepeatingTimer(threading.Thread): while not self.finished.is_set(): self.finished.wait(self.interval) if not self.finished.is_set(): #In case someone has canceled while waiting - try: - self.function(*self.args, **self.kwargs) - except: - pass +# try: + self.function(*self.args, **self.kwargs) +# except: +# pass # logging.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs)) diff --git a/src/sessionmanager/__init__.py b/src/sessionmanager/__init__.py index 01e76232..e89280a3 100644 --- a/src/sessionmanager/__init__.py +++ b/src/sessionmanager/__init__.py @@ -1 +1,9 @@ -# -*- coding: cp1252 -*- +# -*- coding: utf-8 -*- +""" Module to manage sessions. It can create and configure all sessions. + +Contents of this package: + wxUI: The graphical user interface written in WX Python (for windows). The view. + session_exceptions: Some useful exceptions when there is an error. + manager: Handles multiple sessions, setting the configuration files and check if the session is valid. Part of the model. + session: Creates a twitter session for an user. The other part of the model. +""" \ No newline at end of file diff --git a/src/sessionmanager/gui.py b/src/sessionmanager/gui.py deleted file mode 100644 index 3407c5f7..00000000 --- a/src/sessionmanager/gui.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -import time -import wx -import manager -import session_exceptions -import paths -import config -import sound -import languageHandler -import output -import os -import twitter -import webbrowser -from multiplatform_widgets import widgets -from config_utils import Configuration - -class sessionManagerWindow(wx.Dialog): - def __init__(self): - super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize) -# panelSizer = wx.BoxSizer(wx.VERTICAL) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(panel, -1, _(u"Select a twitter account to start TW Blue"), size=wx.DefaultSize) - listSizer = wx.BoxSizer(wx.HORIZONTAL) - self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) - self.fill_list() - listSizer.Add(label, 0, wx.ALL, 5) - listSizer.Add(self.list.list, 0, wx.ALL, 5) - sizer.Add(listSizer, 0, wx.ALL, 5) - new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize) - new.Bind(wx.EVT_BUTTON, self.new_account) - ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize) - ok.SetDefault() - ok.Bind(wx.EVT_BUTTON, self.ok) - cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize) - buttons = wx.BoxSizer(wx.HORIZONTAL) - buttons.Add(new, 0, wx.ALL, 5) - buttons.Add(ok, 0, wx.ALL, 5) - buttons.Add(cancel, 0, wx.ALL, 5) - sizer.Add(buttons, 0, wx.ALL, 5) - panel.SetSizer(sizer) -# sizer.Layout() -# self.Fit() -# self.SetSize(panel.GetBestSize()) -# panelSizer.Add(panel) -# self.SetSizerAndFit(sizer) -# sizer.Layout() - min = sizer.CalcMin() - self.SetClientSize(min) - - def fill_list(self): - self.sessions = [] - for i in os.listdir(paths.config_path()): - if os.path.isdir(paths.config_path(i)): - strconfig = "%s/session.conf" % (paths.config_path(i)) - config_test = Configuration(strconfig) - name = config_test["twitter"]["user_name"] - if name != "" and config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "": - self.list.insert_item(False, name) - self.sessions.append(i) - if self.list.get_count() > 0: - self.list.select_item(0) - self.list.list.SetSize(self.list.list.GetBestSize()) - - def ok(self, ev): - if self.list.get_count() == 0: - wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal() - return - current_session = self.sessions[self.list.get_selected()] - manager.manager.set_current_session(current_session) - config.MAINFILE = "%s/session.conf" % (manager.manager.get_current_session()) - config.setup() - lang=config.main['general']['language'] - languageHandler.setLanguage(lang) - sound.setup() - output.setup() -# else: -# self.name = current_session - self.EndModal(wx.ID_OK) - - def new_account(self, ev): - twitter_object = twitter.twitter.twitter() - dlg = wx.MessageDialog(self, _(u"The request for the required Twitter authorization to continue will be opened on your browser. You only need to do it once. Would you like to autorhise a new account now?"), _(u"Authorisation"), wx.YES_NO) - if dlg.ShowModal() == wx.ID_NO: - return - else: - location = (str(time.time())[:12]) - manager.manager.add_session(location) - config.MAINFILE = "%s/session.conf" % (location,) - config.setup() - try: - twitter_object.authorise() - except: - wx.MessageDialog(None, _(u"Your access token is invalid or the authorisation has failed. Please try again."), _(u"Invalid user token"), wx.ICON_ERROR).ShowModal() - return - total = self.list.get_count() - name = _(u"Authorised account %d") % (total+1) - self.list.insert_item(False, name) - if self.list.get_count() == 1: - self.list.select_item(0) - self.sessions.append(location) diff --git a/src/sessionmanager/manager.py b/src/sessionmanager/manager.py index 8259a58c..7adb9a4a 100644 --- a/src/sessionmanager/manager.py +++ b/src/sessionmanager/manager.py @@ -1,5 +1,6 @@ # -*- coding: cp1252 -*- -from config_utils import Configuration, ConfigurationResetException +#from config_utils import Configuration, ConfigurationResetException +import config import paths import os import session_exceptions @@ -10,17 +11,17 @@ def setup(): manager = sessionManager() class sessionManager(object): - def __init__(self): - FILE = "sessions.conf" - SPEC = "sessions.defaults" - try: - self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC)) - except ConfigurationResetException: - pass +# def __init__(self): +# FILE = "sessions.conf" +# SPEC = "app-configuration.defaults" +# try: +# self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC)) +# except ConfigurationResetException: +# pass def get_current_session(self): - if self.is_valid(self.main["sessions"]["current_session"]): - return self.main["sessions"]["current_session"] + if self.is_valid(config.app["sessions"]["current_session"]): + return config.app["sessions"]["current_session"] else: return False @@ -28,16 +29,16 @@ class sessionManager(object): path = paths.config_path(id) if not os.path.exists(path): os.mkdir(path) - self.main["sessions"]["sessions"].append(id) + config.app["sessions"]["sessions"].append(id) def set_current_session(self, sessionID): - self.main["sessions"]["current_session"] = sessionID - self.main.write() + config.app["sessions"]["current_session"] = sessionID + config.app.write() def is_valid(self, id): if not os.path.exists(paths.config_path(id)): raise session_exceptions.NonExistentSessionError("That session does not exist.") - self.main["sessions"]["current_session"] = "" + config.app["sessions"]["current_session"] = "" return False else: return True \ No newline at end of file diff --git a/src/sessionmanager/session.py b/src/sessionmanager/session.py new file mode 100644 index 00000000..d77cc807 --- /dev/null +++ b/src/sessionmanager/session.py @@ -0,0 +1,269 @@ +# -*- coding: utf-8 -*- +""" The main session object. Here are the twitter functions to interact with the "model" of TWBlue.""" +import twitter +import application +import db +import session_exceptions as Exceptions +import paths +import output +import time +import sound +from twitter import utils +from twython import TwythonError, TwythonRateLimitError, TwythonAuthError +from config_utils import Configuration, ConfigurationResetException +from mysc.thread_utils import call_threaded + +sessions = {} + +class Session(object): + """ A session object where we will save configuration, the twitter object and a local storage for saving the items retrieved through the Twitter API methods""" + + # Decorators. + + def _require_login(fn): + + """ Decorator for checking if the user is logged (a twitter object has credentials) on twitter. + Some functions may need this to avoid make unneeded twitter API calls.""" + + def f(self, *args, **kwargs): + if self.logged == True: + fn(self, *args, **kwargs) + else: + raise Exceptions.NotLoggedSessionError("You are not logged yet.") + return f + + def _require_configuration(fn): + + """ Check if the user has a configured session.""" + + def f(self, *args, **kwargs): + if self.settings != None: + fn(self, *args, **kwargs) + else: + raise Exceptions.NotConfiguredSessionError("Not configured.") + return f + + def order_buffer(self, name, data): + + """ Put the new items on the local database. + name str: The name for the buffer stored in the dictionary. + data list: A list with tweets. + returns the number of items that has been added in this execution""" + + num = 0 + if self.db.has_key(name) == False: + self.db[name] = [] + for i in data: + if utils.find_item(i["id"], self.db[name]) == None: + if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) + else: self.db[name].insert(0, i) + num = num+1 + return num + + def order_cursored_buffer(self, name, data): + + """ Put the new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches) + name str: The name for the buffer stored in the dictionary. + data list: A list with items and some information about cursors. + returns the number of items that has been added in this execution""" + + num = 0 + if self.db.has_key(name) == False: + self.db[name] = {} + self.db[name]["items"] = [] +# if len(self.db[name]["items"]) > 0: + for i in data: + if utils.find_item(i["id"], self.db[name]["items"]) == None: + if self.settings["general"]["reverse_timelines"] == False: self.db[name]["items"].append(i) + else: self.db[name]["items"].insert(0, i) + num = num+1 + return num + + def __init__(self, session_id): + + """ session_id (str): The name of the folder inside the config directory where the session is located.""" + + super(Session, self).__init__() + self.session_id = session_id + self.logged = False + self.settings = None + self.twitter = twitter.twitter.twitter() + self.db = {} + + def get_configuration(self): + + """ Gets settings for a session.""" + + file_ = "%s/session.conf" % (self.session_id,) + try: + self.settings = Configuration(paths.config_path(file_), paths.app_path("Conf.defaults")) + except: + self.settings = None + + @_require_configuration + def login(self): + + """ Login into twitter using credentials from settings. + if the user account isn't authorised, it needs to call self.authorise() before login.""" + + if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None: + self.twitter.login(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"]) + self.logged = True + else: + self.logged = False + raise Exceptions.RequireCredentialsSessionError + + @_require_configuration + def authorise(self): + + """ Authorises a Twitter account. This function needs to be called for each new session, after of self.get_configuration() and before of self.login()""" + + if self.logged == True: + raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.") + else: + self.twitter.authorise(self.settings) + + def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): + + """ Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call to the method at least 25 times, waiting a while between calls. Useful for post methods. + If twitter returns an error, it will not call anymore the method. + call_name str: The method to call + action str: The thing what you are doing on twitter, it will be reported to the user if report_success is set to True. + for example "following @tw_blue2" will be reported as "following @tw_blue2 succeeded". + _sound str: a sound to play if the call is executed properly. + report_success and report_failure bool: These are self explanatory. True or false. It's all. + preexec_message str: A message to speak to the user while the call is doing the work, example: "try to follow to x user".""" + + finished = False + tries = 0 + if preexec_message: + output.speak(preexec_message, True) + while finished==False and tries < 25: + try: + val = getattr(self.twitter.twitter, call_name)(*args, **kwargs) + finished = True + except TwythonError as e: + output.speak(e.message) + if report_failure and hasattr(e, 'message'): + output.speak(_("%s failed. Reason: %s") % (action, e.message)) + finished = True + except: + tries = tries + 1 + time.sleep(5) + if report_success: + output.speak(_("%s succeeded.") % action) + if _sound != None: sound.player.play(_sound) + + @_require_login + def get_favourites_timeline(self, name, *args, **kwargs): + + """ Gets favourites for the authenticated user or a friend or follower or somewhat. + name str: Name for store all in the database.""" + + tl = self.call_paged(self.twitter.twitter.get_favorites, *args, **kwargs) + return self.order_buffer(name, tl) + + def call_paged(self, update_function, *args, **kwargs): + + """ Makes a call to the Twitter API methods several times. Useful for get methods. + this function is needed for retrieving more than 200 items. + update_function str: The function to call. This function must be child of self.twitter.twitter + return a list with all items retrieved.""" + + max = int(self.settings["general"]["max_api_calls"])-1 + results = [] + data = getattr(self.twitter.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + results.extend(data) + for i in range(0, max): + if i == 0: max_id = results[-1]["id"] + else: max_id = results[0]["id"] + data = update_function(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + results.extend(data) + results.reverse() + return results + + @_require_login + def get_user_info(self): + + """ Retrieves some information required by TWBlue for setup.""" + + f = self.twitter.twitter.get_account_settings() + sn = f["screen_name"] + self.db["user_name"] = sn + self.db["user_id"] = self.twitter.twitter.show_user(screen_name=sn)["id_str"] + try: + self.db["utc_offset"] = f["time_zone"]["utc_offset"] + except KeyError: + self.db["utc_offset"] = -time.timezone + self.get_lists() + self.get_muted_users() + self.settings.write() + + @_require_login + def get_lists(self): + + """ Gets the lists that the user is suscribed.""" + + self.db["lists"] = self.twitter.twitter.show_lists(reverse=True) + + @_require_login + def get_muted_users(self): + + """ Gets muted users (oh really?).""" + + self.db["muted_users"] = self.twitter.twitter.get_muted_users_ids()["ids"] + + @_require_login + def get_stream(self, name, function, *args, **kwargs): + + """ Retrieves the items for a regular stream. + name str: Name to save items on the database. + function str: A function to get the items.""" + + last_id = -1 + if self.db.has_key(name): + try: + if self.db[name][0]["id"] > self.db[name][-1]["id"]: + last_id = self.db[name][0]["id"] + else: + last_id = self.db[name][-1]["id"] + except IndexError: + pass + tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs) + self.order_buffer(name, tl) + + @_require_login + def get_cursored_stream(self, name, function, items="users", *args, **kwargs): + + """ Gets items for API calls that requires using cursors to paginate the results. + name str: Name to save it in the database. + function str: Function that provides the items. + items: When the function returns the list with results, items will tell how the order function should be look. + for example get_followers_list returns a list and users are under list["users"], here the items should be point to "users".""" + + items_ = [] + try: + if self.db[name].has_key("next_cursor"): + next_cursor = self.db[name]["next_cursor"] + else: + next_cursor = -1 + except KeyError: + next_cursor = -1 + tl = getattr(self.twitter.twitter, function)(cursor=next_cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + tl[items].reverse() + num = self.order_cursored_buffer(name, tl[items]) + self.db[name]["next_cursor"] = tl["next_cursor"] + return num + + def start_streaming(self): + + """ Start the streaming for sending tweets in realtime.""" + self.main_stream = twitter.buffers.stream.streamer(application.app_key, application.app_secret, self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], self) + call_threaded(self.main_stream.user) + self.timelinesStream = twitter.buffers.indibidual.timelinesStreamer(application.app_key, application.app_secret, self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], session=self) + ids = "" + for i in self.settings["other_buffers"]["timelines"]: + ids = ids + "%s, " % (self.db[i+"-timeline"][0]["user"]["id_str"]) + # if ids != "": + call_threaded(self.timelinesStream.statuses.filter, follow=ids) + \ No newline at end of file diff --git a/src/sessionmanager/sessionManager.py b/src/sessionmanager/sessionManager.py new file mode 100644 index 00000000..0aa901f3 --- /dev/null +++ b/src/sessionmanager/sessionManager.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +import wx +import wxUI as view +import paths +import time +import os +import session +import manager +from config_utils import Configuration + +class sessionManagerController(object): + def __init__(self): + super(sessionManagerController, self).__init__() + manager.setup() + + def fill_list(self): + sessionsList = [] + self.sessions = [] + for i in os.listdir(paths.config_path()): + if os.path.isdir(paths.config_path(i)): + strconfig = "%s/session.conf" % (paths.config_path(i)) + config_test = Configuration(strconfig) + name = config_test["twitter"]["user_name"] + if name != "" and config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "": + sessionsList.append(name) + self.sessions.append(i) + if hasattr(self, "view"): self.view.fill_list(sessionsList) + + def show(self): + self.view = view.sessionManagerWindow(self) + if self.view.ShowModal() == wx.ID_CANCEL: + self.view.Destroy() + + def do_ok(self): + for i in self.sessions: + s = session.Session(i) + s.get_configuration() + s.login() + session.sessions[i] = s + + def manage_new_account(self): + location = (str(time.time())[:6]) + s = session.Session(location) + manager.manager.add_session(location) + s.get_configuration() + try: + s.authorise() + self.sessions.append(location) + self.view.add_new_session_to_list() + except: + self.view.show_unauthorised_error() + return \ No newline at end of file diff --git a/src/sessionmanager/session_exceptions.py b/src/sessionmanager/session_exceptions.py index 6a6502f1..fd7cfc79 100644 --- a/src/sessionmanager/session_exceptions.py +++ b/src/sessionmanager/session_exceptions.py @@ -3,3 +3,7 @@ import exceptions class InvalidSessionError(exceptions.Exception): pass class NonExistentSessionError(exceptions.Exception): pass +class NotLoggedSessionError(exceptions.BaseException): pass +class NotConfiguredSessionError(exceptions.BaseException): pass +class RequireCredentialsSessionError(exceptions.BaseException): pass +class AlreadyAuthorisedError(exceptions.BaseException): pass \ No newline at end of file diff --git a/src/sessionmanager/wxUI.py b/src/sessionmanager/wxUI.py new file mode 100644 index 00000000..a61808f9 --- /dev/null +++ b/src/sessionmanager/wxUI.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +import wx +from multiplatform_widgets import widgets + +class sessionManagerWindow(wx.Dialog): + def __init__(self, controller): + super(sessionManagerWindow, self).__init__(parent=None, title="Session manager", size=wx.DefaultSize) + self.controller = controller + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(panel, -1, u"Select a twitter account to start TW Blue", size=wx.DefaultSize) + listSizer = wx.BoxSizer(wx.HORIZONTAL) + self.list = widgets.list(panel, u"Account", style=wx.LC_SINGLE_SEL|wx.LC_REPORT) + listSizer.Add(label, 0, wx.ALL, 5) + listSizer.Add(self.list.list, 0, wx.ALL, 5) + sizer.Add(listSizer, 0, wx.ALL, 5) + new = wx.Button(panel, -1, u"New account", size=wx.DefaultSize) + new.Bind(wx.EVT_BUTTON, self.new_account) + ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize) + ok.SetDefault() + ok.Bind(wx.EVT_BUTTON, self.ok) + cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize) + buttons = wx.BoxSizer(wx.HORIZONTAL) + buttons.Add(new, 0, wx.ALL, 5) + buttons.Add(ok, 0, wx.ALL, 5) + buttons.Add(cancel, 0, wx.ALL, 5) + sizer.Add(buttons, 0, wx.ALL, 5) + panel.SetSizer(sizer) + min = sizer.CalcMin() + self.SetClientSize(min) + + def fill_list(self, sessionsList): + for i in sessionsList: + self.list.insert_item(False, i) + if self.list.get_count() > 0: + self.list.select_item(0) + self.list.list.SetSize(self.list.list.GetBestSize()) + + def ok(self, ev): + if self.list.get_count() == 0: + wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal() + return + self.controller.do_ok() + self.EndModal(wx.ID_OK) + + def new_account(self, ev): + dlg = wx.MessageDialog(self, _(u"The request for the required Twitter authorization to continue will be opened on your browser. You only need to do it once. Would you like to autorhise a new account now?"), _(u"Authorisation"), wx.YES_NO) + if dlg.ShowModal() == wx.ID_NO: + return + else: + self.controller.manage_new_account() + + def add_new_session_to_list(self): + total = self.list.get_count() + name = _(u"Authorised account %d") % (total+1) + self.list.insert_item(False, name) + if self.list.get_count() == 1: + self.list.select_item(0) + def show_unauthorised_error(self): + wx.MessageDialog(None, _(u"Your access token is invalid or the authorisation has failed. Please try again."), _(u"Invalid user token"), wx.ICON_ERROR).ShowModal() \ No newline at end of file diff --git a/src/sessions.defaults b/src/sessions.defaults deleted file mode 100644 index 18e2f81c..00000000 --- a/src/sessions.defaults +++ /dev/null @@ -1,3 +0,0 @@ -[sessions] -current_session = string(default="") -sessions = list(default=list()) \ No newline at end of file diff --git a/src/sound.py b/src/sound.py index 4fb0a7a1..9bc87ddb 100644 --- a/src/sound.py +++ b/src/sound.py @@ -1,22 +1,4 @@ # -*- coding: utf-8 -*- -""" Sound utilities.""" -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ import sys import url_shortener import audio_services @@ -28,15 +10,18 @@ import paths import sound_lib import subprocess import platform +import output system = platform.system() from mysc.repeating_timer import RepeatingTimer -player = None +player = URLPlayer = None def setup(): - global player + global player, URLPlayer if not player: player = soundSystem() + if not URLPlayer: + URLPlayer = URLStream() def recode_audio(filename, quality=4.5): global system @@ -55,8 +40,8 @@ class soundSystem(object): def check_soundpack(self): """ Checks if the folder where live the current soundpack exists.""" self.soundpack_OK = False - if os.path.exists(paths.sound_path(config.main["sound"]["current_soundpack"])): - self.path = paths.sound_path(config.main["sound"]["current_soundpack"]) + if os.path.exists(paths.sound_path(config.app["app-settings"]["current_soundpack"])): + self.path = paths.sound_path(config.app["app-settings"]["current_soundpack"]) self.soundpack_OK = True elif os.path.exists(paths.sound_path("default")): self.path = paths.sound_path("default") @@ -71,11 +56,11 @@ class soundSystem(object): self.input = sound_lib.input.Input() # Try to use the selected device from the configuration. It can fail if the machine does not has a mic. try: - self.output.set_device(self.output.find_device_by_name(config.main["sound"]["output_device"])) - self.input.set_device(self.input.find_device_by_name(config.main["sound"]["input_device"])) + self.output.set_device(self.output.find_device_by_name(config.app["app-settings"]["output_device"])) + self.input.set_device(self.input.find_device_by_name(config.app["app-settings"]["input_device"])) except: - config.main["sound"]["output_device"] = "Default" - config.main["sound"]["input_device"] = "Default" + config.app["app-settings"]["output_device"] = "Default" + config.app["app-settings"]["input_device"] = "Default" self.files = [] self.cleaner = RepeatingTimer(60, self.clear_list) @@ -84,42 +69,49 @@ class soundSystem(object): def clear_list(self): log.debug("Cleaning sounds... Total sounds found: %i" % len(self.files)) - if self.files == []: return - for i in xrange(0, len(self.files)): - if self.files[i].is_playing == False: - self.files[i].free() - self.files.pop(i) + if len(self.files) == 0: return + try: + for i in range(0, len(self.files)): + if self.files[i].is_playing == False: + self.files[i].free() + self.files.pop(i) + except IndexError: + pass log.debug("Files used now: %i" % len(self.files)) def play(self, sound, argument=False): if self.soundpack_OK == False: return - if config.main["sound"]["global_mute"] == True: return + if config.app["app-settings"]["global_mute"] == True: return sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound)) - sound_object.volume = float(config.main["sound"]["volume"]) + sound_object.volume = float(config.app["app-settings"]["volume"]) self.files.append(sound_object) sound_object.play() -class urlStream(object): - def __init__(self, url): - self.url = url - log.debug(u"URL: %s" % url) +class URLStream(object): + def __init__(self): + self.url = None self.prepared = False - def prepare(self): + def prepare(self, url): self.prepared = False - url = url_shortener.unshorten(self.url) - log.debug("url desacortada: "+str(url)) - if url != None: - self.url = url - transformer = audio_services.find_url_transformer(self.url) - self.url = transformer(self.url) - log.debug(u"Url transformada: %s" % self.url) - prepare = True + self.url = url_shortener.unshorten(url) + if self.url != None: + transformer = audio_services.find_url_transformer(self.url) + self.url = transformer(self.url) + self.prepared = True - def play(self): - self.stream = sound_lib.stream.URLStream(url=self.url) - self.stream.volume = float(config.main["sound"]["volume"]) - self.stream.play() + def play(self, url): + if hasattr(self, "stream") and self.stream.is_playing: + output.speak(_(u"Stopped")) + self.stream.stop() + del self.stream + else: + output.speak(_(u"Playing...")) + self.prepare(url) + if self.prepared == True: + self.stream = sound_lib.stream.URLStream(url=self.url) + self.stream.volume = float(config.app["app-settings"]["volume"]) + self.stream.play() @staticmethod def delete_old_tempfiles(): diff --git a/src/twitter/__init__.py b/src/twitter/__init__.py index c31a81fe..6b3d7122 100644 --- a/src/twitter/__init__.py +++ b/src/twitter/__init__.py @@ -1,2 +1,2 @@ -import buffers, utils, compose, starting, twitter +import buffers, utils, compose, twitter from compose import prettydate \ No newline at end of file diff --git a/src/twitter/authorisationHandler.py b/src/twitter/authorisationHandler.py new file mode 100644 index 00000000..45f4fe4d --- /dev/null +++ b/src/twitter/authorisationHandler.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +import BaseHTTPServer +from urlparse import urlparse, parse_qs + +logged = False +verifier = None + +class handler(BaseHTTPServer.BaseHTTPRequestHandler): + + def do_GET(self): + global logged + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + logged = True + params = parse_qs(urlparse(self.path).query) + global verifier + verifier = params.get('oauth_verifier', [None])[0] + self.wfile.write("You have successfully logged in to Twitter with TW Blue. " + "You can close this window now.") \ No newline at end of file diff --git a/src/twitter/buffers/indibidual.py b/src/twitter/buffers/indibidual.py index 0da7ecaf..cb21fe21 100644 --- a/src/twitter/buffers/indibidual.py +++ b/src/twitter/buffers/indibidual.py @@ -1,46 +1,35 @@ # -*- coding: utf-8 -*- from twitter import compose from twython import TwythonStreamer -import sound -from mysc import event -import wx -import config -import output +from pubsub import pub import logging as original_logger log = original_logger.getLogger("MainStream") -class streamer(TwythonStreamer): - def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=300, retry_count=None, retry_in=10, client_args=None, handlers=None, chunk_size=1, parent=None): - self.db = parent.db - self.parent = parent - TwythonStreamer.__init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=60, retry_count=None, retry_in=180, client_args=None, handlers=None, chunk_size=1) +class timelinesStreamer(TwythonStreamer): + def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=300, retry_count=None, retry_in=10, client_args=None, handlers=None, chunk_size=1, session=None): + self.session = session + super(timelinesStreamer, self).__init__(app_key, app_secret, oauth_token, oauth_token_secret, timeout=60, retry_count=None, retry_in=180, client_args=None, handlers=None, chunk_size=1) def on_error(self, status_code, data): log.debug("%s: %s" % (status_code, data)) def check_tls(self, data): - for i in config.main["other_buffers"]["timelines"]: + for i in self.session.settings["other_buffers"]["timelines"]: if data["user"]["screen_name"] == i: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data) - announce = _(u"One tweet from %s") % (data["user"]["name"]) - tweet_event.SetAnnounce(announce) - wx.PostEvent(self.parent.search_buffer(buffer_type="timeline", name_buffer=data["user"]["screen_name"]), tweet_event) - for i in range(0, self.parent.nb.GetPageCount()): - if self.parent.nb.GetPage(i).type == "list": - try: - self.parent.nb.GetPage(i).users.index(data["user"]["id"]) - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data) - announce = _(u"One tweet from %s in the list %s") % (data["user"]["name"], self.parent.nb.GetPage(i).name_buffer[:-5]) - tweet_event.SetAnnounce(announce) - wx.PostEvent(self.parent.nb.GetPage(i), tweet_event) - except ValueError: - pass + pub.sendMessage("item-in-timeline", data= data, user= self.session.db["user_name"], who= i) + + def on_success(self, data): +# try: + if "text" in data: + self.check_tls(data) +# except: +# pass + +class listsStreamer(timelinesStreamer): def on_success(self, data): try: - if data.has_key("text"): - self.check_tls(data) + if "text" in data: + pub.sendMessage("item-in-list", **{"data": data, "user": self.session.db["user_name"]}) except: pass \ No newline at end of file diff --git a/src/twitter/buffers/stream.py b/src/twitter/buffers/stream.py index 83eb8a39..ac680c56 100644 --- a/src/twitter/buffers/stream.py +++ b/src/twitter/buffers/stream.py @@ -1,104 +1,89 @@ # -*- coding: utf-8 -*- -from twitter import compose, utils +from twitter import utils from twython import TwythonStreamer -import sound -from mysc import event -import wx -import config +from pubsub import pub import logging as original_logger log = original_logger.getLogger("MainStream") -import output class streamer(TwythonStreamer): - def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=300, retry_count=None, retry_in=10, client_args=None, handlers=None, chunk_size=1, parent=None): - self.db = parent.db - self.parent = parent - TwythonStreamer.__init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=480, retry_count=0, retry_in=60, client_args=None, handlers=None, chunk_size=1) - self.muted_users = self.db.settings["muted_users"] + def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, sessionObject, *args, **kwargs): + super(streamer, self).__init__(app_key, app_secret, oauth_token, oauth_token_secret, *args, **kwargs) + self.session = sessionObject + self.muted_users = self.session.db["muted_users"] # self.blocked_users = [] def on_error(self, status_code, data): log.debug("Error %s: %s" % (status_code, data)) + def get_user(self): + return self.session.db["user_name"] + + def put_data(self, place, data): + if self.session.db.has_key(place): + if self.session.settings["general"]["reverse_timelines"] == False: + self.session.db[place].append(data) + else: + self.session.db[place].insert(0, data) + def block_user(self, data): id = data["target"]["id"] if id in self.friends: self.friends.remove(id) - if config.main["other_buffers"]["show_blocks"] == True: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data["target"]) - wx.PostEvent(self.parent.search_buffer("people", "blocks"), tweet_event) + if self.session.settings["other_buffers"]["show_blocks"] == True: + self.session.db["blocked"]["items"].append(data["target"]) + pub.sendMessage("blocked-user", data=data["target"], user=self.get_user()) def unblock(self, data): - if config.main["other_buffers"]["show_blocks"] == True: - item = utils.find_item(data["target"]["id"], self.db.settings["blocks"]) - self.db.settings["blocks"].pop(item) - deleted_event = event.event(event.EVT_DELETED, 1) - deleted_event.SetItem(item) - wx.PostEvent(self.parent.search_buffer("people", "blocks"), deleted_event) - wx.PostEvent(self.parent, event.ResultEvent()) + if self.session.settings["other_buffers"]["show_blocks"] == True: + item = utils.find_item(data["target"]["id"], self.session.db["blocked"]["items"]) + self.session.db["blocked"]["items"].pop(item) + pub.sendMessage("unblocked-user", item=item, user=self.get_user()) def check_send(self, data): - if self.db.settings["user_name"] == data["user"]["screen_name"]: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data) - wx.PostEvent(self.parent.search_buffer("buffer", "sent"), tweet_event) + if self.session.db["user_name"] == data["user"]["screen_name"]: + self.put_data("sent_tweets", data) + pub.sendMessage("sent-tweet", data=data, user=self.get_user()) def check_favs(self, data): - if data["source"]["screen_name"] == self.db.settings["user_name"]: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data["target_object"]) - wx.PostEvent(self.parent.search_buffer("buffer", "favs"), tweet_event) + if data["source"]["screen_name"] == self.session.db["user_name"]: + self.put_data("favourites", data["target_object"]) + pub.sendMessage("favourite", data=data["target_object"], user=self.get_user()) def check_mentions(self, data): - if "@%s" % (self.db.settings["user_name"]) in data["text"]: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data) - text = _(u"One mention from %s ") % (data["user"]["name"]) - tweet_event.SetAnnounce(text) - wx.PostEvent(self.parent.search_buffer("buffer", "mentions"), tweet_event) - + if "@%s" % (self.session.db["user_name"]) in data["text"]: + self.put_data("mentions", data) + pub.sendMessage("mention", data=data, user=self.get_user()) + def process_dm(self, data): - if self.db.settings["user_name"] == data["direct_message"]["sender"]["screen_name"]: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data["direct_message"]) - wx.PostEvent(self.parent.search_buffer("buffer", "sent"), tweet_event) - if self.db.settings["user_name"] != data["direct_message"]["sender"]["screen_name"]: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data["direct_message"]) - text = _(u"One direct message") - tweet_event.SetAnnounce(text) - wx.PostEvent(self.parent.search_buffer("buffer", "direct_messages"), tweet_event) - + if self.session.db["user_name"] == data["direct_message"]["sender"]["screen_name"]: + self.put_data("sent_direct_messages", data["direct_message"]) + pub.sendMessage("sent-dm", data=data["direct_message"], user=self.get_user()) + else: + self.put_data("direct_messages", data["direct_message"]) + pub.sendMessage("direct-message", data=data["direct_message"], user=self.get_user()) + def check_follower(self, data): - if data["target"]["screen_name"] == self.db.settings["user_name"]: - if config.main["other_buffers"]["show_followers"] == True: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data["source"]) - wx.PostEvent(self.parent.search_buffer("people", "followers"), tweet_event) - elif data["source"]["screen_name"] == self.db.settings["user_name"] and config.main["other_buffers"]["show_friends"] == True: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data["target"]) - wx.PostEvent(self.parent.search_buffer("people", "friends"), tweet_event) + if data["target"]["screen_name"] == self.session.db["user_name"]: + self.session.db["followers"]["items"].append(data["source"]) + pub.sendMessage("follower", data=data["source"], user = self.get_user()) + else: + self.session.db["friends"]["items"].append(data["target"]) + pub.sendMessage("friend", data=data["target"], user=self.get_user()) +### def remove_fav(self, data): - if self.db.settings["user_name"] == data["source"]["screen_name"]: - self.db.settings.update() - item = utils.find_item(data["target_object"]["id"], self.db.settings["favs"]) - self.db.settings["favs"].pop(item) - deleted_event = event.event(event.EVT_DELETED, 1) - deleted_event.SetItem(item) - wx.PostEvent(self.parent.search_buffer("buffer", "favs"), deleted_event) + if self.session.db["user_name"] == data["source"]["screen_name"]: + item = utils.find_item(data["target_object"]["id"], self.session.db["favourites"]) + print item + self.session.db["favourites"].pop(item) + pub.sendMessage("unfavourite", item=item, user=self.get_user()) def remove_friend(self, data): - if config.main["other_buffers"]["show_friends"] == True: - item = utils.find_item(data["target"]["id"], self.db.settings["friends"]) + if self.session.settings["other_buffers"]["show_friends"] == True: + item = utils.find_item(data["target"]["id"], self.session.db["friends"]["items"]) if item > 0: - deleted_event = event.event(event.EVT_DELETED, 1) - deleted_event.SetItem(item) - self.friends.pop(item) - self.db.settings["friends"].pop(item) - wx.PostEvent(self.parent.search_buffer("people", "friends"), deleted_event) + self.friends["items"].pop(item) + pub.sendMessage("unfollowing", item=item, user=self.get_user()) def on_success(self, data): try: @@ -106,64 +91,46 @@ class streamer(TwythonStreamer): self.process_dm(data) elif "friends" in data: self.friends = data["friends"] - elif "text" in data and utils.is_allowed(data) == True: + elif "text" in data: if data["user"]["id"] in self.muted_users: return self.check_mentions(data) self.check_send(data) - if data["user"]["id"] in self.friends or data["user"]["screen_name"] == self.db.settings["user_name"]: - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(data) - wx.PostEvent(self.parent.search_buffer("buffer", "home_timeline"), tweet_event) + if data["user"]["id"] in self.friends or data["user"]["screen_name"] == self.session.db["user_name"]: + self.put_data("home_timeline", data) + pub.sendMessage("item-in-home", data=data, user=self.get_user()) elif data.has_key("event"): - if "favorite" == data["event"] and config.main["other_buffers"]["show_favourites"] == True: + if "favorite" == data["event"] and self.session.settings["other_buffers"]["show_favourites"] == True: self.check_favs(data) - elif "unfavorite" == data["event"] and config.main["other_buffers"]["show_favourites"] == True: + elif "unfavorite" == data["event"] and self.session.settings["other_buffers"]["show_favourites"] == True: self.remove_fav(data) - elif "follow" == data["event"] and config.main["other_buffers"]["show_followers"] == True: + elif "follow" == data["event"] and self.session.settings["other_buffers"]["show_followers"] == True: self.check_follower(data) - elif "unfollow" == data["event"] and config.main["other_buffers"]["show_followers"] == True: + elif "unfollow" == data["event"] and self.session.settings["other_buffers"]["show_followers"] == True: self.remove_friend(data) elif "block" == data["event"]: self.block_user(data) - elif "unblock" in data["event"]: + elif "unblock" == data["event"]: self.unblock(data) elif "list_created" == data["event"]: - item = utils.find_item(data["target_object"]["id"], self.db.settings["lists"]) - if item != None: self.db.settings["lists"].append(data["target_object"]) + item = utils.find_item(data["target_object"]["id"], self.session.db["lists"]) + if item != None: self.session.db["lists"].append(data["target_object"]) elif "list_destroyed" == data["event"]: - item = utils.find_item(data["target_object"]["id"], self.db.settings["lists"]) - if item != None: self.db.settings["lists"].pop(item) + item = utils.find_item(data["target_object"]["id"], self.session.db["lists"]) + if item != None: self.session.db["lists"].pop(item) self.parent.remove_list(data["target_object"]["id"]) - elif "list_member_added" == data["event"] and data["source"]["screen_name"] == self.db.settings["user_name"]: - if len(config.main["other_buffers"]["lists"]) > 0: - for i in range(0, self.parent.nb.GetPageCount()): - if self.parent.nb.GetPage(i).type == "list": - if str(data["target_object"]["id"]) == str(self.parent.nb.GetPage(i).argumento): - self.parent.nb.GetPage(i).users.append(data["target"]["id"]) - wx.PostEvent(self.parent, event.ResultEvent()) - elif "list_member_added" == data["event"] and data["target"]["screen_name"] == self.db.settings["user_name"]: - self.db.settings["lists"].append(data["target_object"]) - elif "list_member_removed" == data["event"] and data["source"]["screen_name"] == self.db.settings["user_name"]: - if len(config.main["other_buffers"]["lists"]) > 0: - for i in range(0, self.parent.nb.GetPageCount()): - if self.parent.nb.GetPage(i).type == "list": - if str(data["target_object"]["id"]) == str(self.parent.nb.GetPage(i).argumento): - self.parent.nb.GetPage(i).users.remove(data["target"]["id"]) - wx.PostEvent(self.parent, event.ResultEvent()) - elif "list_member_removed" == data["event"] and data["target"] == self.db.settings["user_name"]: + elif "list_member_added" == data["event"] and data["source"]["screen_name"] == self.get_user(): + pub.sendMessage("new-list-member-added", **{"id":str(data["target"]["id"]), "list":data["target_object"], "user":self.get_user()}) + elif "list_member_added" == data["event"] and data["target"]["screen_name"] == self.get_user(): + self.session.db["lists"].append(data["target_object"]) + elif "list_member_removed" == data["event"] and data["source"]["screen_name"] == self.get_user(): + pub.sendMessage("list-member-deleted", **{"id":str(data["target"]["id"]), "list":data["target_object"], "user":self.get_user()}) + elif "list_member_removed" == data["event"] and data["target"] == self.get_user(): id = data["target_object"]["id"] - list = utils.find_item(id, self.db.settings["lists"]) - if list != None: self.db.settings["lists"].pop(list) - self.parent.remove_list(data["target_object"]["id"]) - if config.main["other_buffers"]["show_events"] == True: - evento = compose.compose_event(data, self.db.settings["user_name"]) - tweet_event = event.event(event.EVT_OBJECT, 1) - tweet_event.SetItem(evento) - text = evento[1] - tweet_event.SetAnnounce(text) -# deleted_event = event.event(event.EVT_DELETED, 1) -# deleted_event.SetItem(evento) - wx.PostEvent(self.parent.search_buffer("event", "events"), tweet_event) + list = utils.find_item(id, self.session.db["lists"]) + if list != None: self.session.db["lists"].pop(list) + pub.sendMessage("list-deleted", **{"item":list, "user":self.get_user()}) + if self.session.settings["other_buffers"]["show_events"] == True: + pub.sendMessage("event", data= data, user= self.get_user()) # self.sound.play("new_event.ogg") - except: + except KeyboardInterrupt: pass diff --git a/src/twitter/compose.py b/src/twitter/compose.py index cf80437b..9721b30d 100644 --- a/src/twitter/compose.py +++ b/src/twitter/compose.py @@ -6,11 +6,6 @@ import datetime import time import output import gettext, paths, locale, gettext_windows -import config, languageHandler -if config.main != None: - languageHandler.setLanguage(config.main["general"]["language"]) -else: - languageHandler.setLanguage("system") import platform system = platform.system() @@ -133,14 +128,14 @@ def translate_short(string): chars = "abcdefghijklmnopqrstuvwxyz" -def compose_tweet(tweet, db): +def compose_tweet(tweet, db, relative_times): """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" # original_date = datetime.datetime.strptime(translate_short(tweet["created_at"]).encode("utf-8"), "%a %b %d %H:%M:%S +0000 %Y") original_date = datetime.datetime.strptime(tweet["created_at"], "%a %b %d %H:%M:%S +0000 %Y") # else: # original_date = datetime.datetime.strptime(tweet["created_at"], '%a %b %d %H:%M:%S +0000 %Y') - date = original_date-datetime.timedelta(seconds=-db.settings["utc_offset"]) - if config.main["general"]["relative_times"] == True: + date = original_date-datetime.timedelta(seconds=-db["utc_offset"]) + if relative_times == True: ts = prettydate(original_date) else: # ts = translate(datetime.datetime.strftime(date, _("%A, %B %d, %Y at %I:%M:%S %p".encode("utf-8"))).decode("utf-8")) @@ -149,7 +144,7 @@ def compose_tweet(tweet, db): text = StripChars(tweet["text"]) if tweet.has_key("sender"): source = "DM" - if db.settings["user_name"] == tweet["sender"]["screen_name"]: user = _(u"Dm to %s ") % (tweet["recipient"]["name"],) + if db["user_name"] == tweet["sender"]["screen_name"]: user = _(u"Dm to %s ") % (tweet["recipient"]["name"],) else: user = tweet["sender"]["name"] elif tweet.has_key("user"): user = tweet["user"]["name"] @@ -162,13 +157,13 @@ def compose_tweet(tweet, db): try: text = text.replace(urls[url], tweet["entities"]["urls"][url]["expanded_url"]) except IndexError: pass tweet["text"] = text - return [user+", ", tweet["text"], ts+", ", source] + return [user+", ", text, ts+", ", source] -def compose_followers_list(tweet, db): +def compose_followers_list(tweet, db, relative_time=True): # original_date = datetime.datetime.strptime(translate_short(tweet["created_at"]).encode("utf-8"), '%a %b %d %H:%M:%S +0000 %Y') original_date = datetime.datetime.strptime(tweet["created_at"], '%a %b %d %H:%M:%S +0000 %Y') - date = original_date-datetime.timedelta(seconds=-db.settings["utc_offset"]) - if config.main["general"]["relative_times"] == True: + date = original_date-datetime.timedelta(seconds=-db["utc_offset"]) + if relative_time == True: ts = prettydate(original_date) else: ts = translate(datetime.datetime.strftime(date, _(u"%A, %B %d, %Y at %I:%M:%S %p"))) @@ -177,8 +172,8 @@ def compose_followers_list(tweet, db): if len(tweet["status"]) > 4: # original_date2 = datetime.datetime.strptime(translate_short(tweet["status"]["created_at"]).encode("utf-8"), '%a %b %d %H:%M:%S +0000 %Y') original_date2 = datetime.datetime.strptime(tweet["status"]["created_at"], '%a %b %d %H:%M:%S +0000 %Y') - date2 = original_date2-datetime.timedelta(seconds=-db.settings["utc_offset"]) - if config.main["general"]["relative_times"]: + date2 = original_date2-datetime.timedelta(seconds=-db["utc_offset"]) + if relative_time == True: ts2 = prettydate(original_date2) else: ts2 = translate(datetime.datetime.strftime(date2, _(u"%A, %B %d, %Y at %I:%M:%S %p"))) diff --git a/src/twitter/starting.py b/src/twitter/starting.py deleted file mode 100644 index 3d9dd9e1..00000000 --- a/src/twitter/starting.py +++ /dev/null @@ -1,259 +0,0 @@ -# -*- config: utf-8 -*- -from twython import Twython, TwythonError -import config -#import sound -import time -import utils - -friends_cursor = followers_cursor = None - -def get_more_items(update_function, twitter_object, users=False, name=None, *args, **kwargs): - results = [] - data = update_function(*args, **kwargs) - if users == True: - global friends_cursor, followers_cursor - if name == "friends": - friends_cursor = data["next_cursor"] - elif name == "followers": - followers_cursor = data["next_cursor"] - for i in data["users"]: results.append(i) - else: - results.extend(data[1:]) - return results - -def call_paged(update_function, twitter_object, *args, **kwargs): - max = int(config.main["general"]["max_api_calls"])-1 - results = [] - data = update_function(*args, **kwargs) - results.extend(data) - for i in range(0, max): - if i == 0: max_id = results[-1]["id"] - else: max_id = results[0]["id"] - data = update_function(max_id=max_id, *args, **kwargs) - results.extend(data) - results.reverse() - return results - -def start_user_info(config, twitter): - f = twitter.twitter.get_account_settings() - sn = f["screen_name"] - config.settings["user_name"] = sn - config.settings["user_id"] = twitter.twitter.show_user(screen_name=sn)["id_str"] - try: - config.settings["utc_offset"] = f["time_zone"]["utc_offset"] - except KeyError: - config.settings["utc_offset"] = -time.timezone - get_lists(config, twitter) - get_muted_users(config, twitter) - -def get_lists(config, twitter): - config.settings["lists"] = twitter.twitter.show_lists(reverse=True) - -def get_muted_users(config, twitter): - config.settings["muted_users"] = twitter.twitter.get_muted_users_ids()["ids"] - -def start_stream(db, twitter, name, function, param=None): - num = 0 - if db.settings.has_key(name): - try: - if db.settings[name][0]["id"] > db.settings[name][-1]["id"]: - last_id = db.settings[name][0]["id"] - else: - last_id = db.settings[name][-1]["id"] - except IndexError: - pass - if param != None: - tl = call_paged(function, twitter, sinze_id=last_id, screen_name=param, count=config.main["general"]["max_tweets_per_call"]) - else: - tl = call_paged(function, twitter, sinze_id=last_id, count=config.main["general"]["max_tweets_per_call"]) - else: - if param != None: - tl = call_paged(function, twitter, screen_name=param, count=config.main["general"]["max_tweets_per_call"]) - else: - tl = call_paged(function, twitter, count=config.main["general"]["max_tweets_per_call"]) - db.settings[name] = [] - last_id = 0 - if len(db.settings[name]) > 0: - for i in tl: - if int(i["id"]) > int(last_id): - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - elif len(db.settings[name]) == 0: - for i in tl: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 -# db.settings.update() - return num - -def start_followers(db, twitter, name, function, param=None): - global friends_cursor, followers_cursor - num = 0 - db.settings[name] = [] -# next_cursor = -1 -# while(next_cursor): - tl = function(screen_name=param, count=config.main["general"]["max_tweets_per_call"]) - for i in tl['users']: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 -# next_cursor = tl["next_cursor"] - db.settings[name].reverse() -# if config.main["streams"]["reverse_timelines"] == True: db.settings[name].reverse() - if name == "followers": followers_cursor = tl["next_cursor"] - elif name == "friends": friends_cursor = tl["next_cursor"] - return num - -def get_users_list(twitter, list_id): - answers = [] - next_cursor = -1 - while(next_cursor): - users = twitter.twitter.get_list_members(list_id=list_id, cursor=next_cursor, include_entities=False, skip_status=True) - for i in users['users']: - answers.append(i["id"]) - next_cursor = users["next_cursor"] - return answers - -def update_stream(config, twitter, name, function, param=None, sndFile=""): - num = 0 - sounded = False - tl = function(sinze_id=config.settings[name][-1]["id"], screen_name=param, count=config.main["general"]["max_tweets_per_call"]) - tl.reverse() - for i in tl: - if i["id"] > config.settings[name][-1]["id"]: - config.settings[name].append(i) - sounded = True - num = num+1 - if sounded == True: - sound.play(sndFile) - return num - -def start_sent(db, twitter, name, function, param=None): - num = 0 - if db.settings.has_key(name): - try: - if db.settings[name][0]["id"] > db.settings[name][-1]["id"]: - last_id = db.settings[name][0]["id"] - else: - last_id = db.settings[name][-1]["id"] - except IndexError: - return 0 - if param != None: - tl = function(sinze_id=last_id, screen_name=param, count=config.main["general"]["max_tweets_per_call"]) - tl2 = twitter.twitter.get_sent_messages(sinze_id=last_id, count=config.main["general"]["max_tweets_per_call"]) - else: - tl = function(sinze_id=last_id, count=config.main["general"]["max_tweets_per_call"]) - tl2 = twitter.twitter.get_sent_messages(sinze_id=last_id, count=config.main["general"]["max_tweets_per_call"]) - else: - if param != None: - tl = function(screen_name=param, count=config.main["general"]["max_tweets_per_call"]) - tl2 = twitter.twitter.get_sent_messages(count=config.main["general"]["max_tweets_per_call"]) - else: - tl = function(count=config.main["general"]["max_tweets_per_call"]) - tl2 = twitter.twitter.get_sent_messages(sinze_id=last_id, count=config.main["general"]["max_tweets_per_call"]) - db.settings[name] = [] - last_id = 0 - tl.extend(tl2) -# tl.reverse() - tl.sort(key=lambda tup: tup["id"]) - if len(db.settings[name]) > 0: - for i in tl: -# print last_id, i["id"] - if int(i["id"]) > int(last_id): - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - elif len(db.settings[name]) == 0: - for i in tl: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - return num - -def start_list(db, twitter, name, list_id): - num = 0 - if db.settings.has_key(name): - try: - if db.settings[name][0]["id"] > db.settings[name][-1]["id"]: - last_id = db.settings[name][0]["id"] - else: - last_id = db.settings[name][-1]["id"] - except IndexError: - pass - tl = twitter.twitter.get_list_statuses(list_id=list_id, count=200) - else: - tl = twitter.twitter.get_list_statuses(list_id=list_id, count=200) - tl.reverse() - db.settings[name] = [] - last_id = 0 - if len(db.settings[name]) > 0: - for i in tl: - if int(i["id"]) > int(last_id): - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - elif len(db.settings[name]) == 0: - for i in tl: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - db.settings.update() - return num - -def search(db, twitter, name, *args, **kwargs): - num = 0 - if db.settings.has_key(name) == False: - db.settings[name] = [] - tl = twitter.twitter.search(*args, **kwargs) - tl["statuses"].reverse() - if len(db.settings[name]) > 0: - for i in tl["statuses"]: - if utils.find_item(i["id"], db.settings[name]) == None: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - elif len(db.settings[name]) == 0: - for i in tl["statuses"]: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - return num - -def search_users(db, twitter, name, *args, **kwargs): - num = 0 - if db.settings.has_key(name) == False: - db.settings[name] = [] - tl = twitter.twitter.search_users(*args, **kwargs) - tl.reverse() - if len(db.settings[name]) > 0: - for i in tl: - if utils.find_item(i["id"], db.settings[name]) == None: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - elif len(db.settings[name]) == 0: - for i in tl: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - return num - -def get_favourites_timeline(db, twitter, name, param, *args, **kwargs): - num = 0 - if db.settings.has_key(name) == False: - db.settings[name] = [] - tl = twitter.twitter.get_favorites(screen_name=param, *args, **kwargs) - tl.reverse() - if len(db.settings[name]) > 0: - for i in tl: - if utils.find_item(i["id"], db.settings[name]) == None: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - elif len(db.settings[name]) == 0: - for i in tl: - if config.main["general"]["reverse_timelines"] == False: db.settings[name].append(i) - else: db.settings[name].insert(0, i) - num = num+1 - return num \ No newline at end of file diff --git a/src/twitter/twitter.py b/src/twitter/twitter.py index ef24d093..1a03533e 100644 --- a/src/twitter/twitter.py +++ b/src/twitter/twitter.py @@ -1,83 +1,29 @@ # -*- coding: utf-8 -*- import BaseHTTPServer import webbrowser -from urlparse import urlparse, parse_qs from twython import Twython, TwythonError -import config import application -import output -import sound -import time - -logged = False -verifier = None - -class handler(BaseHTTPServer.BaseHTTPRequestHandler): - - def do_GET(self): - global logged - self.send_response(200) - self.send_header("Content-type", "text/html") - self.end_headers() - logged = True - params = parse_qs(urlparse(self.path).query) - global verifier - verifier = params.get('oauth_verifier', [None])[0] - self.wfile.write("You have successfully logged in to Twitter with TW Blue. " - "You can close this window now.") +import authorisationHandler class twitter(object): - def login(self, user_key=None, user_secret=None): - if user_key != None and user_secret != None: - self.twitter = Twython(application.app_key, application.app_secret, user_key, user_secret) - elif config.main != None: - self.twitter = Twython(application.app_key, application.app_secret, config.main["twitter"]["user_key"], config.main["twitter"]["user_secret"]) - else: - self.twitter = Twython(application.app_key, application.app_secret, self.final_step['oauth_token'], self.final_step['oauth_token_secret']) + def login(self, user_key, user_secret): + self.twitter = Twython(application.app_key, application.app_secret, user_key, user_secret) self.credentials = self.twitter.verify_credentials() - def authorise(self): - httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', 8080), handler) + def authorise(self, settings): + httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', 8080), authorisationHandler.handler) twitter = Twython(application.app_key, application.app_secret) auth = twitter.get_authentication_tokens("http://127.0.0.1:8080") webbrowser.open_new_tab(auth['auth_url']) - global logged, verifier - while logged == False: +# global logged, verifier + while authorisationHandler.logged == False: httpd.handle_request() self.twitter = Twython(application.app_key, application.app_secret, auth['oauth_token'], auth['oauth_token_secret']) - final = self.twitter.get_authorized_tokens(verifier) - self.save_configuration(final["oauth_token"], final["oauth_token_secret"]) + final = self.twitter.get_authorized_tokens(authorisationHandler.verifier) + self.save_configuration(settings, final["oauth_token"], final["oauth_token_secret"]) - def save_configuration(self, user_key=None, user_secret=None): - if user_key != None and user_secret != None: - config.main["twitter"]["user_key"] = user_key - config.main["twitter"]["user_secret"] = user_secret - else: - config.main['twitter']['user_key'] = self.final_step['oauth_token'] - config.main['twitter']['user_secret'] = self.final_step['oauth_token_secret'] - config.main.write() - - def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): - finished = False - tries = 0 - if preexec_message: - output.speak(preexec_message, True) - while finished==False and tries < 25: - try: - val = getattr(self.twitter, call_name)(*args, **kwargs) - finished = True - except TwythonError as e: -# if hasattr(e, 'reason') and e.reason.startswith("Failed to send request"): - output.speak(e.message) - if report_failure and hasattr(e, 'message'): - output.speak(_("%s failed. Reason: %s") % (action, e.message)) - finished = True - except: - tries = tries + 1 - time.sleep(5) - # raise e - if report_success: - output.speak(_("%s succeeded.") % action) - if _sound != None: sound.player.play(_sound) -# return val \ No newline at end of file + def save_configuration(self, settings, user_key, user_secret): + settings["twitter"]["user_key"] = user_key + settings["twitter"]["user_secret"] = user_secret + settings.write() diff --git a/src/twitter/utils.py b/src/twitter/utils.py index c28d9333..edc627d7 100644 --- a/src/twitter/utils.py +++ b/src/twitter/utils.py @@ -9,8 +9,6 @@ __version__ = 0.1 __doc__ = "Find urls in tweets and #audio hashtag." url_re = re.compile(r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))") -#"(?:\w+://|www\.)[^ ,.?!#%=+][^ ]*") -#bad_chars = '\'\\.,[](){}:;"' url_re2 = re.compile("(?:\w+://|www\.)[^ ,.?!#%=+][^ ]*") bad_chars = '\'\\.,[](){}:;"' @@ -20,13 +18,6 @@ def find_urls_in_text(text): def find_urls (tweet): urls = [] -# for i in tweet["entities"]["urls"]: -# unshortened = url_shortener.unshorten(i["expanded_url"]) -# if unshortened == None: -# urls.append(i["expanded_url"]) -# else: -# urls.append(unshortened) -# return urls return [s[0] for s in url_re.findall(tweet["text"])] def find_item(id, listItem): @@ -44,9 +35,6 @@ def find_previous_reply(id, listItem): return None def find_next_reply(id, listItem): -# r = range(0, len(listItem)) -# r.reverse() -# for i in r: for i in range(0, len(listItem)): if listItem[i]["in_reply_to_status_id_str"] == str(id): return i return None diff --git a/src/twython/streaming/api.py b/src/twython/streaming/api.py index f74f22e4..47678e47 100644 --- a/src/twython/streaming/api.py +++ b/src/twython/streaming/api.py @@ -124,7 +124,6 @@ class TwythonStreamer(object): except requests.exceptions.Timeout: self.on_timeout() else: -# self.connected = False if response.status_code != 200: self.on_error(response.status_code, response.content) diff --git a/src/widgetUtils/__init__.py b/src/widgetUtils/__init__.py new file mode 100644 index 00000000..f9b60c8f --- /dev/null +++ b/src/widgetUtils/__init__.py @@ -0,0 +1,3 @@ +import platform +if platform.system() == "Windows": + from wxUtils import * diff --git a/src/widgetUtils/wxUtils.py b/src/widgetUtils/wxUtils.py new file mode 100644 index 00000000..0512d09a --- /dev/null +++ b/src/widgetUtils/wxUtils.py @@ -0,0 +1,17 @@ +import wx + +# Code responses for WX dialogs. +OK = wx.ID_OK +CANCEL = wx.ID_CANCEL +CLOSE = wx.ID_CLOSE +YES = wx.ID_YES +NO = wx.ID_NO + +#events +CLOSE_EVENT = wx.EVT_CLOSE + +def exit_application(): + wx.GetApp().ExitMainLoop() + +def connect_event(parent, event, func): + return getattr(parent, "Bind")(event, func) \ No newline at end of file diff --git a/src/wxUI/__init__.py b/src/wxUI/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/src/wxUI/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/wxUI/buffers/__init__.py b/src/wxUI/buffers/__init__.py new file mode 100644 index 00000000..cc75e842 --- /dev/null +++ b/src/wxUI/buffers/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from base import basePanel +from dm import dmPanel +from events import eventsPanel +from favourites import favsPanel +from lists import listPanel +from panels import accountPanel, emptyPanel +from people import peoplePanel +from tweet_searches import searchPanel +from user_searches import searchUsersPanel \ No newline at end of file diff --git a/src/wxUI/buffers/base.py b/src/wxUI/buffers/base.py new file mode 100644 index 00000000..83dd12cd --- /dev/null +++ b/src/wxUI/buffers/base.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import wx +from multiplatform_widgets import widgets + +class basePanel(wx.Panel): + + def create_list(self): + self.list = widgets.list(self, _(u"User"), _(u"Text"), _(u"Date"), _(u"Client"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) + self.list.set_windows_size(0, 30) + self.list.set_windows_size(1, 160) + self.list.set_windows_size(2, 55) + self.list.set_windows_size(3, 42) + self.list.set_size() + + def __init__(self, parent, name): + super(basePanel, self).__init__(parent) + self.name = name + self.type = "baseBuffer" + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.create_list() + self.btn = wx.Button(self, -1, _(u"Tweet")) + self.retweetBtn = wx.Button(self, -1, _(u"Retweet")) + self.responseBtn = wx.Button(self, -1, _(u"Reply")) + self.dmBtn = wx.Button(self, -1, _(u"Direct message")) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add(self.btn, 0, wx.ALL, 5) + btnSizer.Add(self.retweetBtn, 0, wx.ALL, 5) + btnSizer.Add(self.responseBtn, 0, wx.ALL, 5) + btnSizer.Add(self.dmBtn, 0, wx.ALL, 5) + self.sizer.Add(btnSizer, 0, wx.ALL, 5) + self.sizer.Add(self.list.list, 0, wx.ALL, 5) + self.SetSizer(self.sizer) diff --git a/src/wxUI/buffers/dm.py b/src/wxUI/buffers/dm.py new file mode 100644 index 00000000..734c15e2 --- /dev/null +++ b/src/wxUI/buffers/dm.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +import wx +from base import basePanel + +class dmPanel(basePanel): + def __init__(self, parent, name): + """ Class to DM'S. Reply and retweet buttons are not showed and they have your delete method for dm's.""" + super(dmPanel, self).__init__(parent, name) + self.retweetBtn.Disable() + self.responseBtn.Disable() + self.type = "dm" \ No newline at end of file diff --git a/src/wxUI/buffers/events.py b/src/wxUI/buffers/events.py new file mode 100644 index 00000000..870531e1 --- /dev/null +++ b/src/wxUI/buffers/events.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +import wx +from multiplatform_widgets import widgets + +class eventsPanel(wx.Panel): + """ Buffer to show events. Different than tweets or people.""" + + def __init__(self, parent, name): + self.type = "event" + super(eventsPanel, self).__init__(parent) + self.name = name + sizer = wx.BoxSizer() + self.list = widgets.list(self, _(u"Date"), _(u"Event"), size=(600,600), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) + self.tweet = wx.Button(self, -1, _(u"Tweet")) + self.delete_event = wx.Button(self, -1, _(u"Remove event")) diff --git a/src/wxUI/buffers/favourites.py b/src/wxUI/buffers/favourites.py new file mode 100644 index 00000000..4837dd6f --- /dev/null +++ b/src/wxUI/buffers/favourites.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +import wx +from base import basePanel + +class favsPanel(basePanel): + def __init__(self, parent, name): + super(favsPanel, self).__init__(parent, name) + self.type = "favourites_timeline" \ No newline at end of file diff --git a/src/wxUI/buffers/lists.py b/src/wxUI/buffers/lists.py new file mode 100644 index 00000000..1985d650 --- /dev/null +++ b/src/wxUI/buffers/lists.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +import wx +from base import basePanel + +class listPanel(basePanel): + def __init__(self, parent, name): + super(listPanel, self).__init__(parent, name) + self.type = "list" + self.users = [] diff --git a/src/wxUI/buffers/panels.py b/src/wxUI/buffers/panels.py new file mode 100644 index 00000000..892ded9c --- /dev/null +++ b/src/wxUI/buffers/panels.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +import wx +from multiplatform_widgets import widgets + +class accountPanel(wx.Panel): + def __init__(self, parent, name=None): + super(accountPanel, self).__init__(parent=parent) + self.name = name + self.type = "account" + sizer = wx.BoxSizer(wx.VERTICAL) + self.list = widgets.list(self, _(u"Announce")) + sizer.Add(self.list.list, 0, wx.ALL, 5) + self.SetSizer(sizer) + +class emptyPanel(accountPanel): + def __init__(self, parent, name): + super(emptyPanel, self).__init__(parent=parent, name=name) + self.type = "empty" \ No newline at end of file diff --git a/src/wxUI/buffers/people.py b/src/wxUI/buffers/people.py new file mode 100644 index 00000000..e0cd6d2e --- /dev/null +++ b/src/wxUI/buffers/people.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +import wx +from multiplatform_widgets import widgets +from base import basePanel + +class peoplePanel(basePanel): + """ Buffer used to show people.""" + + def create_list(self): + self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) + + def __init__(self, parent, name): + super(peoplePanel, self).__init__(parent, name) + self.type = "people" + self.responseBtn.SetLabel(_(u"Mention")) + self.retweetBtn.Disable() diff --git a/src/wxUI/buffers/tweet_searches.py b/src/wxUI/buffers/tweet_searches.py new file mode 100644 index 00000000..28cf974e --- /dev/null +++ b/src/wxUI/buffers/tweet_searches.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +import wx +from base import basePanel + +class searchPanel(basePanel): + def __init__(self, parent, name): + super(searchPanel, self).__init__(parent, name) + self.type = "search" diff --git a/src/wxUI/buffers/user_searches.py b/src/wxUI/buffers/user_searches.py new file mode 100644 index 00000000..b3b1415c --- /dev/null +++ b/src/wxUI/buffers/user_searches.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +import wx +from tweet_searches import searchPanel +from multiplatform_widgets import widgets + +class searchUsersPanel(searchPanel): + def create_list(self): + """ Returns the list for put the tweets here.""" + self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) + + def __init__(self, parent, name): + super(searchUsersPanel, self).__init__(parent, name) + self.create_list() + self.type = "user_searches" \ No newline at end of file diff --git a/src/wxUI/dialogs/__init__.py b/src/wxUI/dialogs/__init__.py new file mode 100644 index 00000000..b7945e73 --- /dev/null +++ b/src/wxUI/dialogs/__init__.py @@ -0,0 +1 @@ +import baseDialog, configuration, follow, lists, message, search, show_user, update_profile, urlList diff --git a/src/wxUI/dialogs/baseDialog.py b/src/wxUI/dialogs/baseDialog.py new file mode 100644 index 00000000..e20b805b --- /dev/null +++ b/src/wxUI/dialogs/baseDialog.py @@ -0,0 +1,16 @@ +import wx + +class BaseWXDialog(wx.Dialog): + def __init__(self, *args, **kwargs): + super(BaseWXDialog, self).__init__(*args, **kwargs) + + def get_response(self): + return self.ShowModal() + + def get(self, control): + if hasattr(self, control): + control = getattr(self, control) + if hasattr(control, "GetValue"): return getattr(control, "GetValue")() + elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() + else: return -1 + else: return 0 \ No newline at end of file diff --git a/src/wxUI/dialogs/configuration.py b/src/wxUI/dialogs/configuration.py new file mode 100644 index 00000000..7fd94af3 --- /dev/null +++ b/src/wxUI/dialogs/configuration.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +import baseDialog +import wx +import logging as original_logger + +class general(wx.Panel, baseDialog.BaseWXDialog): + def __init__(self, parent, languages): + super(general, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + language = wx.StaticText(self, -1, _(u"Language")) + self.language = wx.ListBox(self, -1, choices=languages) + self.language.SetSize(self.language.GetBestSize()) + langBox = wx.BoxSizer(wx.HORIZONTAL) + langBox.Add(language, 0, wx.ALL, 5) + langBox.Add(self.language, 0, wx.ALL, 5) + sizer.Add(langBox, 0, wx.ALL, 5) + self.relative_time = wx.CheckBox(self, -1, _(U"Relative times")) + sizer.Add(self.relative_time, 0, wx.ALL, 5) + self.disable_sapi5 = wx.CheckBox(self, -1, _(u"Activate Sapi5 when any other screen reader is not being run")) + sizer.Add(self.disable_sapi5, 0, wx.ALL, 5) + self.show_gui = wx.CheckBox(self, -1, _(u"Activate the auto-start of the invisible interface")) + sizer.Add(self.show_gui, 0, wx.ALL, 5) + apiCallsBox = wx.BoxSizer(wx.HORIZONTAL) + apiCallsBox.Add(wx.StaticText(self, -1, _(u"API calls when the stream is started (One API call equals to 200 tweetts, two API calls equals 400 tweets, etc):")), 0, wx.ALL, 5) + self.apiCalls = wx.SpinCtrl(self, -1) + self.apiCalls.SetRange(1, 10) + self.apiCalls.SetSize(self.apiCalls.GetBestSize()) + apiCallsBox.Add(self.apiCalls, 0, wx.ALL, 5) + sizer.Add(apiCallsBox, 0, wx.ALL, 5) + tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL) + tweetsPerCallBox.Add(wx.StaticText(self, -1, _(u"Items on each API call")), 0, wx.ALL, 5) + self.itemsPerApiCall = wx.SpinCtrl(self, -1) + self.itemsPerApiCall.SetRange(0, 200) + self.itemsPerApiCall.SetSize(self.itemsPerApiCall.GetBestSize()) + tweetsPerCallBox.Add(self.itemsPerApiCall, 0, wx.ALL, 5) + sizer.Add(tweetsPerCallBox, 0, wx.ALL, 5) + self.reverse_timelines = wx.CheckBox(self, -1, _(u"Inverted buffers: The newest tweets will be shown at the beginning of the lists while the oldest at the end")) + sizer.Add(self.reverse_timelines, 0, wx.ALL, 5) + self.SetSizer(sizer) + +class other_buffers(wx.Panel): + def __init__(self, parent): + super(other_buffers, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + self.followers = wx.CheckBox(self, -1, _(u"Show followers")) + sizer.Add(self.followers, 0, wx.ALL, 5) + self.friends = wx.CheckBox(self, -1, _(u"Show friends")) + sizer.Add(self.friends, 0, wx.ALL, 5) + self.favs = wx.CheckBox(self, -1, _(u"Show favourites")) + sizer.Add(self.favs, 0, wx.ALL, 5) + self.blocks = wx.CheckBox(self, -1, _(u"Show blocked users")) + sizer.Add(self.blocks, 0, wx.ALL, 5) + self.mutes = wx.CheckBox(self, -1, _(u"Show muted users")) + sizer.Add(self.mutes, 0, wx.ALL, 5) + self.events = wx.CheckBox(self, -1, _(u"Show events")) + sizer.Add(self.events, 0, wx.ALL, 5) + self.SetSizer(sizer) + +class ignoredClients(wx.Panel): + def __init__(self, parent, choices): + super(ignoredClients, self).__init__(parent=parent) + sizer = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(self, -1, _(u"Ignored clients")) + self.clients = wx.ListBox(self, -1, choices=choices) + self.clients.SetSize(self.clients.GetBestSize()) + clientsBox = wx.BoxSizer(wx.HORIZONTAL) + clientsBox.Add(label, 0, wx.ALL, 5) + clientsBox.Add(self.clients, 0, wx.ALL, 5) + add = wx.Button(self, -1, _(u"Add client")) + remove = wx.Button(self, -1, _(u"Remove client")) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(add, 0, wx.ALL, 5) + btnBox.Add(remove, 0, wx.ALL, 5) + sizer.Add(clientsBox, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + self.SetSizer(sizer) + +class sound(wx.Panel): + def __init__(self, parent, input_devices, output_devices, soundpacks): + wx.Panel.__init__(self, parent) + sizer = wx.BoxSizer(wx.VERTICAL) + volume = wx.StaticText(self, -1, _(u"Volume")) + self.volumeCtrl = wx.Slider(self) + self.volumeCtrl.SetRange(0, 100) + self.volumeCtrl.SetSize(self.volumeCtrl.GetBestSize()) + volumeBox = wx.BoxSizer(wx.HORIZONTAL) + volumeBox.Add(volume, 0, wx.ALL, 5) + volumeBox.Add(self.volumeCtrl, 0, wx.ALL, 5) + sizer.Add(volumeBox, 0, wx.ALL, 5) + self.global_mute = wx.CheckBox(self, -1, _(u"Global mute")) + sizer.Add(self.global_mute, 0, wx.ALL, 5) + output_label = wx.StaticText(self, -1, _(u"Output device")) + self.output = wx.ComboBox(self, -1, choices=output_devices, style=wx.CB_READONLY) + self.output.SetSize(self.output.GetBestSize()) + outputBox = wx.BoxSizer(wx.HORIZONTAL) + outputBox.Add(output_label, 0, wx.ALL, 5) + outputBox.Add(self.output, 0, wx.ALL, 5) + sizer.Add(outputBox, 0, wx.ALL, 5) + input_label = wx.StaticText(self, -1, _(u"Input device")) + self.input = wx.ComboBox(self, -1, choices=input_devices, style=wx.CB_READONLY) + self.input.SetSize(self.input.GetBestSize()) + inputBox = wx.BoxSizer(wx.HORIZONTAL) + inputBox.Add(input_label, 0, wx.ALL, 5) + inputBox.Add(self.input, 0, wx.ALL, 5) + sizer.Add(inputBox, 0, wx.ALL, 5) + soundBox = wx.BoxSizer(wx.VERTICAL) + soundpack_label = wx.StaticText(self, -1, _(u"Sound pack")) + self.soundpack = wx.ComboBox(self, -1, choices=soundpacks, style=wx.CB_READONLY) + self.soundpack.SetSize(self.soundpack.GetBestSize()) + soundBox.Add(soundpack_label, 0, wx.ALL, 5) + soundBox.Add(self.soundpack, 0, wx.ALL, 5) + sizer.Add(soundBox, 0, wx.ALL, 5) + self.SetSizer(sizer) + +class audioServicesPanel(wx.Panel): + def __init__(self, parent): + super(audioServicesPanel, self).__init__(parent) + mainSizer = wx.BoxSizer(wx.VERTICAL) + apiKeyLabel = wx.StaticText(self, -1, _(u"If you've got a SndUp account, enter your API Key here. Whether the API Key is wrong, the App will fail to upload anything to the server. Whether there's no API Key here, then the audio files will be uploaded anonimously")) + self.apiKey = wx.TextCtrl(self, -1) + dc = wx.WindowDC(self.apiKey) + dc.SetFont(self.apiKey.GetFont()) + self.apiKey.SetSize(dc.GetTextExtent("0"*100)) + apiKeyBox = wx.BoxSizer(wx.HORIZONTAL) + apiKeyBox.Add(apiKeyLabel, 0, wx.ALL, 5) + apiKeyBox.Add(self.apiKey, 0, wx.ALL, 5) + mainSizer.Add(apiKeyBox, 0, wx.ALL, 5) + first_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.dropbox = wx.Button(self, -1) + first_sizer.Add(self.dropbox, 0, wx.ALL, 5) + mainSizer.Add(first_sizer, 0, wx.ALL, 5) + self.SetSizer(mainSizer) + +class configurationDialog(wx.Dialog): + def __init__(self): + super(configurationDialog, self).__init__(None, -1) + self.panel = wx.Panel(self) + self.SetTitle(_(u"TW Blue preferences")) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.notebook = wx.Notebook(self.panel) + + def create_general(self, languageList): + self.general = general(self.notebook, languageList) + self.notebook.AddPage(self.general, _(u"General")) + self.general.SetFocus() + + def create_other_buffers(self): + self.buffers = other_buffers(self.notebook) + self.notebook.AddPage(self.buffers, _(u"Show other buffers")) + + def create_ignored_clients(self, ignored_clients_list): + self.ignored_clients = ignoredClients(self.notebook, ignored_clients_list) + self.notebook.AddPage(self.ignored_clients, _(u"Ignored clients")) + + def create_sound(self, output_devices, input_devices, soundpacks): + self.sound = sound(self.notebook, output_devices, input_devices, soundpacks) + self.notebook.AddPage(self.sound, _(u"Sound")) + def create_audio_services(self): + self.services = audioServicesPanel(self.notebook) + self.notebook.AddPage(self.services, _(u"Audio Services")) + + def realize(self): + self.sizer.Add(self.notebook, 0, wx.ALL, 5) + ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL) + ok = wx.Button(self.panel, wx.ID_OK, _(u"Save")) + ok.SetDefault() + cancel = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close")) + self.SetEscapeId(cancel.GetId()) + ok_cancel_box.Add(ok, 0, wx.ALL, 5) + ok_cancel_box.Add(cancel, 0, wx.ALL, 5) + self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5) + self.panel.SetSizer(self.sizer) + self.SetClientSize(self.sizer.CalcMin()) + + def get_value(self, panel, key): + p = getattr(self, panel) + return getattr(p, key).GetValue() + + def set_value(self, panel, key): + p = getattr(self, panel) + getattr(self, p).SetValue(key) + diff --git a/src/wxUI/dialogs/follow.py b/src/wxUI/dialogs/follow.py new file mode 100644 index 00000000..61831b1d --- /dev/null +++ b/src/wxUI/dialogs/follow.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +import wx + +class actionDialog(wx.Dialog): + def __init__(self, user=[], default="follow", *args, **kwargs): + super(actionDialog, self).__init__(parent=None, *args, **kwargs) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.SetTitle(_(u"Action")) + self.cb = wx.ComboBox(panel, -1, choices=user, value=user[0]) + self.cb.SetFocus() + userSizer.Add(self.cb) + actionSizer = wx.BoxSizer(wx.VERTICAL) + label2 = wx.StaticText(panel, -1, _(u"Action")) + self.follow = wx.RadioButton(panel, -1, _(u"Follow"), style=wx.RB_GROUP) + self.unfollow = wx.RadioButton(panel, -1, _(u"Unfollow")) + self.mute = wx.RadioButton(panel, -1, _(u"Mute")) + self.unmute = wx.RadioButton(panel, -1, _(u"Unmute")) + self.block = wx.RadioButton(panel, -1, _(u"Block")) + self.unblock = wx.RadioButton(panel, -1, _(u"Unblock")) + self.reportSpam = wx.RadioButton(panel, -1, _(u"Report as spam")) + self.setup_default(default) + actionSizer.Add(label2) + actionSizer.Add(self.follow) + actionSizer.Add(self.unfollow) + actionSizer.Add(self.mute) + actionSizer.Add(self.unmute) + actionSizer.Add(self.block) + actionSizer.Add(self.unblock) + actionSizer.Add(self.reportSpam) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok) + btnsizer.Add(cancel) + sizer.Add(userSizer) + sizer.Add(actionSizer) + sizer.Add(btnsizer) + panel.SetSizer(sizer) + + def get_action(self): + if self.follow.GetValue() == True: return "follow" + elif self.unfollow.GetValue() == True: return "unfollow" + elif self.mute.GetValue() == True: return "mute" + elif self.unmute.GetValue() == True: return "unmute" + elif self.reportSpam.GetValue() == True: return "report" + elif self.block.GetValue() == True: return "block" + elif self.unblock.GetValue() == True: return "unblock" + + def setup_default(self, default): + if default == "follow": + self.follow.SetValue(True) + elif default == "unfollow": + self.unfollow.SetValue(True) + elif default == "mute": + self.mute.SetValue(True) + elif default == "unmute": + self.unmute.SetValue(True) + elif default == "report": + self.reportSpam.SetValue(True) + elif default == "block": + self.block.SetValue(True) + elif default == "unblock": + self.unblock.SetValue(True) \ No newline at end of file diff --git a/src/wxUI/dialogs/lists.py b/src/wxUI/dialogs/lists.py new file mode 100644 index 00000000..95e8b7fe --- /dev/null +++ b/src/wxUI/dialogs/lists.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +import wx +from multiplatform_widgets import widgets + +class listViewer(wx.Dialog): + + def __init__(self, *args, **kwargs): + super(listViewer, self).__init__(parent=None, *args, **kwargs) + self.SetTitle(_(u"Lists manager")) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Lists")) + self.lista = widgets.list(panel, _(u"List"), _(u"Description"), _(u"Owner"), _(u"Members"), _(u"mode"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) + self.lista.list.SetFocus() + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label) + sizer.Add(self.lista.list) + self.createBtn = wx.Button(panel, wx.NewId(), _(u"Create a new list")) + self.editBtn = wx.Button(panel, -1, _(u"Edit")) + self.deleteBtn = wx.Button(panel, -1, _(u"Remove")) + self.view = wx.Button(panel, -1, _(u"Open in buffer")) +# self.members = wx.Button(panel, -1, _(u"View members")) +# self.members.Disable() +# self.subscriptors = wx.Button(panel, -1, _(u"View subscribers")) +# self.subscriptors.Disable() +# self.get_linkBtn = wx.Button(panel, -1, _(u"Get link for the list")) +# self.get_linkBtn.Bind(wx.EVT_BUTTON, self.onGetLink) + self.cancelBtn = wx.Button(panel, wx.ID_CANCEL) + btnSizer = wx.BoxSizer() + btnSizer.Add(self.createBtn) + btnSizer.Add(self.editBtn) + btnSizer.Add(self.cancelBtn) + panel.SetSizer(sizer) + + def populate_list(self, lists): + for item in lists: + self.lista.insert_item(False, *item) + + def get_item(self): + return self.lista.get_selected() + +class userListViewer(listViewer): + def __init__(self, username, *args, **kwargs): + self.username = username + super(userListViewer, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Viewing lists for %s") % (self.username)) + self.createBtn.SetLabel(_(u"Subscribe")) + self.deleteBtn.SetLabel(_(u"Unsubscribe")) + self.editBtn.Disable() + self.view.Disable() + +class createListDialog(wx.Dialog): + + def __init__(self, *args, **kwargs): + super(createListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Create a new list")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + name = wx.StaticText(panel, -1, _(u"Name (20 characters maximun)")) + self.name = wx.TextCtrl(panel, -1) + nameSizer = wx.BoxSizer(wx.HORIZONTAL) + nameSizer.Add(name) + nameSizer.Add(self.name) + description = wx.StaticText(panel, -1, _(u"Description")) + self.description = wx.TextCtrl(panel, -1) + descriptionSizer = wx.BoxSizer(wx.HORIZONTAL) + descriptionSizer.Add(description) + descriptionSizer.Add(self.description) + mode = wx.StaticText(panel, -1, _(u"Mode")) + self.public = wx.RadioButton(panel, -1, _(u"Public"), style=wx.RB_GROUP) + self.private = wx.RadioButton(panel, -1, _(u"Private")) + modeBox = wx.BoxSizer(wx.HORIZONTAL) + modeBox.Add(mode) + modeBox.Add(self.public) + modeBox.Add(self.private) + ok = wx.Button(panel, wx.ID_OK) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(ok) + btnBox.Add(cancel) + sizer.Add(nameSizer) + sizer.Add(descriptionSizer) + sizer.Add(modeBox) + sizer.Add(btnBox) + + def get(self, field): + return getattr(self, field).GetValue() + +class editListDialog(createListDialog): + + def __init__(self, list, *args, **kwargs): + super(editListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Editing the list %s") % (list["name"])) + self.name.ChangeValue(list["name"]) + self.description.ChangeValue(list["description"]) + if list["mode"] == "public": + self.public.SetValue(True) + else: + self.private.SetValue(True) + +class addUserListDialog(listViewer): + def __init__(self, *args, **kwargs): + super(addUserListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Select a list to add the user")) + self.createBtn.SetLabel(_(u"Add")) + self.createBtn.SetDefault() + self.editBtn.Disable() + self.view.Disable() +# self.subscriptors.Disable() +# self.members.Disable() + self.deleteBtn.Disable() + +class removeUserListDialog(listViewer): + def __init__(self, *args, **kwargs): + super(removeUserListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Select a list to remove the user")) + self.createBtn.SetLabel(_(u"Remove")) + self.createBtn.SetDefault() + self.editBtn.Disable() + self.view.Disable() +# self.subscriptors.Disable() +# self.members.Disable() + self.deleteBtn.Disable() \ No newline at end of file diff --git a/src/wxUI/dialogs/message.py b/src/wxUI/dialogs/message.py new file mode 100644 index 00000000..4e403ac4 --- /dev/null +++ b/src/wxUI/dialogs/message.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +import wx +import baseDialog + +class textLimited(baseDialog.BaseWXDialog): + def __init__(self, *args, **kwargs): + super(textLimited, self).__init__(parent=None, *args, **kwargs) + + def createTextArea(self, message="", text=""): + self.panel = wx.Panel(self) + self.label = wx.StaticText(self.panel, -1, message) + self.SetTitle(str(len(text))) + self.text = wx.TextCtrl(self.panel, -1, text) + font = self.text.GetFont() + dc = wx.WindowDC(self.text) + dc.SetFont(font) + x, y = dc.GetTextExtent("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + self.text.SetSize((x, y)) + self.text.SetFocus() + self.textBox = wx.BoxSizer(wx.HORIZONTAL) + self.textBox.Add(self.label, 0, wx.ALL, 5) + self.textBox.Add(self.text, 0, wx.ALL, 5) + + def get_text(self): + return self.text.GetValue() + + def onSelect(self, ev): + self.text.SelectAll() + +class tweet(textLimited): + def createControls(self, message, title, text): + self.mainBox = wx.BoxSizer(wx.VERTICAL) + self.createTextArea(message, text) + self.mainBox.Add(self.textBox, 0, wx.ALL, 5) + self.upload_image = wx.Button(self.panel, -1, _(u"Upload a picture"), size=wx.DefaultSize) + self.spellcheck = wx.Button(self.panel, -1, _("Spelling correction"), size=wx.DefaultSize) + self.attach = wx.Button(self.panel, -1, _(u"Attach audio"), size=wx.DefaultSize) + self.shortenButton = wx.Button(self.panel, -1, _(u"Shorten URL"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(self.panel, -1, _(u"Expand URL"), size=wx.DefaultSize) + self.shortenButton.Disable() + self.unshortenButton.Disable() + self.translateButton = wx.Button(self.panel, -1, _(u"Translate message"), size=wx.DefaultSize) + self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Send"), size=wx.DefaultSize) + self.okButton.SetDefault() + cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize) + self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 5) + self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 5) + self.buttonsBox1.Add(self.attach, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) + self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 5) + self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 5) + self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 5) + self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) + self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 5) + self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 5) + self.mainBox.Add(self.ok_cancelSizer) + selectId = wx.NewId() + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ +(wx.ACCEL_CTRL, ord('A'), selectId), +]) + self.SetAcceleratorTable(self.accel_tbl) + self.panel.SetSizer(self.mainBox) + + def __init__(self, message, title, text): + super(tweet, self).__init__() + self.createControls(message, title, text) +# self.onTimer(wx.EVT_CHAR_HOOK) + self.SetClientSize(self.mainBox.CalcMin()) + +class dm(textLimited): + def createControls(self, message, title, users): + self.panel = wx.Panel(self) + self.mainBox = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(self.panel, -1, _(u"Recipient")) + self.cb = wx.ComboBox(self.panel, -1, choices=users, value=users[0], size=wx.DefaultSize) + self.createTextArea(message, text="") + self.mainBox.Add(self.cb, 0, wx.ALL, 5) + self.mainBox.Add(self.textBox, 0, wx.ALL, 5) + self.spellcheck = wx.Button(self.panel, -1, _("Spelling correction"), size=wx.DefaultSize) + self.attach = wx.Button(self.panel, -1, _(u"Attach audio"), size=wx.DefaultSize) + self.shortenButton = wx.Button(self.panel, -1, _(u"Shorten URL"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(self.panel, -1, _(u"Expand URL"), size=wx.DefaultSize) + self.shortenButton.Disable() + self.unshortenButton.Disable() + self.translateButton = wx.Button(self.panel, -1, _(u"Translate message"), size=wx.DefaultSize) + self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Send"), size=wx.DefaultSize) + self.okButton.SetDefault() + cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize) + self.buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + self.buttonsBox.Add(self.attach, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox, 0, wx.ALL, 5) + self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox1.Add(self.shortenButton, 0, wx.ALL, 5) + self.buttonsBox1.Add(self.unshortenButton, 0, wx.ALL, 5) + self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) + self.buttonsBox3 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox3.Add(self.okButton, 0, wx.ALL, 5) + self.buttonsBox3.Add(cancelButton, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox3, 0, wx.ALL, 5) + self.panel.SetSizer(self.mainBox) + + def __init__(self, message, title, users): + super(dm, self).__init__() + self.createControls(message, title, users) +# self.onTimer(wx.EVT_CHAR_HOOK) + self.SetClientSize(self.mainBox.CalcMin()) + +class reply(tweet): + def __init__(self, message, title, text): + super(reply, self).__init__(message, title, text) + self.text.SetInsertionPoint(len(self.text.GetValue())) + self.mentionAll = wx.Button(self, -1, _(u"Mention to all"), size=wx.DefaultSize) + self.mentionAll.Disable() + self.buttonsBox1.Add(self.mentionAll, 0, wx.ALL, 5) + self.buttonsBox1.Layout() + self.mainBox.Layout() + self.SetClientSize(self.mainBox.CalcMin()) + +class viewTweet(wx.Dialog): + def __init__(self, tweet): + super(viewTweet, self).__init__(None, size=(850,850)) + self.SetTitle(_(u"Tweet - %i characters ") % (len(tweet))) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Tweet")) + self.text = wx.TextCtrl(panel, -1, tweet, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y, z) = dc.GetMultiLineTextExtent("0"*140) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + spellcheck = wx.Button(panel, -1, _("Spelling correction"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(panel, -1, _(u"Expand URL"), size=wx.DefaultSize) + self.unshortenButton.Disable() + translateButton = wx.Button(panel, -1, _(u"Translate message"), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize) + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) + buttonsBox.Add(translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.NewId() + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ +(wx.ACCEL_CTRL, ord('A'), selectId), +]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) + + def onSelect(self, ev): + self.text.SelectAll() \ No newline at end of file diff --git a/src/gui/dialogs/search.py b/src/wxUI/dialogs/search.py similarity index 52% rename from src/gui/dialogs/search.py rename to src/wxUI/dialogs/search.py index 60c54f55..c6c6a52c 100644 --- a/src/gui/dialogs/search.py +++ b/src/wxUI/dialogs/search.py @@ -1,24 +1,8 @@ # -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ +import baseDialog import wx -class searchDialog(wx.Dialog): +class searchDialog(baseDialog.BaseWXDialog): def __init__(self): super(searchDialog, self).__init__(None, -1) panel = wx.Panel(self) @@ -45,4 +29,4 @@ class searchDialog(wx.Dialog): btnsizer.Add(cancel, 0, wx.ALL, 5) sizer.Add(btnsizer, 0, wx.ALL, 5) panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + self.SetClientSize(sizer.CalcMin()) \ No newline at end of file diff --git a/src/wxUI/dialogs/show_user.py b/src/wxUI/dialogs/show_user.py new file mode 100644 index 00000000..cfe7b191 --- /dev/null +++ b/src/wxUI/dialogs/show_user.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +import wx + +class showUserProfile(wx.Dialog): + def __init__(self, screen_name): + super(showUserProfile, self).__init__(self, None, -1) + self.SetTitle(_(u"Information for %s") % (screen_name)) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + static = wx.StaticText(panel, -1, _(u"Details")) + sizer.Add(static, 0, wx.ALL, 5) + text = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY) + text.SetFocus() + sizer.Add(text, 0, wx.ALL|wx.EXPAND, 5) + self.url = wx.Button(panel, -1, _(u"Go to URL"), size=wx.DefaultSize) + self.url.Disable() + close = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add(self.url, 0, wx.ALL, 5) + btnSizer.Add(close, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + text.ChangeValue(self.compose_string()) + text.SetSize(text.GetBestSize()) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def get_response(self): + return self.ShowModal() \ No newline at end of file diff --git a/src/gui/dialogs/update_profile.py b/src/wxUI/dialogs/update_profile.py similarity index 58% rename from src/gui/dialogs/update_profile.py rename to src/wxUI/dialogs/update_profile.py index fe1f1b32..9feabd24 100644 --- a/src/gui/dialogs/update_profile.py +++ b/src/wxUI/dialogs/update_profile.py @@ -1,28 +1,8 @@ # -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . -# -############################################################ import wx -from twython import TwythonError class updateProfile(wx.Dialog): def __init__(self, parent): - self.twitter = parent.twitter - self.parent = parent super(updateProfile, self).__init__(parent=None, id=-1) self.SetTitle(_(u"Update your profile")) panel = wx.Panel(self) @@ -78,42 +58,18 @@ class updateProfile(wx.Dialog): sizer.Add(btnBox, 0, wx.ALL, 5) panel.SetSizer(sizer) self.SetClientSize(sizer.CalcMin()) - self.get_data() def onUpload_picture(self, ev): if self.upload_image.GetLabel() == _(u"Discard image"): - self.image = None - del self.file - output.speak(_(u"Discarded")) self.upload_image.SetLabel(_(u"Upload a picture")) + self.controller.clear_file() else: openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if openFileDialog.ShowModal() == wx.ID_CANCEL: return - self.file = open(openFileDialog.GetPath(), "rb") - self.image = True + self.controller.get_file(openFileDialog.GetPath()) self.upload_image.SetLabel(_(u"Discard image")) ev.Skip() - def onUpdateProfile(self, ev): - try: - if self.image != None: - self.twitter.twitter.update_profile_image(image=self.file) - except TwythonError as e: - output.speak(u"Error %s. %s" % (e.error_code, e.msg)) - try: - f = self.twitter.twitter.update_profile(name=self.name.GetValue(), location=self.location.GetValue(), url=self.url.GetValue(), description=self.description.GetValue()) - self.EndModal(wx.ID_OK) - except TwythonError as e: - output.speak(u"Error %s. %s" % (e.error_code, e.msg)) - return - - def get_data(self): - data = self.twitter.twitter.show_user(screen_name=self.parent.db.settings["user_name"]) - self.name.ChangeValue(data["name"]) - if data["url"] != None: - self.url.ChangeValue(data["url"]) - if len(data["location"]) > 0: - self.location.ChangeValue(data["location"]) - if len(data["description"]) > 0: - self.description.ChangeValue(data["description"]) \ No newline at end of file + def get_response(self): + return self.ShowModal() \ No newline at end of file diff --git a/src/wxUI/dialogs/urlList.py b/src/wxUI/dialogs/urlList.py new file mode 100644 index 00000000..7a02008e --- /dev/null +++ b/src/wxUI/dialogs/urlList.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +import wx + +class urlList(wx.Dialog): + def __init__(self): + super(urlList, self).__init__(parent=None, title=_(u"Select an URL")) + panel = wx.Panel(self) + self.lista = wx.ListBox(panel, -1) + self.lista.SetFocus() + self.lista.SetSize(self.lista.GetBestSize()) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.lista, 0, wx.ALL, 5) + goBtn = wx.Button(panel, wx.ID_OK) + goBtn.SetDefault() + cancelBtn = wx.Button(panel, wx.ID_CANCEL) + btnSizer = wx.BoxSizer() + btnSizer.Add(goBtn, 0, wx.ALL, 5) + btnSizer.Add(cancelBtn, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def populate_list(self, urls): + for i in urls: + self.lista.Append(i) + self.lista.SetSelection(0) + + def get_string(self): + return self.lista.GetStringSelection() + + def get_item(self): + return self.lista.GetSelection() + + def get_response(self): + return self.ShowModal() \ No newline at end of file diff --git a/src/wxUI/dialogs/utils.py b/src/wxUI/dialogs/utils.py new file mode 100644 index 00000000..a615775f --- /dev/null +++ b/src/wxUI/dialogs/utils.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +import wx + +class selectUserDialog(wx.Dialog): + def __init__(self, users, *args, **kwargs): + super(selectUserDialog, self).__init__(self, None, -1, *args, **kwargs) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize) + self.cb.SetFocus() + userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) + userSizer.Add(self.cb) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(userSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def get_selection(self): + return self.cb.GetValue() + + def get_response(self): + return self.ShowModal() \ No newline at end of file diff --git a/src/gui/sysTrayIcon.py b/src/wxUI/sysTrayIcon.py similarity index 100% rename from src/gui/sysTrayIcon.py rename to src/wxUI/sysTrayIcon.py diff --git a/src/wxUI/view.py b/src/wxUI/view.py new file mode 100644 index 00000000..83daba14 --- /dev/null +++ b/src/wxUI/view.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +import wx + +class mainFrame(wx.Frame): + """ Main class of the Frame. This is the Main Window.""" + + ### MENU + def makeMenus(self): + """ Creates, bind and returns the menu bar for the application. Also in this function, the accel table is created.""" + menuBar = wx.MenuBar() + + # Application menu + app = wx.Menu() + updateProfile = app.Append(wx.NewId(), _(u"&Update profile")) +# self.Bind(wx.EVT_MENU, self.controller.update_profile, updateProfile) + show_hide = app.Append(wx.NewId(), _(u"&Hide window")) +# self.Bind(wx.EVT_MENU, self.controller.show_hide, show_hide) + search = app.Append(wx.NewId(), _(u"&Search")) + self.Bind(wx.EVT_MENU, self.controller.search, search) + lists = app.Append(wx.NewId(), _(u"&Lists manager")) +# self.view.Bind(wx.EVT_MENU, self.list_manager, lists) + sounds_tutorial = app.Append(wx.NewId(), _(u"Sounds &tutorial")) +# self.view.Bind(wx.EVT_MENU, self.learn_sounds, sounds_tutorial) + keystroke_editor = app.Append(wx.NewId(), _(u"&Edit keystrokes")) + self.Bind(wx.EVT_MENU, self.controller.edit_keystrokes, keystroke_editor) + prefs = app.Append(wx.ID_PREFERENCES, _(u"&Preferences")) +# self.view.Bind(wx.EVT_MENU, self.preferences, prefs) + close = app.Append(wx.ID_EXIT, _(u"E&xit")) +# self.view.Bind(wx.EVT_MENU, self.close, close) + + # Tweet menu + tweet = wx.Menu() + compose = tweet.Append(wx.NewId(), _(u"&Tweet")) +# self.view.Bind(wx.EVT_MENU, self.compose, compose) + response = tweet.Append(wx.NewId(), _(u"Re&ply")) +# self.view.Bind(wx.EVT_MENU, self.reply, response) + retweet = tweet.Append(wx.NewId(), _(u"&Retweet")) +# self.view.Bind(wx.EVT_MENU, self.retweet, retweet) + fav = tweet.Append(wx.NewId(), _(u"Add to &favourites")) +# self.view.Bind(wx.EVT_MENU, self.fav, fav) + unfav = tweet.Append(wx.NewId(), _(u"Remove from favo&urites")) +# self.view.Bind(wx.EVT_MENU, self.unfav, unfav) + view = tweet.Append(wx.NewId(), _(u"&Show tweet")) +# self.view.Bind(wx.EVT_MENU, self.view, view) + delete = tweet.Append(wx.NewId(), _(u"&Delete")) +# self.view.Bind(wx.EVT_MENU, self.delete, delete) + + # User menu + user = wx.Menu() + follow = user.Append(wx.NewId(), _(u"&Follow")) +# self.view.Bind(wx.EVT_MENU, self.onFollow, follow) + unfollow = user.Append(wx.NewId(), _(u"&Unfollow")) +# self.view.Bind(wx.EVT_MENU, self.onUnfollow, unfollow) + mute = user.Append(wx.NewId(), _(u"&Mute")) +# self.view.Bind(wx.EVT_MENU, self.onMute, mute) + unmute = user.Append(wx.NewId(), _(u"U&nmute")) +# self.view.Bind(wx.EVT_MENU, self.onUnmute, unmute) + report = user.Append(wx.NewId(), _(u"&Report as spam")) +# self.view.Bind(wx.EVT_MENU, self.onReport, report) + block = user.Append(wx.NewId(), _(u"&Block")) +# self.view.Bind(wx.EVT_MENU, self.onBlock, block) + unblock = user.Append(wx.NewId(), _(u"Unb&lock")) +# self.view.Bind(wx.EVT_MENU, self.onUnblock, unblock) + dm = user.Append(wx.NewId(), _(u"Direct me&ssage")) +# self.view.Bind(wx.EVT_MENU, self.dm, dm) + addToList = user.Append(wx.NewId(), _(u"&Add to list")) +# self.view.Bind(wx.EVT_MENU, self.add_to_list, addToList) + removeFromList = user.Append(wx.NewId(), _(u"R&emove from list")) +# self.view.Bind(wx.EVT_MENU, self.remove_from_list, removeFromList) + viewLists = user.Append(wx.NewId(), _(u"&View lists")) +# self.view.Bind(wx.EVT_MENU, self.view_user_lists, viewLists) + details = user.Append(wx.NewId(), _(u"Show user &profile")) +# self.view.Bind(wx.EVT_MENU, self.details, details) + timeline = user.Append(wx.NewId(), _(u"&Timeline")) +# self.view.Bind(wx.EVT_MENU, self.open_timeline, timeline) + favs = user.Append(wx.NewId(), _(u"V&iew favourites")) +# self.view.Bind(wx.EVT_MENU, self.favs_timeline, favs) + + # buffer menu + buffer = wx.Menu() + mute = buffer.Append(wx.NewId(), _(u"&Mute")) +# self.view.Bind(wx.EVT_MENU, self.toggle_mute, mute) + autoread = buffer.Append(wx.NewId(), _(u"&Autoread tweets for this buffer")) +# self.view.Bind(wx.EVT_MENU, self.toggle_autoread, autoread) + clear = buffer.Append(wx.NewId(), _(u"&Clear buffer")) +# self.view.Bind(wx.EVT_MENU, self.clear_list, clear) + deleteTl = buffer.Append(wx.NewId(), _(u"&Remove buffer")) +# self.view.Bind(wx.EVT_MENU, self.delete_buffer, deleteTl) + + # Help Menu + help = wx.Menu() + doc = help.Append(-1, _(u"&Documentation")) +# self.view.Bind(wx.EVT_MENU, self.onManual, doc) + changelog = help.Append(wx.NewId(), _(u"&What's new in this version?")) +# self.view.Bind(wx.EVT_MENU, self.onChangelog, changelog) + check_for_updates = help.Append(wx.NewId(), _(u"&Check for updates")) +# self.view.Bind(wx.EVT_MENU, self.onCheckForUpdates, check_for_updates) + reportError = help.Append(wx.NewId(), _(u"&Report an error")) +# self.view.Bind(wx.EVT_MENU, self.onReportBug, reportError) + visit_website = help.Append(-1, _(u"TW Blue &website")) +# self.view.Bind(wx.EVT_MENU, self.onVisit_website, visit_website) + about = help.Append(-1, _(u"About &TW Blue")) +# self.view.Bind(wx.EVT_MENU, self.onAbout, about) + + # Add all to the menu Bar + menuBar.Append(app, _(u"&Application")) + menuBar.Append(tweet, _(u"&Tweet")) + menuBar.Append(user, _(u"&User")) + menuBar.Append(buffer, _(u"&Buffer")) + menuBar.Append(help, _(u"&Help")) + + self.accel_tbl = wx.AcceleratorTable([ +(wx.ACCEL_CTRL, ord('N'), compose.GetId()), +(wx.ACCEL_CTRL, ord('R'), response.GetId()), +(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('R'), retweet.GetId()), +(wx.ACCEL_CTRL, ord('F'), fav.GetId()), +(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('F'), unfav.GetId()), +(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('V'), view.GetId()), +(wx.ACCEL_CTRL, ord('D'), dm.GetId()), + +(wx.ACCEL_CTRL, ord('Q'), close.GetId()), +(wx.ACCEL_CTRL, ord('S'), follow.GetId()), +(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('S'), unfollow.GetId()), +(wx.ACCEL_CTRL, ord('K'), block.GetId()), +(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('K'), report.GetId()), +(wx.ACCEL_CTRL, ord('I'), timeline.GetId()), +(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('I'), deleteTl.GetId()), +(wx.ACCEL_CTRL, ord('M'), show_hide.GetId()), +(wx.ACCEL_CTRL, ord('P'), updateProfile.GetId()), + ]) + + self.SetAcceleratorTable(self.accel_tbl) + return menuBar + + ### MAIN + def __init__(self, controller): + """ Main function of this class.""" + super(mainFrame, self).__init__(None, -1, "TW Blue", size=(1600, 1600)) + self.controller = controller + self.panel = wx.Panel(self) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle("TW Blue") + self.SetMenuBar(self.makeMenus()) + self.nb = wx.Treebook(self.panel, wx.NewId()) + self.buffers = {} + self.SetMenuBar(self.makeMenus()) + + def add_buffer(self, buffer, name): + self.nb.AddPage(buffer, name) + self.buffers[name] = buffer.GetId() + + def insert_buffer(self, buffer, name, pos): + self.nb.InsertSubPage(pos, buffer, name) + self.buffers[name] = buffer.GetId() + + def prepare(self): + self.sizer.Add(self.nb, 0, wx.ALL, 5) + self.panel.SetSizer(self.sizer) + self.SetClientSize(self.sizer.CalcMin()) + + def search(self, name_, account): + for i in range(0, self.nb.GetPageCount()): + if self.nb.GetPage(i).name == name_ and self.nb.GetPage(i).account == account: return i + + def get_current_buffer(self): + return self.nb.GetCurrentPage() + + def get_buffer(self, pos): + return self.GetPage(pos) + + def get_buffer_by_id(self, id): + return self.nb.FindWindowById(id) + + def show(self): + self.Show() \ No newline at end of file