From 2e32fa7ef2cfd8999dde186753cd204a8ff92462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Cort=C3=A9z?= Date: Fri, 3 Apr 2015 16:57:08 -0600 Subject: [PATCH] First great commit for Gtk. It is partially functional now --- src/controller/buffersController.py | 32 ++- src/controller/mainController.py | 38 ++-- src/controller/messages.py | 16 +- src/extra/SoundsTutorial/__init__.py | 2 +- src/extra/SoundsTutorial/gtk_ui.py | 25 +++ src/extra/SoundsTutorial/soundsTutorial.py | 10 +- src/extra/SoundsTutorial/wx_ui.py | 5 +- src/gtkUI/__init__.py | 11 + src/gtkUI/buffers/__init__.py | 11 + src/gtkUI/buffers/base.py | 31 +++ src/gtkUI/buffers/dm.py | 14 ++ src/gtkUI/buffers/events.py | 25 +++ src/gtkUI/buffers/favourites.py | 8 + src/gtkUI/buffers/lists.py | 9 + src/gtkUI/buffers/panels.py | 32 +++ src/gtkUI/buffers/people.py | 17 ++ src/gtkUI/buffers/trends.py | 26 +++ src/gtkUI/buffers/tweet_searches.py | 8 + src/gtkUI/buffers/user_searches.py | 14 ++ src/gtkUI/commonMessageDialogs.py | 57 +++++ src/gtkUI/dialogs/__init__.py | 1 + src/gtkUI/dialogs/configuration.py | 240 ++++++++++++++++++++ src/gtkUI/dialogs/lists.py | 123 +++++++++++ src/gtkUI/dialogs/message.py | 246 +++++++++++++++++++++ src/gtkUI/dialogs/search.py | 32 +++ src/gtkUI/dialogs/show_user.py | 26 +++ src/gtkUI/dialogs/trends.py | 46 ++++ src/gtkUI/dialogs/update_profile.py | 98 ++++++++ src/gtkUI/dialogs/urlList.py | 35 +++ src/gtkUI/dialogs/userActions.py | 81 +++++++ src/gtkUI/dialogs/userSelection.py | 51 +++++ src/gtkUI/dialogs/utils.py | 46 ++++ src/gtkUI/sysTrayIcon.py | 48 ++++ src/gtkUI/view.py | 196 ++++++++++++++++ src/keys/__init__.py | 6 +- src/keys/linuxKeys.py | 21 ++ src/languageHandler.py | 6 +- src/main.py | 77 ++++--- src/sessionmanager/gtkUI.py | 22 +- src/sessionmanager/sessionManager.py | 20 +- src/twitter/compose.py | 28 ++- src/widgetUtils/gtkUtils.py | 78 ++++++- src/widgetUtils/wxUtils.py | 4 +- src/wxUI/view.py | 2 +- 44 files changed, 1814 insertions(+), 110 deletions(-) create mode 100644 src/extra/SoundsTutorial/gtk_ui.py create mode 100644 src/gtkUI/__init__.py create mode 100644 src/gtkUI/buffers/__init__.py create mode 100644 src/gtkUI/buffers/base.py create mode 100644 src/gtkUI/buffers/dm.py create mode 100644 src/gtkUI/buffers/events.py create mode 100644 src/gtkUI/buffers/favourites.py create mode 100644 src/gtkUI/buffers/lists.py create mode 100644 src/gtkUI/buffers/panels.py create mode 100644 src/gtkUI/buffers/people.py create mode 100644 src/gtkUI/buffers/trends.py create mode 100644 src/gtkUI/buffers/tweet_searches.py create mode 100644 src/gtkUI/buffers/user_searches.py create mode 100644 src/gtkUI/commonMessageDialogs.py create mode 100644 src/gtkUI/dialogs/__init__.py create mode 100644 src/gtkUI/dialogs/configuration.py create mode 100644 src/gtkUI/dialogs/lists.py create mode 100644 src/gtkUI/dialogs/message.py create mode 100644 src/gtkUI/dialogs/search.py create mode 100644 src/gtkUI/dialogs/show_user.py create mode 100644 src/gtkUI/dialogs/trends.py create mode 100644 src/gtkUI/dialogs/update_profile.py create mode 100644 src/gtkUI/dialogs/urlList.py create mode 100644 src/gtkUI/dialogs/userActions.py create mode 100644 src/gtkUI/dialogs/userSelection.py create mode 100644 src/gtkUI/dialogs/utils.py create mode 100644 src/gtkUI/sysTrayIcon.py create mode 100644 src/gtkUI/view.py create mode 100644 src/keys/linuxKeys.py diff --git a/src/controller/buffersController.py b/src/controller/buffersController.py index d2079c01..b705b667 100644 --- a/src/controller/buffersController.py +++ b/src/controller/buffersController.py @@ -1,17 +1,22 @@ # -*- coding: utf-8 -*- -import wx +import platform +if platform.system() == "Windows": + import wx + from wxUI import buffers, dialogs, commonMessageDialogs + import user +elif platform.system() == "Linux": + from gi.repository import Gtk + from gtkUI import buffers, dialogs, commonMessageDialogs +import messages import widgetUtils import arrow import webbrowser import output import config import sound -import messages -import user import languageHandler import logging from twitter import compose, utils -from wxUI import buffers, dialogs, commonMessageDialogs from mysc.thread_utils import call_threaded from twython import TwythonError from pubsub import pub @@ -127,6 +132,7 @@ class bufferController(object): call_threaded(self.session.api_call, call_name="update_status", status=text) else: call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image) + if hasattr(tweet.message, "destroy"): tweet.message.destroy() class accountPanel(bufferController): def __init__(self, parent, name, account, account_id): @@ -137,7 +143,6 @@ class accountPanel(bufferController): self.compose_function = None self.session = None self.needs_init = False - self.id = self.buffer.GetId() self.account = account self.buffer.account = account self.name = name @@ -155,7 +160,7 @@ class accountPanel(bufferController): else: self.buffer.change_login(login=True) widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login) - + def login(self, *args, **kwargs): del self.logged self.setup_account() @@ -181,7 +186,6 @@ class emptyPanel(bufferController): 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 @@ -199,7 +203,6 @@ class baseBufferController(bufferController): self.invisible = True self.name = name self.type = self.buffer.type - self.id = self.buffer.GetId() self.session = sessionObject self.compose_function = compose.compose_tweet log.debug("Compose_function: %s" % (self.compose_function,)) @@ -302,8 +305,9 @@ class baseBufferController(bufferController): def bind_events(self): log.debug("Binding events...") - self.buffer.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocus) - self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) + ### disconnect this for wx +# self.buffer.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocus) +# self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_tweet, self.buffer.tweet) # if self.type == "baseBuffer": widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.retweet, self.buffer.retweet) @@ -333,6 +337,7 @@ class baseBufferController(bufferController): call_threaded(self.session.api_call, call_name="update_status", _sound="reply_send.ogg", in_reply_to_status_id=id, status=message.message.get_text()) else: call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", in_reply_to_status_id=id, status=message.message.get_text(), media=message.file) + if hasattr(message.message, "destroy"): message.message.destroy() @_tweets_exist def direct_message(self, *args, **kwargs): @@ -349,6 +354,7 @@ class baseBufferController(bufferController): dm = messages.dm(self.session, _(u"Direct message to %s") % (screen_name,), _(u"New direct message"), users) if dm.message.get_response() == widgetUtils.OK: call_threaded(self.session.api_call, call_name="send_direct_message", text=dm.message.get_text(), screen_name=dm.message.get("cb")) + if hasattr(dm.message, "destroy"): dm.message.destroy() @_tweets_exist def retweet(self, *args, **kwargs): @@ -362,6 +368,7 @@ class baseBufferController(bufferController): call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=retweet.message.get_text(), in_reply_to_status_id=id) else: call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=retweet.message.get_text(), in_reply_to_status_id=id, media=retweet.image) + if hasattr(retweet.message, "destroy"): retweet.message.destroy() elif answer == widgetUtils.NO: call_threaded(self.session.api_call, call_name="retweet", _sound="retweet_send.ogg", id=id) @@ -389,6 +396,7 @@ class baseBufferController(bufferController): urls_list.populate_list(urls) if urls_list.get_response() == widgetUtils.OK: sound.URLPlayer.play(urls_list.get_string(), self.session.settings["sound"]["volume"]) + if hasattr(urls_list, "destroy"): urls_list.destroy() @_tweets_exist def url(self): @@ -403,6 +411,7 @@ class baseBufferController(bufferController): if urls_list.get_response() == widgetUtils.OK: output.speak(_(u"Opening URL...")) webbrowser.open_new_tab(urls_list.get_string()) + if hasattr(urls_list, "destroy"): urls_list.destroy() def clear_list(self): dlg = commonMessageDialogs.clear_list() @@ -439,6 +448,7 @@ class baseBufferController(bufferController): dlg = dialogs.utils.selectUserDialog(title=_(u"User details"), users=users) if dlg.get_response() == widgetUtils.OK: user.profileController(session=self.session, user=dlg.get_user()) + if hasattr(dlg, "destroy"): dlg.destroy() class eventsBufferController(bufferController): def __init__(self, parent, name, session, account, *args, **kwargs): @@ -448,7 +458,6 @@ class eventsBufferController(bufferController): self.buffer = buffers.eventsPanel(parent, name) self.name = name self.account = account - self.id = self.buffer.GetId() self.buffer.account = self.account self.compose_function = compose.compose_event self.session = session @@ -503,6 +512,7 @@ class peopleBufferController(baseBufferController): call_threaded(self.session.api_call, call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text()) else: call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) + if hasattr(message.message, "destroy"): message.message.destroy() def start_stream(self): log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,)) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index f3e426e2..1bfb4434 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1,13 +1,25 @@ # -*- coding: utf-8 -*- +import platform +system = platform.system() import application -from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon) +if system == "Windows": + from update import updater + from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon) + import settings + from extra import SoundsTutorial + import keystrokeEditor + from keyboard_handler.wx_handler import WXKeyboardHandler + import userActionsController + import trendingTopics + import user + from issueReporter import issueReporter +elif system == "Linux": + from gtkUI import (view,) from twitter import utils from sessionmanager import manager, sessionManager -from update import updater import buffersController import messages -import settings from sessionmanager import session as session_ from pubsub import pub import sound @@ -20,18 +32,9 @@ import config import widgetUtils import pygeocoder from pygeolib import GeocoderError -import platform -from extra import SoundsTutorial import logging -if platform.system() == "Windows": - import keystrokeEditor - from keyboard_handler.wx_handler import WXKeyboardHandler -import userActionsController -import trendingTopics -import user import webbrowser from long_tweets import twishort -from issueReporter import issueReporter log = logging.getLogger("mainController") @@ -199,11 +202,13 @@ class Controller(object): self.current_account = "" self.view.prepare() self.bind_stream_events() - self.bind_other_events() - self.set_systray_icon() + if system == "Windows": + self.bind_other_events() + self.set_systray_icon() def check_invisible_at_startup(self): - # Visibility check + # Visibility check. It does only work for windows. + if system != "Windows": return if config.app["app-settings"]["hide_gui"] == True: self.show_hide() self.view.Show() @@ -484,6 +489,7 @@ class Controller(object): if hasattr(session_.sessions[item], "main_stream"): session_.sessions[item].main_stream.disconnect() if hasattr(session_.sessions[item], "timelinesStream"): session_.sessions[item].timelinesStream.disconnect() session_.sessions[item].sound.cleaner.cancel() + if system == "Windows": self.systrayIcon.RemoveIcon() widgetUtils.exit_application() @@ -1200,4 +1206,4 @@ class Controller(object): output.speak(_(u"Buffer mute off")) def __del__(self): - config.app.write() \ No newline at end of file + config.app.write() diff --git a/src/controller/messages.py b/src/controller/messages.py index a9c2e1bc..3ead795d 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -1,12 +1,17 @@ # -*- coding: utf-8 -*- +import platform +system = platform.system() import widgetUtils import output import url_shortener import sound from pubsub import pub -from wxUI.dialogs import message, urlList -from extra import translator, SpellChecker, autocompletionUsers -from extra.AudioUploader import audioUploader +if system == "Windows": + from wxUI.dialogs import message, urlList + from extra import translator, SpellChecker, autocompletionUsers + from extra.AudioUploader import audioUploader +elif system == "Linux": + from gtkUI.dialogs import message from twitter import utils class basicTweet(object): @@ -18,11 +23,12 @@ class basicTweet(object): self.message = getattr(message, messageType)(title, caption, text) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach) +# if system == "Windows": widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor) + self.text_processor() widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten) widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - self.text_processor() def translate(self, event=None): dlg = translator.gui.translateDialog() @@ -171,4 +177,4 @@ class viewTweet(basicTweet): def contain_urls(self): if len(utils.find_urls_in_text(self.message.get_text())) > 0: return True - return False \ No newline at end of file + return False diff --git a/src/extra/SoundsTutorial/__init__.py b/src/extra/SoundsTutorial/__init__.py index 9c245eb4..1e2e7e17 100644 --- a/src/extra/SoundsTutorial/__init__.py +++ b/src/extra/SoundsTutorial/__init__.py @@ -1 +1 @@ -from soundsTutorial import * \ No newline at end of file +from soundsTutorial import soundsTutorial diff --git a/src/extra/SoundsTutorial/gtk_ui.py b/src/extra/SoundsTutorial/gtk_ui.py new file mode 100644 index 00000000..4dda6d1e --- /dev/null +++ b/src/extra/SoundsTutorial/gtk_ui.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +import widgetUtils + +class soundsTutorialDialog(Gtk.Dialog): + def __init__(self, actions): + super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) + box = self.get_content_area() + label = Gtk.Label("Press enter for listen the sound") + self.list = widgetUtils.list("Action") + self.populate_actions(actions) + lBox = Gtk.Box(spacing=6) + lBox.add(label) + lBox.add(self.list.list) + box.add(lBox) + self.play = Gtk.Button("Play") + box.add(self.play) + self.show_all() + + def populate_actions(self, actions): + for i in actions: + self.list.insert_item(i) + + def get_selected(self): + return self.list.get_selected() \ No newline at end of file diff --git a/src/extra/SoundsTutorial/soundsTutorial.py b/src/extra/SoundsTutorial/soundsTutorial.py index cb6095a5..37d9643a 100644 --- a/src/extra/SoundsTutorial/soundsTutorial.py +++ b/src/extra/SoundsTutorial/soundsTutorial.py @@ -1,11 +1,15 @@ # -*- coding: utf-8 -*- +import platform import widgetUtils import os import paths import logging log = logging.getLogger("extra.SoundsTutorial.soundsTutorial") -import wx_ui import soundsTutorial_constants +if platform.system() == "Windows": + import wx_ui as UI +elif platform.system() == "Linux": + import gtk_ui as UI class soundsTutorial(object): def __init__(self, sessionObject): @@ -19,12 +23,12 @@ class soundsTutorial(object): log.debug("Searching sound files...") [self.files.append(i[0]) for i in soundsTutorial_constants.actions] log.debug("Creating dialog...") - self.dialog = wx_ui.soundsTutorialDialog(self.actions) + self.dialog = UI.soundsTutorialDialog(self.actions) widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) self.dialog.get_response() def on_play(self, *args, **kwargs): try: - self.session.sound.play(self.files[self.dialog.items.GetSelection()]+".ogg") + self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg") except: log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],)) \ No newline at end of file diff --git a/src/extra/SoundsTutorial/wx_ui.py b/src/extra/SoundsTutorial/wx_ui.py index c5676582..d3480add 100644 --- a/src/extra/SoundsTutorial/wx_ui.py +++ b/src/extra/SoundsTutorial/wx_ui.py @@ -23,4 +23,7 @@ class soundsTutorialDialog(widgetUtils.BaseDialog): sizer.Add(listBox) sizer.Add(btnBox) panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) \ No newline at end of file + self.SetClientSize(sizer.CalcMin()) + + def get_selection(self): + return self.items.GetSelection() \ No newline at end of file diff --git a/src/gtkUI/__init__.py b/src/gtkUI/__init__.py new file mode 100644 index 00000000..096e5554 --- /dev/null +++ b/src/gtkUI/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +""" This is the GTK view module for TWBlue. +As of April 3 2015, there are the things that have been implemented: +* the main view (partially implemented) +* All buffers. +* Three of the most common message dialogs. +* Dialogs for tweet, reply, retweet, send a direct message and view a tweet. + +And we need to implement: +* All the other dialogs. +""" diff --git a/src/gtkUI/buffers/__init__.py b/src/gtkUI/buffers/__init__.py new file mode 100644 index 00000000..f60ca1ce --- /dev/null +++ b/src/gtkUI/buffers/__init__.py @@ -0,0 +1,11 @@ +# -*- 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 trends import trendsPanel +from tweet_searches import searchPanel +from user_searches import searchUsersPanel diff --git a/src/gtkUI/buffers/base.py b/src/gtkUI/buffers/base.py new file mode 100644 index 00000000..76a0135a --- /dev/null +++ b/src/gtkUI/buffers/base.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +import widgetUtils +from gi.repository import Gtk + +class basePanel(Gtk.VBox): + + def create_list(self): + self.list = widgetUtils.list(_(u"User"), _(u"Text"), _(u"Date"), _(u"Client")) + + def __init__(self, parent, name): + super(basePanel, self).__init__(spacing=6) + self.name = name + self.type = "baseBuffer" + self.create_list() + self.tweet = Gtk.Button(_(u"Tweet")) + self.retweet = Gtk.Button(_(u"Retweet")) + self.reply = Gtk.Button(_(u"Reply")) + self.dm = Gtk.Button(_(u"Direct message")) + btnSizer = Gtk.Box(spacing=6) + btnSizer.add(self.tweet) + btnSizer.add(self.retweet) + btnSizer.add(self.reply) + btnSizer.add(self.dm) + self.add(self.list.list) + self.add(btnSizer) + + def set_position(self, reversed=False): + if reversed == False: + self.list.select_item(self.list.get_count()-1) + else: + self.list.select_item(0) diff --git a/src/gtkUI/buffers/dm.py b/src/gtkUI/buffers/dm.py new file mode 100644 index 00000000..cfdbd18c --- /dev/null +++ b/src/gtkUI/buffers/dm.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +import widgetUtils +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.retweet.hide() + self.retweet.set_no_show_all(True) + self.reply.hide() + self.reply.set_no_show_all(True) + self.type = "dm" diff --git a/src/gtkUI/buffers/events.py b/src/gtkUI/buffers/events.py new file mode 100644 index 00000000..1b3a5af5 --- /dev/null +++ b/src/gtkUI/buffers/events.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +import widgetUtils +from gi.repository import Gtk + +class eventsPanel(Gtk.VBox): + """ Buffer to show events. Different than tweets or people.""" + + def __init__(self, parent, name): + self.type = "event" + super(eventsPanel, self).__init__(spacing=6) + self.name = name + self.list = widgetUtils.list(_(u"Date"), _(u"Event")) + self.add(self.list.list) + self.tweet = Gtk.Button(_(u"Tweet")) + self.delete_event = Gtk.Button(_(u"Remove event")) + btnBox = Gtk.Box(spacing=6) + btnBox.add(self.tweet) + btnBox.add(self.delete_event) + self.add(btnBox) + + def set_position(self, reversed=False): + if reversed == False: + self.list.select_item(self.list.get_count()-1) + else: + self.list.select_item(0) diff --git a/src/gtkUI/buffers/favourites.py b/src/gtkUI/buffers/favourites.py new file mode 100644 index 00000000..916f21a6 --- /dev/null +++ b/src/gtkUI/buffers/favourites.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +from base import basePanel + +class favsPanel(basePanel): + def __init__(self, parent, name): + super(favsPanel, self).__init__(parent, name) + self.type = "favourites_timeline" diff --git a/src/gtkUI/buffers/lists.py b/src/gtkUI/buffers/lists.py new file mode 100644 index 00000000..ffb77981 --- /dev/null +++ b/src/gtkUI/buffers/lists.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +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/gtkUI/buffers/panels.py b/src/gtkUI/buffers/panels.py new file mode 100644 index 00000000..1a3916af --- /dev/null +++ b/src/gtkUI/buffers/panels.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +import widgetUtils + +class accountPanel(Gtk.VBox): + def __init__(self, parent, name=None): + super(accountPanel, self).__init__(spacing=5) + self.name = name + self.type = "account" + self.login = Gtk.Button(_(u"Login")) + self.add(self.login) + self.autostart_account = Gtk.ToggleButton(_(u"Start account automatically")) + self.add(self.autostart_account) + + def change_login(self, login=True): + if login == True: + self.login.set_label(_(u"Login")) + else: + self.login.set_label(_(u"Logout")) + + def change_autostart(self, autostart=True): + self.autostart_account.set_active(autostart) + + def get_autostart(self): + return self.autostart_account.get_active() + +class emptyPanel(Gtk.VBox): + def __init__(self, parent, name): + super(emptyPanel, self).__init__(spacing=6) + self.name = name + self.type = "account" + diff --git a/src/gtkUI/buffers/people.py b/src/gtkUI/buffers/people.py new file mode 100644 index 00000000..4bf620fc --- /dev/null +++ b/src/gtkUI/buffers/people.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +import widgetUtils +from base import basePanel + +class peoplePanel(basePanel): + """ Buffer used to show people.""" + + def create_list(self): + self.list = widgetUtils.list(_(u"User")) + + def __init__(self, parent, name): + super(peoplePanel, self).__init__(parent, name) + self.type = "people" + self.reply.set_label(_(u"Mention")) + self.retweet.hide() + self.retweet.set_no_show_all(True) diff --git a/src/gtkUI/buffers/trends.py b/src/gtkUI/buffers/trends.py new file mode 100644 index 00000000..1e4b24a2 --- /dev/null +++ b/src/gtkUI/buffers/trends.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +import widgetUtils + +class trendsPanel(Gtk.VBox): + def create_list(self): + """ Returns the list for put the tweets here.""" + self.list = widgetUtils.list(_(u"Trending topic")) + + def __init__(self, parent, name): + super(trendsPanel, self).__init__(spacing=6) + self.type = "trends" + self.create_list() + self.tweet = Gtk.Button(_(u"Tweet")) + self.tweetTrendBtn = Gtk.Button(_(u"Tweet about this trend")) + btnSizer = Gtk.Box(spacing=3) + btnSizer.add(self.tweet) + btnSizer.add(self.tweetTrendBtn) + self.add(btnSizer) + self.Add(self.list.list) + + def set_position(self, reversed=False): + if reversed == False: + self.list.select_item(self.list.get_count()-1) + else: + self.list.select_item(0) diff --git a/src/gtkUI/buffers/tweet_searches.py b/src/gtkUI/buffers/tweet_searches.py new file mode 100644 index 00000000..330014da --- /dev/null +++ b/src/gtkUI/buffers/tweet_searches.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +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/gtkUI/buffers/user_searches.py b/src/gtkUI/buffers/user_searches.py new file mode 100644 index 00000000..41b0ff9e --- /dev/null +++ b/src/gtkUI/buffers/user_searches.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +from tweet_searches import searchPanel +import widgetUtils + +class searchUsersPanel(searchPanel): + def create_list(self): + """ Returns the list for put the tweets here.""" + self.list = widgetUtils.list(_(u"User")) + + def __init__(self, parent, name): + self.create_list() + super(searchUsersPanel, self).__init__(parent, name) + self.type = "user_searches" diff --git a/src/gtkUI/commonMessageDialogs.py b/src/gtkUI/commonMessageDialogs.py new file mode 100644 index 00000000..5644d65b --- /dev/null +++ b/src/gtkUI/commonMessageDialogs.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk + +def retweet_question(parent): + dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, _(u"Retweet")) + dialog.format_secondary_text(_(u"Would you like to add a comment to this tweet?")) + answer = dialog.run() + dialog.destroy() + return answer + +def delete_tweet_dialog(parent): + dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, _(u"Delete")) + dialog.format_secondary_text(_(u"Do you really want to delete this message? It will be eliminated from Twitter as well.")) + answer = dialog.run() + dialog.destroy() + return answer + +def exit_dialog(parent): + dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, _(u"Exit")) + dialog.format_secondary_text(_(u"Do you really want to close TW Blue?")) + answer = dialog.run() + dialog.destroy() + return answer + +def needs_restart(): + 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() + +def delete_user_from_db(): + return wx.MessageDialog(None, _(u"Are you sure you want to delete this user from the database? This user will not appear on the autocomplete results anymore."), _(u"Confirm"), wx.YES_NO|wx.ICON_QUESTION).ShowModal() + +def get_ignored_client(): + entry = wx.TextEntryDialog(None, _(u"Enter the name of the client here"), _(u"Add a new ignored client")) + if entry.ShowModal() == wx.ID_OK: + return entry.GetValue() + return None + +def clear_list(): + dlg = wx.MessageDialog(None, _(u"Do you really want to empty this buffer? It's items will be removed from the list but not from Twitter"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO) + return dlg.ShowModal() + +def remove_buffer(): + return wx.MessageDialog(None, _(u"Do you really want to delete this timeline?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() + +def user_not_exist(): + return wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() + +def timeline_exist(): + return 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() + +def no_tweets(): + return wx.MessageDialog(None, _(u"This user has no tweets. You can't open a timeline for this user"), _(u"Error!"), wx.ICON_ERROR).ShowModal() + +def protected_user(): + return wx.MessageDialog(None, _(u"This is a protected Twitter user. It means you can not open a timeline using the Streaming API. The user's tweets will not update due to a twitter policy. Do you want to continue?"), _(u"Warning"), wx.ICON_WARNING|wx.YES_NO).ShowModal() + +def no_following(): + return wx.MessageDialog(None, _(u"This is a protected user account, you need follow to this user for viewing your tweets or favourites."), _(u"Error"), wx.ICON_ERROR).ShowModal() diff --git a/src/gtkUI/dialogs/__init__.py b/src/gtkUI/dialogs/__init__.py new file mode 100644 index 00000000..d8e11f66 --- /dev/null +++ b/src/gtkUI/dialogs/__init__.py @@ -0,0 +1 @@ +#import trends, configuration, lists, message, search, show_user, update_profile, urlList, userSelection, utils diff --git a/src/gtkUI/dialogs/configuration.py b/src/gtkUI/dialogs/configuration.py new file mode 100644 index 00000000..905b4f43 --- /dev/null +++ b/src/gtkUI/dialogs/configuration.py @@ -0,0 +1,240 @@ +# -*- 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.ask_at_exit = wx.CheckBox(self, -1, _(U"ask before exiting TwBlue?")) + sizer.Add(self.ask_at_exit, 0, wx.ALL, 5) + self.use_invisible_shorcuts = wx.CheckBox(self, -1, _(u"Use invisible interface's keyboard shorcuts on the GUI")) + sizer.Add(self.use_invisible_shorcuts, 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.hide_gui = wx.CheckBox(self, -1, _(u"Activate the auto-start of the invisible interface")) + sizer.Add(self.hide_gui, 0, wx.ALL, 5) + self.SetSizer(sizer) + +class generalAccount(wx.Panel, baseDialog.BaseWXDialog): + def __init__(self, parent): + super(generalAccount, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + self.au = wx.Button(self, wx.NewId(), _(u"Set the autocomplete function")) + sizer.Add(self.au, 0, wx.ALL, 5) + self.relative_time = wx.CheckBox(self, wx.NewId(), _(U"Relative times")) + sizer.Add(self.relative_time, 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, wx.NewId()) + 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, wx.NewId()) + 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, wx.NewId(), _(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) + self.add = wx.Button(self, -1, _(u"Add client")) + self.remove = wx.Button(self, -1, _(u"Remove client")) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.add, 0, wx.ALL, 5) + btnBox.Add(self.remove, 0, wx.ALL, 5) + sizer.Add(clientsBox, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + self.SetSizer(sizer) + + def append(self, client): + self.clients.Append(client) + + def get_clients(self): + return self.clients.GetCount() + + def get_client_id(self): + return self.clients.GetSelection() + + def remove_(self, id): + self.clients.Delete(id) + +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.session_mute = wx.CheckBox(self, -1, _(u"Session mute")) + sizer.Add(self.session_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) + + def get(self, control): + return getattr(self, control).GetStringSelection() + +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) + + def set_dropbox(self, active=True): + if active == True: + self.dropbox.SetLabel(_(u"Unlink your Dropbox account")) + else: + self.dropbox.SetLabel(_(u"Link your Dropbox account")) + + def show_dialog(self): + 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() + + def get_response(self): + dlg = wx.TextEntryDialog(self, _(u"Enter the code here."), _(u"Verification code")) + if dlg.ShowModal() == wx.ID_CANCEL: + return False + return dlg.GetValue() + + def show_error(self): + wx.MessageDialog(self, _(u"Error during authorisation. Try again later."), _(u"Error!"), wx.ICON_ERROR).ShowModal() + + def get_dropbox(self): + return self.dropbox.GetLabel() + +class configurationDialog(baseDialog.BaseWXDialog): + + def set_title(self, title): + self.SetTitle(title) + + 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_general_account(self): + self.general = generalAccount(self.notebook) + 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, value): + p = getattr(self, panel) + control = getattr(p, key) + getattr(control, "SetValue")(value) + diff --git a/src/gtkUI/dialogs/lists.py b/src/gtkUI/dialogs/lists.py new file mode 100644 index 00000000..95e8b7fe --- /dev/null +++ b/src/gtkUI/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/gtkUI/dialogs/message.py b/src/gtkUI/dialogs/message.py new file mode 100644 index 00000000..6c28af1b --- /dev/null +++ b/src/gtkUI/dialogs/message.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +from gi.repository import Gtk +import widgetUtils + +class textLimited(widgetUtils.baseDialog): + def __init__(self, *args, **kwargs): + super(textLimited, self).__init__(buttons=(Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL), *args, **kwargs) + + def createTextArea(self, message="", text=""): + self.label = Gtk.Label(message) + self.text = Gtk.Entry() + self.text.set_text(text) + self.text.set_placeholder_text(message) + self.set_title(str(len(text))) + self.textBox = Gtk.Box(spacing=10) + self.textBox.add(self.label) + self.textBox.add(self.text) + + def text_focus(self): + self.text.grab_focus() + + def get_text(self): + return self.text.get_text() + + def set_text(self, text): + self.text.set_text(text) + + def set_title(self, new_title): + self.text.set_placeholder_text(new_title) +# self.set_title(new_title) + + def enable_button(self, buttonName): + if getattr(self, buttonName): + return getattr(self, buttonName).show() + + def disable_button(self, buttonName): + if getattr(self, buttonName): + return getattr(self, buttonName).hide() + + def set_cursor_at_end(self): + self.text.set_position(-1) + + def set_cursor_at_position(self, position): + self.text.set_position() + + def get_position(self): + return self.text.get_position() + +class tweet(textLimited): + def createControls(self, title, message, text): + self.createTextArea(message, text) + self.box.add(self.textBox) + self.upload_image = Gtk.Button(_(u"Upload a picture")) + self.spellcheck = Gtk.Button(_("Spelling correction")) + self.attach = Gtk.Button(_(u"Attach audio")) + self.shortenButton = Gtk.Button(_(u"Shorten URL")) + self.unshortenButton = Gtk.Button(_(u"Expand URL")) + self.shortenButton.hide() + self.shortenButton.set_no_show_all(True) + self.unshortenButton.hide() + self.unshortenButton.set_no_show_all(True) + self.translateButton = Gtk.Button(_(u"Translate message")) + self.autocompletionButton = Gtk.Button(_(u"&Autocomplete users")) + self.buttonsBox1 = Gtk.Box(spacing=6) + self.buttonsBox1.add(self.upload_image) + self.buttonsBox1.add(self.spellcheck) + self.buttonsBox1.add(self.attach) + self.box.add(self.buttonsBox1) + self.buttonsBox2 = Gtk.Box(spacing=6) + self.buttonsBox2.add(self.shortenButton) + self.buttonsBox2.add(self.unshortenButton) + self.buttonsBox2.add(self.translateButton) + self.box.add(self.buttonsBox2) + + def __init__(self, title, message, text): + super(tweet, self).__init__() + self.createControls(message, title, text) + self.show_all() + + def get_image(self): + 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 None + return open(openFileDialog.GetPath(), "rb") + +class dm(textLimited): + def createControls(self, title, message, users): + label = Gtk.Label(_(u"Recipient")) + self.cb = Gtk.ComboBoxText.new_with_entry() + self.cb.set_entry_text_column(0) + for user in users: + self.cb.append_text(user) + self.cb.get_child().set_placeholder_text(_(u"Recipient")) + self.cb.get_child().set_text(users[0]) + self.autocompletionButton = Gtk.Button(_(u"&Autocomplete users")) + self.createTextArea(message, text="") + userBox = Gtk.Box(spacing=8) + userBox.add(label) + userBox.add(self.cb) + userBox.add(self.autocompletionButton) + self.box.add(userBox) +# self.mainBox.Add(self.cb, 0, wx.ALL, 5) + self.box.add(self.textBox) + self.spellcheck = Gtk.Button(_("Spelling correction")) + self.attach = Gtk.Button(_(u"Attach audio")) + self.shortenButton = Gtk.Button(_(u"Shorten URL")) + self.unshortenButton = Gtk.Button(_(u"Expand URL")) + self.shortenButton.hide() + self.shortenButton.set_no_show_all(True) + self.unshortenButton.hide() + self.unshortenButton.set_no_show_all(True) + self.translateButton = Gtk.Button(_(u"Translate message")) + self.buttonsBox = Gtk.Box(spacing=6) + self.buttonsBox.add(self.spellcheck) + self.buttonsBox.add(self.attach) + self.box.add(self.buttonsBox) + self.buttonsBox1 = Gtk.Box(spacing=6) + self.buttonsBox1.add(self.shortenButton) + self.buttonsBox1.add(self.unshortenButton) + self.buttonsBox1.add(self.translateButton) + self.box.add(self.buttonsBox1) + self.text.grab_focus() + + + def get(self, control): + if control == "cb": + return self.cb.get_active_text() + + def __init__(self, title, message, users): + super(dm, self).__init__() + self.createControls(message, title, users) +# self.onTimer(wx.EVT_CHAR_HOOK) + self.show_all() + + def get_user(self): + return self.cb.get_text() + + def set_user(self, user): + return self.cb.set_value() + +class reply(tweet): + def __init__(self, title, message, text): + super(reply, self).__init__(message, title, text) + self.text.set_position(-1) + self.mentionAll = Gtk.Button(_(u"Men&tion to all")) + self.mentionAll.set_no_show_all(True) + self.mentionAll.hide() + self.buttonsBox1.add(self.mentionAll) + +class viewTweet(widgetUtils.baseDialog): + def set_title(self, lenght): + pass +# self.set_title(_(u"Tweet - %i characters ") % (lenght,)) + + def __init__(self, text, rt_count, favs_count): + super(viewTweet, self).__init__(buttons=(Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) + label = Gtk.Label(_(u"Tweet")) + self.text = Gtk.TextView() + self.textBuffer = self.text.get_buffer() + self.textBuffer.set_text(text) + self.textBuffer.set_editable(False) + self.text.set_placeholder_text(message) + textBox = Gtk.Box(spacing=6) + textBox.add(label) + textBox.add(self.text) + self.box.add(textBox) + rtCountLabel = Gtk.Label(_(u"Retweets: ")) + rtCount = Gtk.Entry() + rtCount.set_text(rt_count) + rtCount.set_editable(False) + rtBox = Gtk.Box(spacing=2) + rtBox.add(rtCountLabel) + rtBox.add(rtCount) + favsCountLabel = Gtk.Label(_(u"Favourites: ")) + favsCount = Gtk.Entry() + favsCount.set_text(favs_count) + favsCount.set_editable(False) + favsBox = Gtk.Box(spacing=2) + favsBox.add(favsCountLabel) + favsBox.add(favsCount) + infoBox = Gtk.Box(spacing=4) + infoBox.add(rtBox) + infoBox.add(favsBox) + self.box.add(infoBox) + self.spellcheck = Gtk.Button(_("Spelling correction")) + self.unshortenButton = Gtk.Button(_(u"Expand URL")) + self.unshortenButton.hide() + self.unshortenButton.set_no_show_all(True) + self.translateButton = Gtk.Button(_(u"Translate message")) + buttonsBox = Gtk.Box(spacing=6) + buttonsBox.add(self.spellcheck) + buttonsBox.add(self.unshortenButton) + buttonsBox.add(self.translateButton) + self.box.Add(buttonsBox) + self.show_all() + + def set_text(self, text): + self.textBuffer.set_text(text) + + def get_text(self): + return self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), False) + + def text_focus(self): + self.text.grab_focus() + + def enable_button(self, buttonName): + if getattr(self, buttonName): + return getattr(self, buttonName).show() + +class viewNonTweet(widgetUtils.baseDialog): + + def __init__(self, text): + super(viewNonTweet, self).__init__(buttons=(Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) + self.set_title(_(u"View")) + label = Gtk.Label(_(u"Item")) + self.text = Gtk.TextView() + self.text.set_editable(False) + self.text.get_buffer().set_text(text) + textBox = Gtk.Box(spacing=5) + textBox.add(label) + textBox.add(self.text) + self.box.Add(textBox) + self.spellcheck = Gtk.Button(_("Spelling correction")) + self.unshortenButton = Gtk.Button(_(u"Expand URL")) + self.unshortenButton.hide() + self.unshortenButton.set_no_show_all(True) + self.translateButton = Gtk.Button(_(u"Translate message")) + buttonsBox = Gtk.Box(spacing=6) + buttonsBox.add(self.spellcheck) + buttonsBox.add(self.unshortenButton) + buttonsBox.add(self.translateButton) + self.box.Add(buttonsBox) + self.show_all() + + def set_text(self, text): + self.text.get_buffer().set_text() + + def get_text(self): + return self.text.get_buffer().get_text() + + def text_focus(self): + self.text.grab_focus() + + def enable_button(self, buttonName): + if getattr(self, buttonName): + return getattr(self, buttonName).show() diff --git a/src/gtkUI/dialogs/search.py b/src/gtkUI/dialogs/search.py new file mode 100644 index 00000000..81b54272 --- /dev/null +++ b/src/gtkUI/dialogs/search.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import baseDialog +import wx + +class searchDialog(baseDialog.BaseWXDialog): + def __init__(self, value=""): + 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, value) + 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()) \ No newline at end of file diff --git a/src/gtkUI/dialogs/show_user.py b/src/gtkUI/dialogs/show_user.py new file mode 100644 index 00000000..ecc601a2 --- /dev/null +++ b/src/gtkUI/dialogs/show_user.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +import wx +import baseDialog + +class showUserProfile(baseDialog.BaseWXDialog): + def __init__(self): + super(showUserProfile, self).__init__(parent=None, id=wx.NewId()) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + static = wx.StaticText(panel, -1, _(u"Details")) + sizer.Add(static, 0, wx.ALL, 5) + self.text = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY, size=(350, 250)) + self.text.SetFocus() + sizer.Add(self.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) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def enable_url(self, enabled=True): + self.url.Enable(enabled) \ No newline at end of file diff --git a/src/gtkUI/dialogs/trends.py b/src/gtkUI/dialogs/trends.py new file mode 100644 index 00000000..76275ec9 --- /dev/null +++ b/src/gtkUI/dialogs/trends.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +import baseDialog +import wx + +class trendingTopicsDialog(baseDialog.BaseWXDialog): + def __init__(self): + super(trendingTopicsDialog, self).__init__(None, -1) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle(_(u"View trending topics")) + label = wx.StaticText(panel, -1, _(u"Trending topics by")) + sizer.Add(label, 0, wx.ALL, 5) + self.country = wx.RadioButton(panel, -1, _(u"Country"), style=wx.RB_GROUP) + self.city = wx.RadioButton(panel, -1, _(u"City")) + radioSizer = wx.BoxSizer(wx.HORIZONTAL) + radioSizer.Add(label, 0, wx.ALL, 5) + radioSizer.Add(self.country, 0, wx.ALL, 5) + radioSizer.Add(self.city, 0, wx.ALL, 5) + sizer.Add(radioSizer, 0, wx.ALL, 5) + label = wx.StaticText(panel, -1, _(u"Location")) + self.location = wx.ListBox(panel, -1, choices=[], style=wx.CB_READONLY) + locationBox = wx.BoxSizer(wx.HORIZONTAL) + locationBox.Add(label, 0, wx.ALL, 5) + locationBox.Add(self.location, 0, wx.ALL, 5) + sizer.Add(locationBox, 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()) + + def get_active(self): + if self.country.GetValue() == True: + return "country" + else: + return "city" + + def get_item(self): + return self.location.GetStringSelection() + + def set(self, values): + self.location.Set(values) \ No newline at end of file diff --git a/src/gtkUI/dialogs/update_profile.py b/src/gtkUI/dialogs/update_profile.py new file mode 100644 index 00000000..027a2e74 --- /dev/null +++ b/src/gtkUI/dialogs/update_profile.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +import wx +import baseDialog + +class updateProfileDialog(baseDialog.BaseWXDialog): + def __init__(self): + super(updateProfileDialog, self).__init__(parent=None, id=-1) + self.SetTitle(_(u"Update your profile")) + panel = wx.Panel(self) + labelName = wx.StaticText(panel, -1, _(u"Name (20 characters maximum)")) + self.name = wx.TextCtrl(panel, -1) + self.name.SetFocus() + dc = wx.WindowDC(self.name) + dc.SetFont(self.name.GetFont()) + self.name.SetSize(dc.GetTextExtent("0"*20)) + labelLocation = wx.StaticText(panel, -1, _(u"Location")) + self.location = wx.TextCtrl(panel, -1) + dc = wx.WindowDC(self.location) + dc.SetFont(self.location.GetFont()) + self.location.SetSize(dc.GetTextExtent("0"*35)) + labelUrl = wx.StaticText(panel, -1, _(u"Website")) + self.url = wx.TextCtrl(panel, -1) + dc = wx.WindowDC(self.url) + dc.SetFont(self.url.GetFont()) + self.url.SetSize(dc.GetTextExtent("0"*22)) + labelDescription = wx.StaticText(panel, -1, _(u"Bio (160 characters maximum)")) + self.description = wx.TextCtrl(panel, -1, size=(400, 400)) + dc = wx.WindowDC(self.description) + dc.SetFont(self.description.GetFont()) + self.description.SetSize(dc.GetTextExtent("0"*160)) + self.image = None + self.upload_image = wx.Button(panel, -1, _(u"Upload a picture")) + self.ok = wx.Button(panel, wx.ID_OK, _(u"Update profile")) + self.ok.SetDefault() + close = wx.Button(panel, wx.ID_CANCEL, _("Close")) + sizer = wx.BoxSizer(wx.VERTICAL) + nameBox = wx.BoxSizer(wx.HORIZONTAL) + nameBox.Add(labelName, 0, wx.ALL, 5) + nameBox.Add(self.name, 0, wx.ALL, 5) + sizer.Add(nameBox, 0, wx.ALL, 5) + locationBox = wx.BoxSizer(wx.HORIZONTAL) + locationBox.Add(labelLocation, 0, wx.ALL, 5) + locationBox.Add(self.location, 0, wx.ALL, 5) + sizer.Add(locationBox, 0, wx.ALL, 5) + urlBox = wx.BoxSizer(wx.HORIZONTAL) + urlBox.Add(labelUrl, 0, wx.ALL, 5) + urlBox.Add(self.url, 0, wx.ALL, 5) + sizer.Add(urlBox, 0, wx.ALL, 5) + descriptionBox = wx.BoxSizer(wx.HORIZONTAL) + descriptionBox.Add(labelDescription, 0, wx.ALL, 5) + descriptionBox.Add(self.description, 0, wx.ALL, 5) + sizer.Add(descriptionBox, 0, wx.ALL, 5) + sizer.Add(self.upload_image, 5, wx.CENTER, 5) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.ok, 0, wx.ALL, 5) + btnBox.Add(close, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def set_name(self, name): + self.set("name", name) + + def set_description(self, description): + self.set("description", description) + + def set_location(self, location): + self.set("location", location) + + def set_url(self, url): + self.set("url", url) + + def change_upload_button(self, uploaded=False): + if uploaded == False: + self.upload_image.SetLabel(_(u"Upload a picture")) + else: + self.upload_image.SetLabel(_(u"Discard image")) + + def upload_picture(self): + 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 None + return openFileDialog.GetPath() + + def hide_upload_button(self, hide): + self.upload_image.Enable(hide) + + def set_readonly(self): + self.name.style = wx.TE_READONLY + self.name.Refresh() + self.description.style = wx.TE_READONLY + self.description.Refresh() + self.location.style = wx.TE_READONLY + self.location.Refresh() + self.url.style = wx.TE_READONLY + self.url.Refresh() + self.hide_upload_button(False) + self.ok.Enable(False) \ No newline at end of file diff --git a/src/gtkUI/dialogs/urlList.py b/src/gtkUI/dialogs/urlList.py new file mode 100644 index 00000000..7a02008e --- /dev/null +++ b/src/gtkUI/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/gtkUI/dialogs/userActions.py b/src/gtkUI/dialogs/userActions.py new file mode 100644 index 00000000..2f9f6dc1 --- /dev/null +++ b/src/gtkUI/dialogs/userActions.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +import wx + +class UserActionsDialog(wx.Dialog): + def __init__(self, users=[], default="follow", *args, **kwargs): + super(UserActionsDialog, self).__init__(parent=None, *args, **kwargs) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.SetTitle(_(u"Action")) + userLabel = wx.StaticText(panel, -1, _(u"User")) + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) + self.cb.SetFocus() + userSizer.Add(userLabel, 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + 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.ignore_client = wx.RadioButton(panel, -1, _(u"Ignore tweets from this client")) + self.setup_default(default) + hSizer = wx.BoxSizer(wx.HORIZONTAL) + hSizer.Add(label2, 0, wx.ALL, 5) + actionSizer.Add(self.follow, 0, wx.ALL, 5) + actionSizer.Add(self.unfollow, 0, wx.ALL, 5) + actionSizer.Add(self.mute, 0, wx.ALL, 5) + actionSizer.Add(self.unmute, 0, wx.ALL, 5) + actionSizer.Add(self.block, 0, wx.ALL, 5) + actionSizer.Add(self.unblock, 0, wx.ALL, 5) + actionSizer.Add(self.reportSpam, 0, wx.ALL, 5) + actionSizer.Add(self.ignore_client, 0, wx.ALL, 5) + hSizer.Add(actionSizer, 0, wx.ALL, 5) + 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(hSizer, 0, wx.ALL, 5) + 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" + elif self.ignore_client.GetValue() == True: return "ignore_client" + + 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) + elif default == "ignore_client": + self.ignore_client.SetValue(True) + + def get_response(self): + return self.ShowModal() + + def get_user(self): + return self.cb.GetValue() \ No newline at end of file diff --git a/src/gtkUI/dialogs/userSelection.py b/src/gtkUI/dialogs/userSelection.py new file mode 100644 index 00000000..22a3711f --- /dev/null +++ b/src/gtkUI/dialogs/userSelection.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +import wx + +class selectUserDialog(wx.Dialog): + def __init__(self, users=[], default="tweets", *args, **kwargs): + super(selectUserDialog, self).__init__(parent=None, *args, **kwargs) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.SetTitle(_(u"Timeline for %s") % (users[0])) + userLabel = wx.StaticText(panel, -1, _(u"User")) + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) + self.cb.SetFocus() + userSizer.Add(userLabel, 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + actionSizer = wx.BoxSizer(wx.VERTICAL) + label2 = wx.StaticText(panel, -1, _(u"Buffer type")) + self.tweets = wx.RadioButton(panel, -1, _(u"Tweets"), style=wx.RB_GROUP) + self.favourites = wx.RadioButton(panel, -1, _(u"Favourites")) + self.setup_default(default) + hSizer = wx.BoxSizer(wx.HORIZONTAL) + hSizer.Add(label2, 0, wx.ALL, 5) + actionSizer.Add(self.tweets, 0, wx.ALL, 5) + actionSizer.Add(self.favourites, 0, wx.ALL, 5) + hSizer.Add(actionSizer, 0, wx.ALL, 5) + 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(hSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer) + panel.SetSizer(sizer) + + def get_action(self): + if self.tweets.GetValue() == True: return "tweets" + elif self.favourites.GetValue() == True: return "favourites" + + def setup_default(self, default): + if default == "tweets": + self.tweets.SetValue(True) + elif default == "favourites": + self.favourites.SetValue(True) + + def get_response(self): + return self.ShowModal() + + def get_user(self): + return self.cb.GetValue() \ No newline at end of file diff --git a/src/gtkUI/dialogs/utils.py b/src/gtkUI/dialogs/utils.py new file mode 100644 index 00000000..eaf75e5e --- /dev/null +++ b/src/gtkUI/dialogs/utils.py @@ -0,0 +1,46 @@ +# -*- 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 baseDialog + +class selectUserDialog(baseDialog.BaseWXDialog): + def __init__(self, title, users): + super(selectUserDialog, self).__init__(parent=None, id=wx.NewId(), title=title) + 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() +# 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()) + + def get_user(self): + return self.cb.GetValue() + diff --git a/src/gtkUI/sysTrayIcon.py b/src/gtkUI/sysTrayIcon.py new file mode 100644 index 00000000..56578cbb --- /dev/null +++ b/src/gtkUI/sysTrayIcon.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" A systray for TW Blue """ +############################################################ +# Copyright (c) 2014 José Manuel Delicado Alcolea +# +# 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 +import paths +import os + +class SysTrayIcon(wx.TaskBarIcon): + + def __init__(self): + super(SysTrayIcon, self).__init__() + icon=wx.Icon(os.path.join(paths.app_path(), "icon.ico"), wx.BITMAP_TYPE_ICO) + self.SetIcon(icon, application.name) + self.menu=wx.Menu() + self.tweet = self.menu.Append(wx.ID_ANY, _(u"Tweet")) + self.global_settings = self.menu.Append(wx.ID_ANY, _(u"&Global settings")) + self.account_settings = self.menu.Append(wx.ID_ANY, _(u"Account se&ttings")) + self.update_profile = self.menu.Append(wx.ID_ANY, _(u"Update &profile")) + self.show_hide = self.menu.Append(wx.ID_ANY, _(u"&Show / hide")) + self.doc = self.menu.Append(wx.ID_ANY, _(u"&Documentation")) + self.doc.Enable(False) + self.check_for_updates = self.menu.Append(wx.ID_ANY, _(u"Check for &updates")) + self.exit = self.menu.Append(wx.ID_ANY, _(u"&Exit")) + + def show_menu(self): + self.PopupMenu(self.menu) + + def Destroy(self): + self.menu.Destroy() + super(SysTrayIcon, self).Destroy() \ No newline at end of file diff --git a/src/gtkUI/view.py b/src/gtkUI/view.py new file mode 100644 index 00000000..b9e40a44 --- /dev/null +++ b/src/gtkUI/view.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +import application +import widgetUtils +from gi.repository import Gtk + +class mainFrame(Gtk.Window): + """ Main class of the Frame. This is the Main Window.""" + + def append_to_menu(self, menu, *elements): + for i in elements: + menu.append(i) + + ### MENU + def makeMenus(self): + """ Creates, bind and returns the menu bar for the application. Also in this function, the accel table is created.""" + menuBar = Gtk.MenuBar() + + # Application menu + app = Gtk.Menu() + + self.manage_accounts = Gtk.MenuItem(label="Manage accounts") + self.updateProfile = Gtk.MenuItem(label="Update profile") + # As in Gtk is not possible to bind keyboard shorcuts to the system, we don't have support for an invisible interface. + self.show_hide = None + self.menuitem_search = Gtk.MenuItem(label="Search") + self.trends = Gtk.MenuItem(label="View trending topics") + self.lists = Gtk.MenuItem(label="Lists manager") + self.sounds_tutorial = Gtk.MenuItem(label="Sounds tutorial") + self.keystrokes_editor = None + self.account_settings = Gtk.MenuItem(label="Account settings") + self.prefs = Gtk.MenuItem(label="Global settings") + self.close = Gtk.MenuItem(label="Close") + self.append_to_menu(app, self.manage_accounts, self.updateProfile, self.menuitem_search, self.trends, self.lists, self.sounds_tutorial, self.account_settings, self.prefs, self.close) + + app_menu = Gtk.MenuItem(label="Application") + app_menu.set_submenu(app) + menuBar.append(app_menu) + + # Tweet menu + tweet = Gtk.Menu() + self.compose = Gtk.MenuItem(label="Tweet") + self.reply = Gtk.MenuItem(label="Reply") + self.retweet = Gtk.MenuItem(label="Retweet") + self.fav = Gtk.MenuItem(label="Add to favourites") + self.unfav = Gtk.MenuItem(label="Remove from favourites") + self.view = Gtk.MenuItem(label="Show tweet") + self.view_coordinates = Gtk.MenuItem(label="View address") + self.view_conversation = Gtk.MenuItem(label="View conversation") + self.delete = Gtk.MenuItem(label="Delete") + self.append_to_menu(tweet, self.compose, self.reply, self.retweet, self.fav, self.unfav, self.view, self.view_coordinates, self.view_conversation, self.delete) + tweet_menu = Gtk.MenuItem(label="Tweet") + tweet_menu.set_submenu(tweet) + menuBar.append(tweet_menu) + + # User menu + user = Gtk.Menu() + self.follow = Gtk.MenuItem(label="Follow") + self.unfollow = Gtk.MenuItem(label="Unfollow") + self.mute = Gtk.MenuItem(label="Mute") + self.unmute = Gtk.MenuItem(label="Unmute") + self.report = Gtk.MenuItem(label="Report as spam") + self.block = Gtk.MenuItem(label="Block") + self.unblock = Gtk.MenuItem(label="Unblock") + self.dm = Gtk.MenuItem(label="Direct message") + self.addToList = Gtk.MenuItem(label="Add to list") + self.removeFromList = Gtk.MenuItem(label="Remove from list") + self.viewLists = Gtk.MenuItem(label="View lists") + self.details = Gtk.MenuItem(label="Show user profile") + self.timeline = Gtk.MenuItem(label="Timeline") + self.favs = Gtk.MenuItem(label="View favourites") + self.append_to_menu(user, self.follow, self.unfollow, self.mute, self.unmute, self.report, self.block, self.unblock, self.dm, self.addToList, self.removeFromList, self.viewLists, self.details, self.timeline, self.favs) + user_menu = Gtk.MenuItem(label="User") + user_menu.set_submenu(user) + menuBar.append(user_menu) + + # buffer menu + buffer = Gtk.Menu() + self.load_previous_items = Gtk.MenuItem(label="Load previous items") + self.mute_buffer = Gtk.MenuItem(label="Mute") + self.autoread = Gtk.MenuItem(label="Autoread tweets for this buffer") + self.clear = Gtk.MenuItem(label="Clear buffer") + self.deleteTl = Gtk.MenuItem(label="Remove buffer") + self.append_to_menu(buffer, self.load_previous_items, self.mute_buffer, self.autoread, self.clear, self.deleteTl) + buffer_menu = Gtk.MenuItem(label="Buffer") + buffer_menu.set_submenu(buffer) + menuBar.append(buffer_menu) + + # Help Menu + help = Gtk.Menu() + self.doc = Gtk.MenuItem(label="Documentation") + self.changelog = Gtk.MenuItem(label="What's new in this version?") + self.check_for_updates = Gtk.MenuItem(label="Check for updates") + self.reportError = Gtk.MenuItem(label="Report an error") + self.visit_website = Gtk.MenuItem(label="TWBlue's website") + self.about = Gtk.MenuItem(label="ABout TWBlue") + self.append_to_menu(help, self.doc, self.changelog, self.check_for_updates, self.reportError, self.visit_website, self.about) + help_menu = Gtk.MenuItem(label="Help") + help_menu.set_submenu(help) + menuBar.append(help_menu) + self.box.pack_start(menuBar, False, False, 0) + + ### MAIN + def __init__(self): + """ Main function of this class.""" + super(mainFrame, self).__init__(title="TW Blue") + self.box = Gtk.VBox() + self.makeMenus() + self.nb = widgetUtils.notebook() + self.w = None + self.notebookBox = Gtk.Box(spacing=5) + self.notebookBox.add(self.nb.view) + self.box.add(self.notebookBox) + self.add(self.box) + select = self.nb.view.get_selection() + select.connect("changed", self.load) + + def show(self): + self.show_all() + + def get_buffer_count(self): + return self.nb.get_count() + + def add_buffer(self, buffer, name): + buff = widgetUtils.buffer(buffer) + buff.name = name + self.nb.store.append(None, (buff,)) + + def insert_buffer(self, buffer, name, pos): + iter = self.nb.store.get_iter(pos) + buff = widgetUtils.buffer(buffer) + buff.name = name + self.nb.store.insert(iter, -1, (buff,)) + + def prepare(self): + pass + + def search(self, name_, account): + (path, iter) = self.nb.search(self.nb.store, name_, account) + if path != None: + return path + + def get_current_buffer(self): + return self.nb.get_current_page() + + def get_current_buffer_pos(self): + return self.nb.get_current_page_path() + + def get_buffer(self, pos): + return self.get_page(pos) + + def load(self, selection): + model, treeiter = selection.get_selected() + if treeiter != None: + if self.w != None: + self.notebookBox.remove(self.w) + self.w = self.nb.store[treeiter][0].buffer + self.notebookBox.add(self.w) + self.show_all() + + def change_buffer(self, position): + self.nb.ChangeSelection(position) + + def get_buffer_text(self): + return self.nb.GetPageText(self.nb.GetSelection()) + + def get_buffer_by_id(self, id): + return self.nb.FindWindowById(id) + def advance_selection(self, forward): + self.nb.AdvanceSelection(forward) + + + def show_address(self, address): + wx.MessageDialog(self, address, _(u"Address"), wx.OK).ShowModal() + + def delete_buffer(self, pos): + self.nb.DeletePage(pos) + + def about_dialog(self): + 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 set_focus(self): + self.SetFocus() + + def check_menuitem(self, menuitem, check=True): + if hasattr(self, menuitem): + getattr(self, menuitem).Check(check) + +def no_update_available(): + wx.MessageDialog(None, _(u"Your TW Blue version is up to date"), _(u"Update"), style=wx.OK).ShowModal() diff --git a/src/keys/__init__.py b/src/keys/__init__.py index d5c44272..52b35647 100644 --- a/src/keys/__init__.py +++ b/src/keys/__init__.py @@ -7,7 +7,9 @@ import paths if platform.architecture()[0][:2] == "32": lib = load_library("api_keys32", x86_path=paths.app_path("keys/lib")) else: - lib = load_library("api_keys64", x64_path=paths.app_path("keys/lib")) +# lib = load_library("api_keys64", x64_path=paths.app_path("keys/lib")) + import linuxKeys + lib = linuxKeys keyring = None @@ -26,4 +28,4 @@ class Keyring(object): return result.value def get(self, func): - return getattr(self, "_call_method")("get_"+func) \ No newline at end of file + return getattr(self, "_call_method")("get_"+func) diff --git a/src/keys/linuxKeys.py b/src/keys/linuxKeys.py new file mode 100644 index 00000000..f0212ddc --- /dev/null +++ b/src/keys/linuxKeys.py @@ -0,0 +1,21 @@ +def get_api_key(): + return "8pDLbyOW3saYnvSZ4uLFg\0" + +def get_api_secret(): + return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0"; + +#char *get_dropbox_api_key(){ +#return "key\0"; +#} +#char *get_dropbox_api_secret(){ +#return "secret_key\0"; +#} +#char *get_twishort_api_key(){ +#return "key\0"; +#} +#char *get_bts_user(){ +#return "user\0"; +#} +#char *get_bts_password(){ +#return "pass\0"; +#} diff --git a/src/languageHandler.py b/src/languageHandler.py index 34a1d1d5..45546eb4 100644 --- a/src/languageHandler.py +++ b/src/languageHandler.py @@ -130,10 +130,10 @@ def setLanguage(lang): elif system == "Darwin": import Foundation localeName = Foundation.NSLocale.currentLocale().identifier() + else: + localeName=locale.getdefaultlocale()[0] trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName]) curLang=localeName -# else: -# localeName=locale.getdefaultlocale()[0] # trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName]) # curLang=localeName @@ -205,4 +205,4 @@ def langToWindowsLocale(lang): "ru": "rus", "tr": "trk" } - return languages[lang] \ No newline at end of file + return languages[lang] diff --git a/src/main.py b/src/main.py index ccfd471b..cdf9056e 100644 --- a/src/main.py +++ b/src/main.py @@ -1,42 +1,51 @@ # -*- coding: utf-8 -*- -import sys -import os -#redirect the original stdout and stderr -stdout=sys.stdout -stderr=sys.stderr -sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w") -sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w") +import platform +""" there are lots of things not implemented for Gtk+ yet. + We've started this effort 1 Apr 2015 so it isn't fully functional. We will remove the ifs statements when are no needed""" + +system = platform.system() +if system == "Windows": + import sys + import os + #redirect the original stdout and stderr + stdout=sys.stdout + stderr=sys.stderr + sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w") + sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w") import languageHandler -import wx import paths import commandline import config import sound import output -from logger import logger import logging -import platform import application import keys from mysc.thread_utils import call_threaded -from update import updater import fixes #extra variables to control the temporal stdout and stderr, while the final files are opened. We understand that some errors could happen while all outputs are closed, so let's try to avoid it. -stdout_temp=sys.stdout -stderr_temp=sys.stderr +import widgetUtils +if system == "Windows": + from logger import logger + from update import updater + stdout_temp=sys.stdout + stderr_temp=sys.stderr #if it's a binary version -if hasattr(sys, 'frozen'): - sys.stderr = open(paths.logs_path("stderr.log"), 'w') - sys.stdout = open(paths.logs_path("stdout.log"), 'w') -else: - sys.stdout=stdout - sys.stderr=stderr -#the final log files have been opened succesfully, let's close the temporal files -stdout_temp.close() -stderr_temp.close() -#finally, remove the temporal files. TW Blue doesn't need them anymore, and we will get more free space on the harddrive -os.remove(stdout_temp.name) -os.remove(stderr_temp.name) + if hasattr(sys, 'frozen'): + sys.stderr = open(paths.logs_path("stderr.log"), 'w') + sys.stdout = open(paths.logs_path("stdout.log"), 'w') + else: + sys.stdout=stdout + sys.stderr=stderr + #the final log files have been opened succesfully, let's close the temporal files + stdout_temp.close() + stderr_temp.close() + #finally, remove the temporal files. TW Blue doesn't need them anymore, and we will get more free space on the harddrive + os.remove(stdout_temp.name) + os.remove(stderr_temp.name) +if system == "Linux": + from gi.repository import Gdk, GObject, GLib + log = logging.getLogger("main") def setup(): @@ -51,20 +60,26 @@ def setup(): keys.setup() from controller import mainController from sessionmanager import sessionManager - app = wx.App() - updater.do_update() + app = widgetUtils.mainLoopObject() + if system == "Windows": + updater.do_update() sm = sessionManager.sessionManagerController() sm.fill_list() if len(sm.sessions) == 0: sm.show() else: sm.do_ok() + if hasattr(sm.view, "destroy"): + sm.view.destroy() del sm fixes.setup() r = mainController.Controller() - r.view.Show() + r.view.show() r.do_work() r.check_invisible_at_startup() - call_threaded(r.start) - app.MainLoop() + if system == "Windows": + call_threaded(r.start) + elif system == "Linux": + GLib.idle_add(r.start) + app.run() -setup() \ No newline at end of file +setup() diff --git a/src/sessionmanager/gtkUI.py b/src/sessionmanager/gtkUI.py index 8b016d18..f83f249b 100644 --- a/src/sessionmanager/gtkUI.py +++ b/src/sessionmanager/gtkUI.py @@ -1,33 +1,31 @@ from gi.repository import Gtk import widgetUtils -class sessionManagerWindow(Gtk.Dialog): +class sessionManagerWindow(widgetUtils.baseDialog): def __init__(self): super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) - box = self.get_content_area() self.list = widgetUtils.list("Session") - box.add(self.list.list) + self.box.add(self.list.list) btnBox = Gtk.Box(spacing=6) self.new = Gtk.Button("New account") self.remove = Gtk.Button("Remove account") btnBox.add(self.new) btnBox.add(self.remove) - box.add(btnBox) + self.box.add(btnBox) self.show_all() def fill_list(self, sessionsList): for i in sessionsList: - self.list.insert_item(i) + self.list.insert_item(False, i) if self.list.get_count() > 0: self.list.select_item(0) - def get_response(self): - return self.run() - def new_account_dialog(self): dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Authorization") dialog.format_secondary_text("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?") - return dialog.run() + answer = dialog.run() + dialog.destroy() + return answer def add_new_session_to_list(self): total = self.list.get_count() @@ -39,12 +37,14 @@ class sessionManagerWindow(Gtk.Dialog): def show_unauthorised_error(self): dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "Invalid user token") dialog.format_secondary_text("Your access token is invalid or the authorisation has failed. Please try again.") - return dialog.run() + answer = dialog.run() + return answer def remove_account_dialog(self): dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Remove account") dialog.format_secondary_text("Do you really want delete this account?") - return dialog.run() + answer = dialog.run() + return answer def get_selected(self): return self.list.get_selected() diff --git a/src/sessionmanager/sessionManager.py b/src/sessionmanager/sessionManager.py index 2c9e1a84..62d34686 100644 --- a/src/sessionmanager/sessionManager.py +++ b/src/sessionmanager/sessionManager.py @@ -48,6 +48,8 @@ class sessionManagerController(object): def show(self): if self.view.get_response() == widgetUtils.OK: self.do_ok() +# else: + self.view.destroy() def do_ok(self): log.debug("Starting sessions...") @@ -59,6 +61,7 @@ class sessionManagerController(object): s.login() session.sessions[i] = s self.new_sessions[i] = s +# self.view.destroy() def manage_new_account(self, *args, **kwargs): if self.view.new_account_dialog() == widgetUtils.YES: @@ -67,14 +70,14 @@ class sessionManagerController(object): 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: - log.exception("Error authorising the session") - self.view.show_unauthorised_error() - return +# try: + s.authorise() + self.sessions.append(location) + self.view.add_new_session_to_list() +# except: +# log.exception("Error authorising the session") +# self.view.show_unauthorised_error() +# return def remove(self, *args, **kwargs): if self.view.remove_account_dialog() == widgetUtils.YES: @@ -83,3 +86,4 @@ class sessionManagerController(object): self.removed_sessions.append(selected_account) self.sessions.remove(selected_account) shutil.rmtree(path=paths.config_path(selected_account), ignore_errors=True) + diff --git a/src/twitter/compose.py b/src/twitter/compose.py index ef0db1f3..fae41fe9 100644 --- a/src/twitter/compose.py +++ b/src/twitter/compose.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +import platform +system = platform.system() import utils import re import htmlentitydefs @@ -30,11 +32,14 @@ def compose_tweet(tweet, db, relative_times): long = twishort.is_long(tweet) if long != False: tweet["long_uri"] = long - original_date = arrow.get(tweet["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en") - if relative_times == True: - ts = original_date.humanize(locale=languageHandler.getLanguage()) + if system == "Windows": + original_date = arrow.get(tweet["created_at"], "ddd MMM DD H:m:s Z YYYY", locale="en") + if relative_times == True: + ts = original_date.humanize(locale=languageHandler.getLanguage()) + else: + ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage()) else: - ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage()) + ts = tweet["created_at"] text = StripChars(tweet["text"]) if tweet.has_key("sender"): source = "DM" @@ -54,18 +59,23 @@ def compose_tweet(tweet, db, relative_times): return [user+", ", tweet["text"], ts+", ", source] def compose_followers_list(tweet, db, relative_times=True): - original_date = arrow.get(tweet["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en") - if relative_times == True: - ts = original_date.humanize(locale=languageHandler.getLanguage()) + if system == "Windows": + original_date = arrow.get(tweet["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en") + if relative_times == True: + ts = original_date.humanize(locale=languageHandler.getLanguage()) + else: + ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage()) else: - ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage()) + ts = tweet["created_at"] if tweet.has_key("status"): - if len(tweet["status"]) > 4: + if len(tweet["status"]) > 4 and system == "Windows": original_date2 = arrow.get(tweet["status"]["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en") if relative_times: ts2 = original_date2.humanize(locale=languageHandler.getLanguage()) else: ts2 = original_date2.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage()) + else: + ts2 = _("Unavailable") else: ts2 = _("Unavailable") return [_(u"%s (@%s). %s followers, %s friends, %s tweets. Last tweet on %s. Joined Twitter on %s") % (tweet["name"], tweet["screen_name"], tweet["followers_count"], tweet["friends_count"], tweet["statuses_count"], ts2, ts)] diff --git a/src/widgetUtils/gtkUtils.py b/src/widgetUtils/gtkUtils.py index ef5cf83e..04d549bb 100644 --- a/src/widgetUtils/gtkUtils.py +++ b/src/widgetUtils/gtkUtils.py @@ -1,4 +1,5 @@ from gi.repository import Gtk, Gdk +from gi.repository import GObject toolkit = "gtk" # Code responses for GTK +3 dialogs. @@ -19,11 +20,13 @@ CLOSE_EVENT = "delete-event" # This is activated when a button is pressed. BUTTON_PRESSED = "clicked" # This is activated when an user enter text on an edit box. -#ENTERED_TEXT = wx.EVT_TEXT +ENTERED_TEXT = "changed" MENU = "activate" #KEYPRESS = wx.EVT_CHAR_HOOK #NOTEBOOK_PAGE_CHANGED = wx.EVT_NOTEBOOK_PAGE_CHANGED +CHECKBOX = "toggled" + def exit_application(): """ Closes the current window cleanly. """ Gtk.main_quit() @@ -51,21 +54,84 @@ class list(object): self.list = Gtk.TreeView(model=self.store) renderer = Gtk.CellRendererText() for i in range(0, len(self.columns)): - column = Gtk.TreeViewColumn(self.columns[i], renderer, text=0) - column.set_sort_column_id(i) + column = Gtk.TreeViewColumn(self.columns[i], renderer, text=i) +# column.set_sort_column_id(i) self.list.append_column(column) - def insert_item(self, *item): - self.store.append(item) + def insert_item(self, reversed=False, *item): + if reversed == False: + self.store.append(row=item) + else: + self.store.insert(position=0, row=item) def get_selected(self): tree_selection = self.list.get_selection() (model, pathlist) = tree_selection.get_selected_rows() - return pathlist[0] + return int(pathlist[0].to_string() ) def select_item(self, item): tree_selection = self.list.get_selection() tree_selection.select_path(item) + def remove_item(self, item): + self.store.remove(self.store.get_iter(item)) + def get_count(self): return len(self.store) + +class baseDialog(Gtk.Dialog): + def __init__(self, *args, **kwargs): + super(baseDialog, self).__init__(*args, **kwargs) + self.box = self.get_content_area() + + def get_response(self): + answer = self.run() + return answer + +class buffer(GObject.GObject): + name = GObject.property(type=str) + + def __init__(self, obj): + super(buffer, self).__init__() + self.buffer = obj + +class notebook(object): + + def __init__(self): + self.store = Gtk.TreeStore(buffer.__gtype__) + self.view = Gtk.TreeView() + self.view.set_model(self.store) + + column = Gtk.TreeViewColumn("Buffer") + cell = Gtk.CellRendererText() + column.pack_start(cell, True) + column.set_cell_data_func(cell, self.get_buffer) + self.view.append_column(column) + + def get_buffer(self, column, cell, model, iter, data): + cell.set_property('text', self.store.get_value(iter, 0).name) + + def match_func(self, row, name_, account): + name = name_ + account = account + iter = self.store.get_iter(row.path) + if self.store[iter][0].buffer.name == name and self.store[iter][0].buffer.account == account: + return (row.path, iter) + else: + return (None, None) + + def search(self, rows, name_, account): + if not rows: return None + for row in rows: + (path, iter) = self.match_func(row, name_, account) + if iter != None: + return (path, iter) + (result_path, result_iter) = self.search(row.iterchildren(), name_, account) + if result_path: return (result_path, result_iter) + return (None, None) + +class mainLoopObject(object): + + def run(self): + GObject.type_register(buffer) + Gtk.main() diff --git a/src/widgetUtils/wxUtils.py b/src/widgetUtils/wxUtils.py index b871258b..28140852 100644 --- a/src/widgetUtils/wxUtils.py +++ b/src/widgetUtils/wxUtils.py @@ -104,11 +104,11 @@ class BaseDialog(wx.Dialog): def get_title(self): return self.GetTitle() -class mainloopObject(wx.App): +class mainLoopObject(wx.App): def __init__(self): self.app = wx.App() - def run_mainloop(self): + def run(self): self.app.MainLoop() diff --git a/src/wxUI/view.py b/src/wxUI/view.py index fd82b26a..9c20e145 100644 --- a/src/wxUI/view.py +++ b/src/wxUI/view.py @@ -128,7 +128,7 @@ class mainFrame(wx.Frame): 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)