Compare commits

...

109 Commits

Author SHA1 Message Date
437f01ac78 Merge branch 'master' of https://github.com/manuelcortez/twblue 2015-01-13 08:51:41 -06:00
fd6c7fa2d7 Changes for the 0.51 version 2015-01-13 08:51:03 -06:00
jmdaweb
b373e716c7 pa.c format: appinfo.ini: fixed package version. 2015-01-12 21:15:40 +01:00
cc00c513c3 Merge branch 'master' of https://github.com/manuelcortez/twblue 2015-01-12 11:22:33 -06:00
jmdaweb
0a0fe58715 readme.md: fixed duplicated package name. 2015-01-12 17:12:54 +01:00
e831098bd2 Merge branch 'master' of https://github.com/manuelcortez/twblue 2015-01-12 10:02:39 -06:00
jmdaweb
05d62456ee Installer: updated website. Application.py: changed version to 0.51. Main.py: redirect stdout and stderr to log files located in temp folder. 2015-01-12 16:54:19 +01:00
d2e6221432 Commit for 0.51 release 2015-01-12 09:25:07 -06:00
jmdaweb
d31a3e5bb7 Installer script: updated to version 0.51, updated website, added german translation. Added the portableApps template used to package TWBlue in portableApps.com format 2015-01-08 16:12:37 +01:00
e3b0a3d731 Fix for the last commit 2015-01-08 08:11:33 -06:00
3a6849cf0b the Webdomain for TWBlue has been changed 2015-01-08 08:09:20 -06:00
6832a4a93e Merge branch 'master' of https://github.com/manuelcortez/twblue 2015-01-01 21:08:36 -06:00
jmdaweb
bda1ddce47 updated readme file 2014-12-30 22:56:31 +01:00
b106b3a0f2 updated readme 2014-12-29 14:27:34 -06:00
813ad2fc1e Merge branch 'master' of https://github.com/manuelcortez/twblue 2014-12-29 13:53:26 -06:00
4bcd8d8b4e Updated readme; a few bugfixes; german translation is added 2014-12-29 13:52:50 -06:00
jmdaweb
4ef7c6c5f1 Updated pyenchant to version 1.6.6 in windows dependencies submodule 2014-12-26 20:10:58 +01:00
b6c9edafcf Merge branch 'master' of https://github.com/manuelcortez/twblue 2014-12-24 12:07:32 -06:00
73be8400b0 a few bugfixes in date representations. Fix for #14 2014-12-24 12:06:28 -06:00
jmdaweb
5fdbb578c4 removed setuptools from windows dependencies submodule 2014-12-24 10:51:27 +01:00
jmdaweb
540bf5d312 updated windows dependencies with the new python 2.7.9 2014-12-20 00:20:07 +01:00
375cdd2528 0.50 Release changes. Last commit for this year. 2014-12-18 00:59:18 -06:00
jmdaweb
836675bfa1 New sound for trending topics, updated contributors in application.py 2014-12-16 22:12:29 +01:00
jmdaweb
2b3c7601f2 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-15 18:10:55 +01:00
eb2c315abb Bugfixes for lists buffers and autocomplete 2014-12-15 09:53:13 -06:00
e12f440cf2 Build_installer fixes 2014-12-14 19:07:18 -06:00
jmdaweb
57dc271fb0 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-12 19:33:37 +01:00
193cafcc9d A bash script to create TWBlue installer versions has been added 2014-12-12 12:21:59 -06:00
jmdaweb
e7b6c39f76 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-12 11:26:19 +01:00
7df2441442 Fixes for the Snapshot6 compilation process 2014-12-11 15:37:53 -06:00
jmdaweb
aa687450f6 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-11 21:52:01 +01:00
6e0ae38d4e Code changes for Snapshot 6 2014-12-11 12:21:37 -06:00
jmdaweb
fa8c9f639c Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-11 17:26:02 +01:00
9502cef251 Final additions for TWBlue 0.50. TWBlue's source code has been frozen 2014-12-11 10:03:02 -06:00
jmdaweb
982dd78f81 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-11 16:26:30 +01:00
jmdaweb
4b98f27968 Now TWBlue.exe.log shouldn't be created, so admin rights aren't required the first time in the installed version. 2014-12-11 16:25:22 +01:00
jmdaweb
ecb0fa8f2b Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-10 20:04:17 +01:00
ef2ff9dbfc This tries to fix the bug related to stdout and stderr for TWBlue installed 2014-12-10 12:44:11 -06:00
jmdaweb
1fe94642a2 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-10 18:33:18 +01:00
b232a0b0ad Ignoring clients improvements: adding clients from the action users dialog does always work, no matters the buffer the client is added 2014-12-10 11:19:38 -06:00
2ce59cf208 Autocompletion improvements. Adding/removing users manually is now possible. 2014-12-09 17:56:43 -06:00
jmdaweb
ceb8266828 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-09 17:10:44 +01:00
jmdaweb
21970f2c94 installer: now two radio buttons are displayed in the license page. 2014-12-09 17:10:03 +01:00
14965f73d3 Invisible shorcuts no blocks itself when passes through the events buffer 2014-12-09 08:26:33 -06:00
jmdaweb
267b454fc6 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-09 10:36:30 +01:00
c3dc00c241 Mantis support is back on TWBlue 2014-12-08 22:06:44 -06:00
jmdaweb
9fb67f01ae Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-08 20:49:05 +01:00
6d1cd0b1fc The mention all button works as espected when someone replies to a retweet 2014-12-08 13:38:27 -06:00
a7ef572d05 Now, TWBlue does not block the system when any session is closed or turned off 2014-12-08 12:46:29 -06:00
403784b77a The switcher module does not close the app when it is cancelled. 2014-12-08 10:17:07 -06:00
d032a6d8f7 Use invisible interface's keyboard shorcuts even if the window is displayed 2014-12-08 09:44:02 -06:00
jmdaweb
231d43ab22 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-08 00:32:46 +01:00
5e3bcfc82e Mentions are detected even if username's capitalization is incorrect 2014-12-07 13:24:56 -06:00
8e92d97260 Trending topic buffers are removed from configuration 2014-12-07 12:22:19 -06:00
bb1ffa9ff1 Merge branch 'master' of https://github.com/manuelcortez/twblue 2014-12-07 09:31:46 -06:00
104bc4ec8c Changes for Snapshot 5 release 2014-12-07 09:31:39 -06:00
jmdaweb
6ae555fe72 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-06 20:18:10 +01:00
jmdaweb
dd51516c30 Improved installer script. In the finish page, it shows a checkbox to run TW Blue, and a button to go to the website. Modified installer version to 0.50 2014-12-06 20:17:21 +01:00
jmdaweb
4e18bb0721 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-06 00:09:11 +01:00
jmdaweb
0492e65aa0 Merge branch 'master' of github.com:manuelcortez/TWBlue 2014-12-06 00:08:43 +01:00
jmdaweb
a5fb59d7a7 fixed submodule 2014-12-06 00:08:09 +01:00
f2fab29cb7 Trending topics improvements 2014-12-05 17:05:29 -06:00
jmdaweb
f36accf89b Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-06 00:01:21 +01:00
a13536233e Improvements on autocomplete, now it updates its database at startup 2014-12-05 16:23:54 -06:00
bc2d448464 Updated translations 2014-12-05 12:21:40 -06:00
60ec9ab215 Date is displayed properly in the GUI 2014-12-05 11:31:58 -06:00
20b5fc079b onFocus will play the ogg file instead the mp3 2014-12-05 11:25:29 -06:00
80e231b689 Merge branch 'master' of https://github.com/manuelcortez/twblue 2014-12-05 11:21:27 -06:00
7137d437bd Basic tt support, fixed some English mistakes reported by @sukiletxe 2014-12-05 11:20:55 -06:00
jmdaweb
a07b3c1829 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-02 23:36:47 +01:00
jmdaweb
c062c10542 Converted the geo sound to ogg format 2014-12-02 23:35:37 +01:00
jmdaweb
0e7c070bd4 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-02 22:18:45 +01:00
jmdaweb
9f35d079b1 Updated windows-dependencies submodule with the new pycurl 2014-12-02 22:18:11 +01:00
jmdaweb
a3fca4d2a0 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-02 21:27:00 +01:00
ada6f1fb0d Fixing some issues with tweets and retweets 2014-12-02 11:40:39 -06:00
79124810b0 Reverse geocode is now in TWBlue. Ctrl+win+g and CTRL+Shift+Win+G and in the tweet menu on the menu bar 2014-12-01 17:19:03 -06:00
fee7254d55 Configuration for autocompletion users 2014-12-01 15:21:25 -06:00
jmdaweb
c12902d011 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-12-01 13:14:36 +01:00
2f7eb12104 There is a context menu on buffers. When the applications key or the right mouse button is pressed that menu is displayed. It only works for the GUI 2014-12-01 05:55:25 -06:00
855cefeb8d Now the session manager does not appear ramdonly 2014-11-30 22:35:48 -06:00
e649b883c6 gendoc script has been deletedo so it isn't necessary 2014-11-30 17:43:00 -06:00
jmdaweb
1a61f2d790 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-11-30 22:26:33 +01:00
jmdaweb
6abfba317a updated windows dependencies submodule 2014-11-30 22:25:50 +01:00
jmdaweb
18ce92daab Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-11-30 11:19:03 +01:00
jmdaweb
84f729f42b Now setup.py shouldn't include an unnecesary mfc90.dll in x64 builds 2014-11-30 11:17:26 +01:00
jmdaweb
4e7666cf52 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-11-30 00:42:56 +01:00
88e0fbb531 Updated readmes 2014-11-29 11:29:22 -06:00
af32b3ceb6 Merge branch 'master' of github.com:manuelcortez/TWBlue 2014-11-29 11:09:39 -06:00
94dc083650 Windows-dependencies fix 2014-11-29 11:09:33 -06:00
acb3cce1d6 Changes on snapshot 4; audio uploader fixes 2014-11-29 11:07:06 -06:00
jmdaweb
2b3e1099f6 Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-11-27 22:05:21 +01:00
jmdaweb
60507e8f6b Pressing enter, spacebar or mouse left click should show window if it's not visible 2014-11-27 17:31:10 +01:00
jmdaweb
75bfc17bb1 Merge branch 'master' of github.com:manuelcortez/TWBlue 2014-11-27 17:19:08 +01:00
acb8c5acd3 TWBlue starts automatically if there is only an account 2014-11-27 07:18:05 -06:00
jmdaweb
5bcf04fc94 Merge branch 'master' of github.com:manuelcortez/TWBlue 2014-11-27 10:12:54 +01:00
0f2fbc775a Switch account is now possible from the application menu 2014-11-26 17:26:53 -06:00
1b684cd12c The session manager has a remove account button 2014-11-26 16:38:46 -06:00
9d64901791 Session manager deletes invalid sessions; plays audio from any URL when the tweet has more than one 2014-11-26 13:45:24 -06:00
18f7cb6c96 Replies will not show on list buffers 2014-11-26 11:52:36 -06:00
7f673fb9de Show more information about tweets on the ViewTweets dialog 2014-11-26 05:43:13 -06:00
jmdaweb
f6f542fbec Merge branch 'master' of https://github.com/manuelcortez/TWBlue 2014-11-25 23:09:33 +01:00
jmdaweb
a211e2e5e4 Merge branch 'master' of github.com:manuelcortez/TWBlue 2014-11-25 22:49:12 +01:00
3ec8ac31a5 Autocompletion for users has been implemented 2014-11-25 12:30:00 -06:00
jmdaweb
dacbb19586 added the windows dependencies as a git submodule, so the users can get them only if they plan to build a binary version 2014-11-25 14:44:59 +01:00
jmdaweb
55691cca20 Fixed setup.py, now it takes the correct bootstrap.exe in x64 builds 2014-11-24 17:26:35 +01:00
0104b97df0 Merge branch 'master' of github.com:manuelcortez/TWBlue 2014-11-21 11:39:35 -06:00
aa58e61e5e TWBlue shows followers and friends in realtime again 2014-11-21 11:37:41 -06:00
jmdaweb
fae204f3c2 updated windows build instructions 2014-11-19 16:07:55 +01:00
d8149a4c96 TWBlue has access to the direct messages on all accounts 2014-11-14 16:05:34 -06:00
120 changed files with 16705 additions and 6618 deletions

4
.gitignore vendored
View File

@@ -1,12 +1,8 @@
*.pyc
*~
windows-dependencies/*
src/build/
src/dist/
src/config/
src/config1/
src/config2/
src/config3/
src/dropbox/
src/logs/
src/documentation/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "windows-dependencies"]
path = windows-dependencies
url = https://github.com/jmdaweb/TWBlue_deps_windows.git

View File

@@ -15,4 +15,92 @@ TW Blue is an app designed to use Twitter in a simple and fast way and avoiding,
* Play various file and URL types which contain audio
* and more!
See the [TWBlue's webpage](http://twblue.com.mx) for more details.
See the [TWBlue's webpage](http://twblue.com.mx) for more details.
## Using TWBlue from sources
This document describes how to run tw blue from source, and, after that, how to build a binary version, which doesn't need Python and the other dependencies to run.
### Required dependencies.
Although most dependencies can be found in the windows-dependencies directory, we provide links to their official websites. If you are cloning with git, don't forget to initialize and update the submodules to get the windows-dependencies folder. You can use these two commands to perform this task from git bash:
git submodule init
git submodule update
All the dependencies provided in this folder are prebuilt. If you want to build them from source, you will need Microsoft visual Studio 2008.
#### Dependencies packaged in windows installers
* [Python,](http://python.org) version 2.7.9
If you want to build both x86 and x64 binaries, you can install python x86 to C:\python27 and python x64 to C:\python27x64, for example.
* [wxPython](http://www.wxpython.org) for Python 2.7, version 3.0.2
* [Python windows extensions (pywin32)](http://www.sourceforge.net/projects/pywin32/) for python 2.7, build 219
* [Pycurl](http://pycurl.sourceforge.net) 7.19.5 for Python 2.7: [32-bit downloads,](https://pypi.python.org/pypi/pycurl/7.19.3.1) [64-bit downloads](http://www.lfd.uci.edu/~gohlke/pythonlibs/)
* [PyEnchant,](http://pythonhosted.org/pyenchant/) version 1.6.6.
x64 version has been built by TW Blue developers, so you only will find it in windows-dependencies folder
The windows installers are available only in the windows-dependencies folder
To build a binary version:
* [Py2exe](http://www.sourceforge.net/projects/py2exe/) for Python 2.7, version 0.6.9
#### Dependencies that must be installed using easy_install
setuptools install a script, called easy_install. You can find it in the python scripts directory. To install packages using easy_install, you have to navigate to the scripts directory using a command prompt, for example:
cd C:\python27x64\scripts
You can also add the scripts folder to your path environment variable.
After that, run the following command to install a package, replacing packagename with the names listed below:
easy_install -Z package
The -z switch unzips the package, instead of installing it compressed. If you add the --upgrade switch, you can upgrade a package to its latest version. The following packages need to be installed:
* dropbox
* configobj
* requests-oauthlib
* future
* pygeocoder
* suds
* arrow
* markdown
easy_install will automatically get the additional libraries that these packages need to work properly.
#### Other dependencies
These dependencies are located in the windows-dependencies directory. You don't need to install or modify them.
* Bootstrap 1.2.1: included in dependencies directory.
This dependency has been built using pure basic 4.61. Its source can be found at http://hg.q-continuum.net/updater
* [oggenc2.exe,](http://www.rarewares.org/ogg-oggenc.php) version 2.87
* Microsoft Visual c++ 2008 redistributable dlls.
#### Dependencies required to build the installer
* [NSIS unicode,](http://www.scratchpaper.com/) version 2.46.5
### Running TW Blue from source
Now that you have installed all these packages, you can run TW Blue from source using a command prompt. Navigate to the src directory into the repo, and type the following command:
python main.py
If necesary, change the first part of the command to reflect where is your python executable. You can run TW Blue using python x86 and x64
### Building a binary version
A binary version doesn't need python and the other dependencies to run, it's the same version that you will find in TW Blue website if you download the zip files.
To build it, run the following command from the src folder:
python setup.py py2exe
You will find the binaries in the dist directory.
### How to generate a translation template
You must run the gen_pot.bat file, located in the tools directory. Your python installation should be in your path environment variable. The pot file will appear in the tools directory too.

View File

@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
import application
documentation = []
documentation.append(_(u"""Documentation for TW Blue 0.46"""))
documentation.append(_(u"""Documentation for {0} - {1}""").format(application.name, application.version))
# Translators: This is the new line character, don't change it in the translations.
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Table of contents"""))
# Table of contents for the python markdown extension
documentation.append("""[TOC]""")
#documentation.append(_(u"""# Version 0.46 (alpha)"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Warning!"""))
@@ -41,42 +42,44 @@ documentation.append(_(u"""
documentation.append(_(u"""In order to use an application like TW Blue which allows you to manage your Twitter account, you must first be registered on it. It's beyond the scope of this document to explain how to do so. We'll start from the premise that you have an account with its corresponding user name and password."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Authorising the application"""))
documentation.append(_(u"""### Authorising the application"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""First off, it's necessary to authorise the program so it can access your Twitter account and act on your behalf. The authorisation process is quite simple, and the program never gets data such as your username and password. In order to authorise the application, you just need to run the main executable file, called TWBlue.exe (on some computers it may appear simply as TWBlue)."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""When executed, if you have not previously configured the program, it will show a dialogue box where it tells you'll be taken to Twitter in order to authorise the application as soon as you press OK. To begin the authorisation process, press the only available button on the box."""))
#$documentation.append(_(u"""When executed, if you have not previously configured the program, it will show a dialogue box where it tells you'll be taken to Twitter in order to authorise the application as soon as you press OK. To begin the authorisation process, press the only available button on the box."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Your default browser will open on the Twitter page to request authorisation. Enter your user name and password if you're not already logged in, look for the authorise button, and press it."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Read the instructions you will get if the process is successful. In summary, you will be given a numeric code with several digits you must paste on an edit field open by the application on another window."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Paste the verification code, and press the enter key. """))
documentation.append(_(u"""
"""))
#$documentation.append(_(u"""Read the instructions you will get if the process is successful. In summary, you will be given a numeric code with several digits you must paste on an edit field open by the application on another window."""))
#$documentation.append(_(u"""
#$"""))
#$documentation.append(_(u"""Paste the verification code, and press the enter key. """))
#$documentation.append(_(u"""
#$"""))
### Add here the instructions on how to deal with the session manager.
documentation.append(_(u"""If all went well, the application will start playing sounds, indicating your data are being updated."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""When the process is finished,the program will play another sound, and the screen reader will say "ready"."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## The program's interface {#interface}"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""The easiest way to describe the graphical interface of the application is a window with a menu bar with four menus (application, tweet, user and help), a list with several elements, and, in most cases, three buttons: tweet, retweet and reply. The actions available for each element are described below."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Elements on the lists may be tweets, direct messages or users. TW Blue creates different tabs for each list, which can be sent tweets, main timeline tweets, favourites, or direct messages, and each tab contains a single type of tweet. These tabs are called lists or buffers."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""To switch from list to list press control-tab to go forward, and control-shift-tab to go back. Screen readers will announce the list that gains the focus at all times. These are the basic lists of TW Blue, which are configured by default."""))
documentation.append(_(u"""## The program's interface"""))
documentation.append(_(u"""
"""))
### Add the new GUI description here
#$documentation.append(_(u"""The easiest way to describe the graphical interface of the application is a window with a menu bar with five menus (application, tweet, user, buffer and help), a list with several elements, and, in most cases, three buttons: tweet, retweet and reply. The actions available for each element are described below."""))
#$documentation.append(_(u"""
#$"""))
#$documentation.append(_(u"""Elements on the lists may be tweets, direct messages or users. TW Blue creates different tabs for each list, which can be sent tweets, main timeline tweets, favourites, or direct messages, and each tab contains a single type of tweet. These tabs are called lists or buffers."""))
#$documentation.append(_(u"""
#$"""))
#$documentation.append(_(u"""To switch from list to list press control-tab to go forward, and control-shift-tab to go back. Screen readers will announce the list that gains the focus at all times. These are the basic lists of TW Blue, which are configured by default."""))
#$documentation.append(_(u"""
#$"""))
documentation.append(_(u"""* Home: it shows all the tweets on the main timeline. These are the tweets by users you follow."""))
documentation.append(_(u"""* Mentions: if a user, whether you follow them or not, mentions you on Twitter, you will find it on this list."""))
documentation.append(_(u"""* Direct messages: here go the private direct messages you exchange with users you follow and who follow you back. This list only shows received messages."""))
@@ -86,38 +89,42 @@ documentation.append(_(u"""* Followers: when users follow you, you'll be able to
documentation.append(_(u"""* Friends: the same as the previous list, but these are the users you follow."""))
documentation.append(_(u"""* User timelines: these are lists you may create. They contain only the tweets by a specific user. They're used so you can see the tweets by a single person and you don't want to look all over your timeline. You may create as many as you like."""))
documentation.append(_(u"""* Events: An event is anything that happens on Twitter, such as when someone follows you, when someone adds or removes one of your tweets from their favorites list, or when you subscribe to a list. There are many more but TW Blue shows the most common ones in the events buffer so that you can easily keep track of what is happening on your account."""))
documentation.append(_(u"""* Lists: A list is similar to a temporary timeline, except that you can configure it to contain tweets from multiple users. This is currently an experimental feature. If you decide to use it, please report any problems you encounter."""))
documentation.append(_(u"""* Lists: A list is similar to a temporary timeline, except that you can configure it to contain tweets from multiple users."""))
documentation.append(_(u"""* Search: A search buffer contains the results of a search operation."""))
documentation.append(_(u"""* User favorites: You can have TW Blue create a buffer containing tweets favorited by a particular user."""))
### add here the trending buffers description.
documentation.append(_(u"""
"""))
documentation.append(_(u"""Note: In this version of TW Blue, you will be able to see up to (or around) 400 friends and followers in their respective buffers. In the next version, we will provide a solution for those who have more to be able to see them."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Bear in mind the default configuration only allows getting the last 200 tweets for the home,, mentions, direct messages, and user timeline lists. You can change this on the setup dialogue. For the sent list, the last 200 tweets and the last 200 sent direct messages will be retrieved. Future versions will allow changing this parameter."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""If there's a URL on a tweet TW Blue will try to open it when you press enter on it. If there are several, it will show you a list with all of them so you choose the one you want. If you're on the followers or friends dialogue, the enter key will show you additional information on them."""))
#$documentation.append(_(u"""Note: In this version of TW Blue, you will be able to see up to (or around) 400 friends and followers in their respective buffers. In the next version, we will provide a solution for those who have more to be able to see them."""))
#$documentation.append(_(u"""
#$"""))
#$documentation.append(_(u"""Bear in mind the default configuration only allows getting the last 200 tweets for the home,, mentions, direct messages, and user timeline lists. You can change this on the setup dialogue. For the sent list, the last 200 tweets and the last 200 sent direct messages will be retrieved. Future versions will allow changing this parameter."""))
#$documentation.append(_(u"""
#$"""))
documentation.append(_(u"""If there's a URL on a tweet TW Blue will try to open it when you press enter on it. If there are several, it will show you a list with all of them so you choose the one you want. If you're on the followers or friends buffer, the enter key will show you additional information on them."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""If you press control-enter, TW Blue will try to play the audio from the focused tweet, as long as it has a URL. If it has the #audio hashtag, you will hear a sound when it is selected, letting you know you can try to play it. However, a tweet can be missing the hashtag and TW Blue will still be able to play it so long as it contains a URL with audio."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Controls {#controls}"""))
### Add information about the GEO location in tweets.
documentation.append(_(u"""## Controls"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Beginning with the latest version, there's support for an interface which does not require a visible window. It can be activated by pressing control-m, or choosing hide window from the application menu. This interface is entirely driven through shortcut keys. These shortcuts are different from those used to drive the graphical interface. Each interface can use only its own shortcuts, so you may not use the invisible shortcuts if you have the graphical interface opened. This section describes both the graphical and the invisible interface."""))
### add more information about using invisible shorcuts in the GUI mode in the next variable.
documentation.append(_(u"""Beginning with the 0.36 version, there's support for an interface which does not require a visible window. It can be activated by pressing control-m, or choosing hide window from the application menu. This interface is entirely driven through shortcut keys. These shortcuts are different from those used to drive the graphical interface. This section describes both the graphical and the invisible interface."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""### The graphical user interface (GUI) {#gui}"""))
documentation.append(_(u"""### The graphical user interface (GUI)"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Here you have a list divided into two parts. On the one hand, the buttons you will find while tabbing around on the program's interface, and on the other, the different elements present on the menu bar."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""#### Buttons on the application {#buttons}"""))
documentation.append(_(u"""#### Buttons on the application"""))
documentation.append(_(u"""
"""))
### Add information on spell correction, translate, attach images and audio.
documentation.append(_(u"""* Tweet: this button opens up a dialogue box to write your tweet. The message must not exceed 140 characters. If you write past this limit, a sound will play to warn you. You may use the shorten and expand URL buttons to comply with the character limit. Press enter to send the tweet. If all goes well, you'll hear a sound confirming it. Otherwise, the screen reader will say an error message in English describing the problem."""))
documentation.append(_(u"""* Retweet: this button retweets the message you're reading. After you press it, you'll be asked if you want to add a comment or simply send it as written."""))
documentation.append(_(u"""* Reply: when you're viewing a tweet, you can reply to the user who sent it by pressing this button. A dialogue will open up like the one for tweeting, but with the name of the user already filled in (for example @user) so you only need to write your message. If there are more users mentioned on the tweet, you can press shift-tab and press the mention all users button. When you're on the friends or followers lists, the button will be called mention instead."""))
@@ -127,13 +134,13 @@ documentation.append(_(u"""
documentation.append(_(u"""Bear in mind that buttons will appear according to which actions are possible on the list you are browsing. For example, on the home timeline, mentions, sent, favourites and user timelines you will see the four buttons, while on the direct messages list you'll only get the direct message and tweet buttons, and on friends and followers lists you will get the direct message, tweet, and mention buttons."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""#### Menus {#menus}"""))
documentation.append(_(u"""#### Menus"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""On top of the program window there's a menu bar which has the same functions, and some more. To access the menu bar, press alt. You will find four menus: application, tweet, user and help. This section describes the items on each one of them."""))
documentation.append(_(u"""On top of the program window there's a menu bar which has the same functions, and some more. To access the menu bar, press alt. You will find five: application, tweet, user, buffer and help. This section describes the items on each one of them."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""##### Application menu {#app}"""))
documentation.append(_(u"""##### Application menu"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""* Update profile: opens a dialogue box where you can update your information on Twitter: name, location, URL and bio. If you have already set this up the fields will be prefilled with the existing information. Also, you can upload a photo to your profile."""))

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,8 @@
[Launch]
ProgramExecutable=TWBlue\TWBlue.exe
ProgramExecutable64=TWBlue64\TWBlue.exe
CommandLineArguments=-p -d "%PAL:DataDir%"
SinglePortableAppInstance=true
MinOS=XP
SingleAppInstance=false
DirectoryMoveOK=yes

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

View File

@@ -0,0 +1,28 @@
[Format]
Type=PortableApps.comFormat
Version=3.0
[Details]
Name=TWBlue portable
AppID=TWBluePortable
Publisher=jmdaweb & TWBlue & PortableApps.com
Homepage=PortableApps.com/TWBluePortable
Category=Internet
Description=A portable, fast and accessible Twitter client with many options.
Language=Multilingual
InstallType=Multilingual
[License]
Shareable=true
OpenSource=true
Freeware=true
CommercialUse=true
EULAVersion=2
[Version]
PackageVersion=0.51.0.0
DisplayVersion=0.51
[Control]
Icons=1
Start=TWBluePortable.exe

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,17 @@
[Languages]
ENGLISH=true
ENGLISHGB=true
ARABIC=true
BASQUE=true
CATALAN=true
FINNISH=true
FRENCH=true
GALICIAN=true
GERMAN=true
HUNGARIAN=true
ITALIAN=true
POLISH=true
PORTUGUESEBR=true
RUSSIAN=true
SPANISHINTERNATIONAL=true
TURKISH=true

View File

@@ -0,0 +1,3 @@
The files in this directory are necessary for the portable application to
function. There is normally no need to directly access or alter any of the
files within these directories.

339
pa.c format/App/license.txt Normal file
View File

@@ -0,0 +1,339 @@
 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,41 @@
You can get tw blue's source code at https://github.com/manuelcortez/TWBlue
LICENSE
=======
This package's installer and launcher are released under the GPL. The launcher
is the PortableApps.com Launcher, available with full source and documentation
from http://portableapps.com/development. We request that developers using the
PortableApps.com Launcher please leave this directory intact and unchanged.
USER CONFIGURATION
==================
Some configuration in the PortableApps.com Launcher can be overridden by the
user in an INI file next to TWBluePortable.exe called TWBluePortable.ini.
If you are happy with the default options, it is not necessary, though. There
is an example INI included with this package to get you started. To use it,
copy AppNamePortable.ini from this directory to TWBluePortable.ini next to
TWBluePortable.exe. The options in the INI file are as follows:
AdditionalParameters=
DisableSplashScreen=false
RunLocally=false
(There is no need for an INI header in this file; if you have one, though, it
won't damage anything.)
The AdditionalParameters entry allows you to pass additional command-line
parameters to the application.
The DisableSplashScreen entry allows you to run the launcher without the splash
screen showing up. The default is false.
The RunLocally entry allows you to run the portable application from a read-
only medium. This is known as Live mode. It copies what it needs to to a
temporary directory on the host computer, runs the application, and then
deletes it afterwards, leaving nothing behind. This can be useful for running
the application from a CD or if you work on a computer that may have spyware or
viruses and you'd like to keep your device set to read-only. As a consequence
of this technique, any changes you make during the Live mode session aren't
saved back to your device. The default is false.

View File

@@ -0,0 +1,6 @@
AdditionalParameters=
DisableSplashScreen=false
RunLocally=false
# The above options are explained in the included readme.txt
# This INI file is an example only and is not used unless it is placed as described in the included readme.txt

150
pa.c format/help.html Normal file
View File

@@ -0,0 +1,150 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>TWBlue Portable Help</title>
<link rel="alternate" href="http://portableapps.com/feeds/general" type="application/rss+xml" title="PortableApps.com">
<link rel="shortcut icon" href="Other/Help/Images/Favicon.ico">
<style type="text/css">
body {
font-family : Verdana,Arial,Helvetica,sans-serif;
font-size : 76%;
color : black;
margin : 20px;
background : #e6e8ea;
text-align : center;
}
a {
color : #b31616;
font-weight : bold;
}
a:link, a:visited, a:active {}
a:hover {
color : red;
}
h1, h2, h3, h4, h5, h6 {
font-family : Arial, sans-serif;
font-weight : normal;
}
h1 {
color : #b31616;
font-weight : bold;
letter-spacing : -2px;
font-size : 2.2em;
border-bottom : 1px solid silver;
padding-bottom : 5px;
}
h2 {
font-size : 1.5em;
border-bottom : 1px solid silver;
padding-bottom : 3px;
clear : both;
}
h3 { font-size : 1.2em; }
h4 { font-size : 1.1em; }
h5 { font-size : 1.0em; }
h6 { font-size : 0.8em; }
img { border : 0; }
ol, ul, li, p, pre, table, tr, td, th { font-size : 1.0em; }
pre { font-family : monospace; }
strong, b { font-weight : bold; }
td, th {
border : 1px solid #aaaaaa;
border-collapse : collapse;
padding : 3px;
}
th {
background : #3667a8;
color : white;
}
ol ol { list-style-type : lower-alpha; }
.content {
text-align : left;
margin-left : auto;
margin-right : auto;
width : 780px;
background-color : white;
border-left : 1px solid black;
border-right : 1px solid black;
padding : 12px 30px;
line-height : 150%;
}
.logo {
background : white url("Other/Help/Images/Help_Background_Header.png") repeat-x;
width : 840px;
margin-top : 20px;
margin-left : auto;
margin-right : auto;
text-align : left;
border-right : 1px solid black;
border-left : 1px solid black;
}
.footer {
background : white url("Other/Help/Images/Help_Background_Footer.png") repeat-x;
width : 840px;
height : 16px;
margin-left : auto;
margin-right : auto;
text-align : left;
border-right : 1px solid black;
border-left : 1px solid black;
}
.logo img {
padding-left : 0px;
border : none;
position : relative;
top : -4px;
}
* html .content { width : 760px; }
* html .logo, * html .footer { width : 820px; }
.content h1 { margin : 0px; }
h1.hastagline { border : 0; }
h2.tagline {
color : #747673;
clear : none;
margin-top : 0em;
}
/* printer styles */
@media print {
body, .content {
margin : 0;
padding : 0;
}
.navigation, .locator, .footer a, .message, .footer-links { display : none; }
.footer, .content, .header { border : none; }
a {
text-decoration : none;
font-weight : normal;
color : black;
}
}
</style>
</head>
<body>
<div class="logo"><a href="http://portableapps.com/"><img src="Other/Help/Images/Help_Logo_Top.png" alt="PortableApps.com - Your Digital Life, Anywhere"></a></div>
<div class="content">
<h1 class="hastagline">TWBlue Portable Help</h1>
<h2 class="tagline">A powerful and accessible Twitter client</h2>
<p>TWBlue Portable is the TWBlue whatever it is packaged with a PortableApps.com launcher as a <a href="http://portableapps.com/about/what_is_a_portable_app">portable app</a>, so you can view and send tweets on your iPod, USB flash drive, portable hard drive, etc. It has all the same features as TWBlue, plus, it leaves no personal information behind on the machine you run it on, so you can take it with you wherever you go. <a href="http://twblue.es">Learn more about TWBlue...</a></p>
<p><a href="http://portableapps.com/donate"><img src="Other/Help/Images/Donation_Button.png" style="vertical-align:middle" alt="Make a Donation"></a> - Support PortableApps.com's Hosting and Development</p>
<p><a href="http://portableapps.com/node/*Node ID*">Go to the TWBlue Portable Homepage &gt;&gt;</a></p>
<p><a href="http://portableapps.com/">Get more portable apps at PortableApps.com</a></p>
<p>This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative.</p>
<h2>Portable App Issues</h2>
<ul>
<li><a href="http://portableapps.com/support/portable_app#downloading">Downloading a Portable App</a></li>
<li><a href="http://portableapps.com/support/portable_app#installing">Installing a Portable App</a></li>
<li><a href="http://portableapps.com/support/portable_app#using">Using a Portable App</a></li>
<li><a href="http://portableapps.com/support/portable_app#upgrading">Upgrading a Portable App</a></li>
</ul>
<p>You can read about advanced configuration options for the PortableApps.com Launcher in its <a href="Other/Source/Readme.txt">readme file</a>.</p>
</div>
<div class="footer"></div>
</body>
</html>

View File

@@ -1,60 +0,0 @@
tw blue build instructions for Windows
Introduction.
This document describes how to run tw blue from source, and, after that, how to build a binary version, which doesn't need Python and the other dependencies to run.
Required dependencies.
The following dependencies need to be installed in your system. If you want to build tw blue for 32-bit versions of Windows, you will find the required software in the x86 folder, inside dependencies directory. If you want to build tw blue for 64-bit windows versions, use the x64 folder.
In this document you will also find links to each dependency website.
If you want to build manually some of the following libraries, you need Microsoft Visual studio 2008 professional.
Dependencies list:
- Python, version 2.7.6: http://www.python.org
- wxPython for Python 2.7, version 3.0.0 (2.9.5 to avoid problems in windows xp): http://www.wxpython.org
-Python windows extensions (pywin32) for python 2.7, build 218: http://www.sourceforge.net/projects/pywin32/
- ConfigObj, version 4.7.2: http://www.voidspace.org.uk/python/configobj.html
- oauthlib 0.6.1: https://pypi.python.org/pypi/oauthlib/0.6.1
- Pycurl 7.19.3.1 for Python 2.7:
Official website: http://pycurl.sourceforge.net/
32-bit downloads: https://pypi.python.org/pypi/pycurl/7.19.3.1
64-bit downloads: http://www.lfd.uci.edu/~gohlke/pythonlibs/
- Requests 2.2.1:
Official website: http://www.python-requests.org/en/latest/
Recommended download site: https://pypi.python.org/pypi/requests/2.2.1
- Requests-oauthlib 0.4.0: https://github.com/requests/requests-oauthlib
- Suds 0.4:
Official website: https://fedorahosted.org/suds
Recommended download site: https://pypi.python.org/pypi/suds/0.4
- Twython 3.1.2: https://pypi.python.org/pypi/twython/3.1.2
- Bootstrap 1.2.1: included in dependencies directory.
Copy the bootstrap.exe file corresponding to the desired platform in the windows folder, inside this repository.
This dependency has been built using pure basic 4.61. Its source can be found at http://hg.q-continuum.net/updater
- oggenc2.exe, version 2.87: http://www.rarewares.org/ogg-oggenc.php
Copy the oggenc2.exe file corresponding to the desired platform in the windows folder, inside this repository.
-Visual C++ 2008 dlls, included in vcredist-x86.7z and vcredist-x64.7z:
Extract the file corresponding to your platform to the windows folder.
To build the binary version:
- Py2exe for Python 2.7, version 0.6.9: http://www.sourceforge.net/projects/py2exe/
- Setuptools 2.1: https://pypi.python.org/pypi/setuptools
- 7-zip: http://7-zip.org
To generate the documentation:
- Pandoc, version 1.12.3:
Official website: http://johnmacfarlane.net/pandoc/
Downloads site: http://code.google.com/p/pandoc/downloads/list
How to run tw blue from source
Run the file main.py located in windows folder. If you have a x64 system, you can install both 32-bit and 64-bit python versions, and test tw blue in these platforms.
How to generate the documentation
To generate quickly the documentation, a bash console is required. You can find bash in git for windows, cygwin, or MSYS, for example.
You must navigate to the tools directory and run the script gen_doc.sh. It will generate and place all html documentation in windows\documentation directory.
How to build a binary version
You must type the following command. In the following example, we will assume that python is the path to the python executable (x86 or x64) and that you have navigated to the windows directory:
python setup.py py2exe
You will find the binary version in the dist directory. You can compress this folder using 7-zip and you will get the zip version.
How to generate a translation template
You must run the gen_pot.bat file, located in the tools directory. Your python installation should be in your path environment variable. The pot file will appear in the tools directory too.

View File

@@ -1,83 +1,89 @@
!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "x64.nsh"
CRCCheck on
XPStyle on
Name "TW Blue"
OutFile "TWBlue_setup.exe"
InstallDir "$PROGRAMFILES\twblue"
InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "InstallLocation"
RequestExecutionLevel admin
SetCompress auto
SetCompressor /solid lzma
SetDatablockOptimize on
VIAddVersionKey ProductName "TW Blue"
VIAddVersionKey LegalCopyright "Copyright 2014 Manuel Cortez."
VIAddVersionKey ProductVersion "0.48"
VIAddVersionKey FileVersion "0.48"
VIProductVersion "0.48.0.0"
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "license.txt"
!insertmacro MUI_PAGE_DIRECTORY
var StartMenuFolder
!insertmacro MUI_PAGE_STARTMENU startmenu $StartMenuFolder
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "Spanish"
!insertmacro MUI_LANGUAGE "Italian"
!insertmacro MUI_LANGUAGE "Finnish"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "PortugueseBR"
!insertmacro MUI_LANGUAGE "Polish"
!insertmacro MUI_LANGUAGE "Hungarian"
!insertmacro MUI_LANGUAGE "Turkish"
!insertmacro MUI_LANGUAGE "Arabic"
!insertmacro MUI_LANGUAGE "Galician"
!insertmacro MUI_LANGUAGE "Catalan"
!insertmacro MUI_LANGUAGE "Basque"
!insertmacro MUI_RESERVEFILE_LANGDLL
Section
SetShellVarContext All
SetOutPath "$INSTDIR"
${If} ${RunningX64}
File /r TWBlue64\*
${Else}
File /r TWBlue\*
${EndIf}
CreateShortCut "$DESKTOP\TW Blue.lnk" "$INSTDIR\TWBlue.exe" "-i"
!insertmacro MUI_STARTMENU_WRITE_BEGIN startmenu
CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TW Blue.lnk" "$INSTDIR\TWBlue.exe" "-i"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TW Blue on the web.lnk" "http://twblue.com.mx"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
!insertmacro MUI_STARTMENU_WRITE_END
WriteUninstaller "$INSTDIR\Uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayName" "TW Blue"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortez"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.47"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.com.mx"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 47
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1
SectionEnd
Section "Uninstall"
SetShellVarContext All
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue"
RMDir /r /REBOOTOK $INSTDIR
Delete "$DESKTOP\TW Blue.lnk"
!insertmacro MUI_STARTMENU_GETFOLDER startmenu $StartMenuFolder
RMDir /r "$SMPROGRAMS\$StartMenuFolder"
SectionEnd
Function .onInit
${If} ${RunningX64}
StrCpy $instdir "$programfiles64\twblue"
${EndIf}
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "x64.nsh"
CRCCheck on
XPStyle on
Name "TW Blue"
OutFile "TWBlue_setup.exe"
InstallDir "$PROGRAMFILES\twblue"
InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "InstallLocation"
RequestExecutionLevel admin
SetCompress auto
SetCompressor /solid lzma
SetDatablockOptimize on
VIAddVersionKey ProductName "TW Blue"
VIAddVersionKey LegalCopyright "Copyright 2014 Manuel Cortez."
VIAddVersionKey ProductVersion "0.51"
VIAddVersionKey FileVersion "0.51"
VIProductVersion "0.51.0.0"
!insertmacro MUI_PAGE_WELCOME
!define MUI_LICENSEPAGE_RADIOBUTTONS
!insertmacro MUI_PAGE_LICENSE "license.txt"
!insertmacro MUI_PAGE_DIRECTORY
var StartMenuFolder
!insertmacro MUI_PAGE_STARTMENU startmenu $StartMenuFolder
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_LINK "Visit TW Blue website"
!define MUI_FINISHPAGE_LINK_LOCATION "http://twblue.es"
!define MUI_FINISHPAGE_RUN "$INSTDIR\TWBlue.exe"
!define MUI_FINISHPAGE_RUN_PARAMETERS "-i"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "Spanish"
!insertmacro MUI_LANGUAGE "Italian"
!insertmacro MUI_LANGUAGE "Finnish"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "PortugueseBR"
!insertmacro MUI_LANGUAGE "Polish"
!insertmacro MUI_LANGUAGE "German"
!insertmacro MUI_LANGUAGE "Hungarian"
!insertmacro MUI_LANGUAGE "Turkish"
!insertmacro MUI_LANGUAGE "Arabic"
!insertmacro MUI_LANGUAGE "Galician"
!insertmacro MUI_LANGUAGE "Catalan"
!insertmacro MUI_LANGUAGE "Basque"
!insertmacro MUI_RESERVEFILE_LANGDLL
Section
SetShellVarContext All
SetOutPath "$INSTDIR"
${If} ${RunningX64}
File /r TWBlue64\*
${Else}
File /r TWBlue\*
${EndIf}
CreateShortCut "$DESKTOP\TW Blue.lnk" "$INSTDIR\TWBlue.exe" "-i"
!insertmacro MUI_STARTMENU_WRITE_BEGIN startmenu
CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TW Blue.lnk" "$INSTDIR\TWBlue.exe" "-i"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TW Blue on the web.lnk" "http://twblue.es"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
!insertmacro MUI_STARTMENU_WRITE_END
WriteUninstaller "$INSTDIR\Uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayName" "TW Blue"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortez"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.51"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.es"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 51
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1
SectionEnd
Section "Uninstall"
SetShellVarContext All
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue"
RMDir /r /REBOOTOK $INSTDIR
Delete "$DESKTOP\TW Blue.lnk"
!insertmacro MUI_STARTMENU_GETFOLDER startmenu $StartMenuFolder
RMDir /r "$SMPROGRAMS\$StartMenuFolder"
SectionEnd
Function .onInit
${If} ${RunningX64}
StrCpy $instdir "$programfiles64\twblue"
${EndIf}
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd

View File

@@ -15,6 +15,7 @@ reverse_timelines = boolean(default=False)
time_to_check_streams = integer(default=30)
announce_stream_status = boolean(default=True)
ask_at_exit = boolean(default=True)
use_invisible_keyboard_shorcuts = boolean(default=False)
[sound]
volume = float(default=1.0)
@@ -35,11 +36,14 @@ timelines = list(default=list())
tweet_searches = list(default=list())
lists = list(default=list())
favourites_timelines = list(default=list())
trending_topic_buffers = list(default=list())
muted_buffers = list(default=list())
autoread_buffers = list(default=list())
[mysc]
spelling_language = string(default="")
save_followers_in_autocompletion_db = boolean(default=False)
save_friends_in_autocompletion_db = boolean(default=False)
[services]
dropbox_token=string(default="")
@@ -86,3 +90,6 @@ search = string(default="control+win+-")
edit_keystrokes = string(default="control+win+k")
view_user_lists = string(default="control+win+l")
get_more_items = string(default="alt+win+pageup")
reverse_geocode = string(default="control+win+g")
view_reverse_geocode = string(default="control+win+shift+g")
get_trending_topics = string(default="control+win+t")

View File

@@ -1,20 +1,20 @@
# -*- coding: utf-8 -*-
name = 'TW Blue'
name = 'TWBlue'
snapshot = False
if snapshot == False:
version = "0.48"
update_url = 'http://twblue.com.mx/updates/tw_blue.json'
version = "0.51"
update_url = 'http://twblue.es/updates/tw_blue.json'
else:
version = "4"
update_url = 'http://twblue.com.mx/updates/snapshots.json'
version = "7"
update_url = 'http://twblue.es/updates/snapshots.json'
author = u"Manuel Cortéz"
authorEmail = "info@twblue.com.mx"
copyright = u"copyright (C) 2013-2014, Manuel cortéz"
authorEmail = "manuel@manuelcortez.net"
copyright = u"copyright (C) 2013-2015, Manuel cortéz"
description = u"TW Blue is an app designed to use Twitter in a simple and fast way and avoiding, as far as possible, the consumtion of excessive resources of the machine where its running. With this app youll have access to most twitter features."
translators = [u"Bryner Villalobos (English)", u"Mohammed Al Shara (Arabic)", u"Salva Doménech, Juan Carlos Rivilla(Catalan)", u"Manuel cortéz(Spanish)", u"Sukil Etxenike Arizaleta(Basque)", u"Jani Kinnunen(finnish)", u"Javier Currás, José Manuel Delicado, Alba Quinteiro(Galician)", u"Robert Osztolykan(Hungarian)", u"Paweł Masarczyk(Polish)", u"Odenilton Júnior Santos(Portuguese)", u"Alexander Jaszyn(Russian)", u"Burak (Turkish)"]
url = u"http://twblue.com.mx"
#report_bugs_url = "http://twblue.com.mx/errores/api/soap/mantisconnect.php?wsdl"
translators = [u"Bryner Villalobos (English)", u"Mohammed Al Shara (Arabic)", u"Joan Rabat, Juan Carlos Rivilla (Catalan)", u"Manuel cortéz (Spanish)", u"Sukil Etxenike Arizaleta (Basque)", u"Jani Kinnunen (finnish)", u"Rémy Ruiz (French)", u"Alba Quinteiro (Galician)", u"Steffen Schultz (German)", u"Robert Osztolykan (Hungarian)", u"Paweł Masarczyk (Polish)", u"Odenilton Júnior Santos (Portuguese)", u"Alexander Jaszyn (Russian)", u"Burak (Turkish)"]
url = u"http://twblue.es"
report_bugs_url = "http://twblue.es/bugs/api/soap/mantisconnect.php?wsdl"
# Tokens
app_key = '8pDLbyOW3saYnvSZ4uLFg'
app_secret = 'YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY'
app_secret = 'YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY'

View File

@@ -8,7 +8,9 @@ group.add_argument("-p", "--portable", help="Use TW Blue as a portable aplicatio
group.add_argument("-i", "--installed", help="Use TW Blue as an installed application. Config files will be saved on the user data directory", action="store_true")
parser.add_argument("-d", "--data-directory", action="store", dest="directory", help="Specifies the directory where TW Blue saves the data files")
args = parser.parse_args()
if args.installed == True: paths.mode = "installed"
if args.installed == True:
paths.mode = "installed"
elif args.portable == True:
paths.mode = "portable"
if args.directory != None: paths.directory = args.directory

View File

@@ -16,6 +16,7 @@ class soundsTutorial(wx.Dialog):
_(u"A bug has happened"),
_(u"You've added a tweet to your favourites"),
_(u"Someone's favourites have been updated"),
_(u"The tweet has coordinates to determine its location"),
_(u"There are no more tweets to read"),
_(u"A list has a new tweet"),
_(u"You can't add any more characters on the tweet"),
@@ -25,6 +26,7 @@ class soundsTutorial(wx.Dialog):
_(u"You've replied"),
_(u"You've retweeted"),
_(u"A search has been updated"),
_(u"the buffer for trending topics has been updated"),
_(u"There's a new tweet in the main buffer"),
_(u"You've sent a tweet"),
_(u"There's a new tweet in a timeline"),

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
import storage
import output
import wx_menu
class autocompletionUsers(object):
def __init__(self, window):
super(autocompletionUsers, self).__init__()
self.window = window
def show_menu(self):
position = self.window.text.GetInsertionPoint()
text = self.window.text.GetValue()
text = text[:position]
try:
pattern = text.split()[-1]
except IndexError:
output.speak(_(u"You have to start writing"))
return
if pattern.startswith("@") == True:
db = storage.storage()
menu = wx_menu.menu(self.window.text, pattern[1:])
users = db.get_users(pattern[1:])
if len(users) > 0:
menu.append_options(users)
self.window.PopupMenu(menu, self.window.text.GetPosition())
menu.Destroy()
else:
output.speak(_(u"There are not results in your users database"))
else:
output.speak(_(u"Autocompletion only works for users."))

View File

@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
import storage
import wx
import wx_manage
class autocompletionManage(object):
def __init__(self, window):
super(autocompletionManage, self).__init__()
self.window = window
self.dialog = wx_manage.autocompletionManageDialog()
self.database = storage.storage()
self.users = self.database.get_all_users()
self.dialog.put_users(self.users)
self.dialog.add.Bind(wx.EVT_BUTTON, self.add_user)
self.dialog.remove.Bind(wx.EVT_BUTTON, self.remove_user)
self.dialog.ShowModal()
def update_list(self):
item = self.dialog.users.get_selected()
self.dialog.users.clear()
self.users = self.database.get_all_users()
self.dialog.put_users(self.users)
self.dialog.users.select_item(item)
def add_user(self, event=None):
usr = self.dialog.get_user()
if usr == False:
return
try:
data = self.window.twitter.twitter.show_user(screen_name=usr)
except:
self.dialog.show_invalid_user_error()
return
self.database.set_user(data["screen_name"], data["name"], 0)
self.update_list()
def remove_user(self, ev):
ask = 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)
if ask.ShowModal() == wx.ID_YES:
item = self.dialog.users.get_selected()
user = self.users[item]
self.database.remove_user(user[0])
self.update_list()

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
import storage
import wx
import config
import wx_settings
import manage
import output
from mysc.thread_utils import call_threaded
class autocompletionSettings(object):
def __init__(self, window):
super(autocompletionSettings, self).__init__()
self.window = window
self.dialog = wx_settings.autocompletionSettingsDialog()
self.dialog.friends_buffer.SetValue(config.main["mysc"]["save_friends_in_autocompletion_db"])
self.dialog.followers_buffer.SetValue(config.main["mysc"]["save_followers_in_autocompletion_db"])
self.dialog.viewList.Bind(wx.EVT_BUTTON, self.view_list)
if self.dialog.ShowModal() == wx.ID_OK:
call_threaded(self.add_users_to_database)
def add_users_to_database(self):
config.main["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.friends_buffer.GetValue()
config.main["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.friends_buffer.GetValue()
output.speak(_(u"Updating database... You can close this window now. A message will tell you when the process finishes."))
database = storage.storage()
if self.dialog.followers_buffer.GetValue() == True:
buffer = self.window.search_buffer("people", "followers")
for i in buffer.db.settings[buffer.name_buffer]:
database.set_user(i["screen_name"], i["name"], 1)
else:
database.remove_by_buffer(1)
if self.dialog.friends_buffer.GetValue() == True:
buffer = self.window.search_buffer("people", "friends")
for i in buffer.db.settings[buffer.name_buffer]:
database.set_user(i["screen_name"], i["name"], 2)
else:
database.remove_by_buffer(2)
wx_settings.show_success_dialog()
self.dialog.Destroy()
def view_list(self, ev):
q = manage.autocompletionManage(self.window)
def execute_at_startup(window):
database = storage.storage()
if config.main["mysc"]["save_followers_in_autocompletion_db"] == True and config.main["other_buffers"]["show_followers"] == True:
buffer = window.search_buffer("people", "followers")
for i in buffer.db.settings[buffer.name_buffer]:
database.set_user(i["screen_name"], i["name"], 1)
else:
database.remove_by_buffer(1)
if config.main["mysc"]["save_friends_in_autocompletion_db"] == True and config.main["other_buffers"]["show_friends"] == True:
buffer = window.search_buffer("people", "friends")
for i in buffer.db.settings[buffer.name_buffer]:
database.set_user(i["screen_name"], i["name"], 2)
else:
database.remove_by_buffer(2)

View File

@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
import sqlite3, paths
from sessionmanager import manager
class storage(object):
def __init__(self):
self.connection = sqlite3.connect(paths.config_path("%s/autocompletionUsers.dat" % (manager.manager.get_current_session())))
self.cursor = self.connection.cursor()
if self.table_exist("users") == False:
self.create_table()
def table_exist(self, table):
ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table))
answer = ask.fetchone()
if answer == None:
return False
else:
return True
def get_all_users(self):
self.cursor.execute("""select * from users""")
return self.cursor.fetchall()
def get_users(self, term):
self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),))
return self.cursor.fetchall()
def set_user(self, screen_name, user_name, from_a_buffer):
self.cursor.execute("""insert or ignore into users values(?, ?, ?)""", (screen_name, user_name, from_a_buffer))
self.connection.commit()
def remove_user(self, user):
self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,))
self.connection.commit()
return self.cursor.fetchone()
def remove_by_buffer(self, bufferType):
""" Removes all users saved on a buffer. BufferType is 0 for no buffer, 1 for friends and 2 for followers"""
self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,))
self.connection.commit()
return self.cursor.fetchone()
def create_table(self):
self.cursor.execute("""
create table users(
user TEXT UNIQUE,
name TEXT,
from_a_buffer INTEGER
)""")
def __del__(self):
self.cursor.close()
self.connection.close()

View File

@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
import wx
from multiplatform_widgets import widgets
class autocompletionManageDialog(wx.Dialog):
def __init__(self):
super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocomplete users database"))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(panel, -1, _(u"Editing TWBlue users database"))
self.users = widgets.list(panel, _(u"Username"), _(u"Name"), style=wx.LC_REPORT)
sizer.Add(label, 0, wx.ALL, 5)
sizer.Add(self.users.list, 0, wx.ALL, 5)
self.add = wx.Button(panel, -1, _(u"Add user"))
self.remove = wx.Button(panel, -1, _(u"Remove user"))
optionsBox = wx.BoxSizer(wx.HORIZONTAL)
optionsBox.Add(self.add, 0, wx.ALL, 5)
optionsBox.Add(self.remove, 0, wx.ALL, 5)
sizer.Add(optionsBox, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK)
cancel = wx.Button(panel, wx.ID_CANCEL)
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
sizerBtn.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(sizerBtn, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def put_users(self, users):
for i in users:
j = [i[0], i[1]]
self.users.insert_item(False, *j)
def get_user(self):
usr = False
userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database"))
if userDlg.ShowModal() == wx.ID_OK:
usr = userDlg.GetValue()
return usr
def show_invalid_user_error(self):
wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal()

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
import wx
class menu(wx.Menu):
def __init__(self, window, pattern):
super(menu, self).__init__()
self.window = window
self.pattern = pattern
def append_options(self, options):
for i in options:
item = wx.MenuItem(self, wx.NewId(), "%s (@%s)" % (i[1], i[0]))
self.AppendItem(item)
self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item)
def select_text(self, ev, text):
self.window.ChangeValue(self.window.GetValue().replace(self.pattern, text+" "))
self.window.SetInsertionPointEnd()

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
import wx
class autocompletionSettingsDialog(wx.Dialog):
def __init__(self):
super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users settings"))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.followers_buffer = wx.CheckBox(panel, -1, _(u"Add users from followers buffer"))
self.friends_buffer = wx.CheckBox(panel, -1, _(u"Add users from friends buffer"))
sizer.Add(self.followers_buffer, 0, wx.ALL, 5)
sizer.Add(self.friends_buffer, 0, wx.ALL, 5)
self.viewList = wx.Button(panel, -1, _(u"See the users list"))
sizer.Add(self.viewList, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK)
cancel = wx.Button(panel, wx.ID_CANCEL)
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
sizerBtn.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(sizerBtn, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def show_success_dialog():
wx.MessageDialog(None, _(u"TWBlue's database of users has been updated."), _(u"Done"), wx.OK).ShowModal()

View File

@@ -1,105 +0,0 @@
# Copyright (c) 2006, 2007, 2010 Alexander Belchenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Helper for standard gettext.py on Windows.
Module obtains user language code on Windows to use with standard
Python gettext.py library.
The module provides 2 functions: setup_env and get_language.
You may use setup_env before initializing gettext functions.
Or you can use get_language to get the list of language codes suitable
to pass them to gettext.find or gettext.translation function.
Usage example #1:
import gettext, gettext_windows
gettext_windows.setup_env()
gettext.install('myapp')
Usage example #2:
import gettext, gettext_windows
lang = gettext_windows.get_language()
translation = gettext.translation('myapp', languages=lang)
_ = translation.gettext
"""
import locale
import os
import sys
OS_WINDOWS = (sys.platform == 'win32')
def setup_env_windows(system_lang=True):
"""Check environment variables used by gettext
and setup LANG if there is none.
"""
if _get_lang_env_var() is not None:
return
lang = get_language_windows(system_lang)
if lang:
os.environ['LANGUAGE'] = ':'.join(lang)
def get_language_windows(system_lang=True):
"""Get language code based on current Windows settings.
@return: list of languages.
"""
try:
import ctypes
except ImportError:
return [locale.getdefaultlocale()[0]]
# get all locales using windows API
lcid_user = ctypes.windll.kernel32.GetUserDefaultLCID()
lcid_system = ctypes.windll.kernel32.GetSystemDefaultLCID()
if system_lang and lcid_user != lcid_system:
lcids = [lcid_user, lcid_system]
else:
lcids = [lcid_user]
return filter(None, [locale.windows_locale.get(i) for i in lcids]) or None
def setup_env_other(system_lang=True):
pass
def get_language_other(system_lang=True):
lang = _get_lang_env_var()
if lang is not None:
return lang.split(':')
return None
def _get_lang_env_var():
for i in ('LANGUAGE','LC_ALL','LC_MESSAGES','LANG'):
lang = os.environ.get(i)
if lang:
return lang
return None
if OS_WINDOWS:
setup_env = setup_env_windows
get_language = get_language_windows
else:
setup_env = setup_env_other
get_language = get_language_other

View File

@@ -7,4 +7,5 @@ from favourites import *
from lists import *
from people import *
from tweet_searches import *
from user_searches import *
from user_searches import *
from trends import *

View File

@@ -18,6 +18,8 @@
############################################################
import wx
import gui.dialogs
import arrow
import languageHandler
import twitter
import webbrowser
import config
@@ -27,7 +29,7 @@ import logging as original_logger
import output
import platform
import datetime
from twitter import prettydate
import menus
from multiplatform_widgets import widgets
from mysc import event
from mysc.thread_utils import call_threaded
@@ -39,6 +41,8 @@ class basePanel(wx.Panel):
def bind_events(self):
self.Bind(event.MyEVT_OBJECT, self.update)
self.Bind(event.MyEVT_DELETED, self.Remove)
self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.showMenu, self.list.list)
self.Bind(wx.EVT_LIST_KEY_DOWN, self.showMenuByKey, self.list.list)
self.list.list.Bind(wx.EVT_CHAR_HOOK, self.interact)
if self.system == "Windows":
self.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocus)
@@ -147,14 +151,19 @@ class basePanel(wx.Panel):
if config.main["general"]["relative_times"] == True:
# On windows we need only put the new date on the column, but under linux and mac it isn't possible.
if self.system == "Windows":
original_date = datetime.datetime.strptime(tweet["created_at"], "%a %b %d %H:%M:%S +0000 %Y")
date = original_date-datetime.timedelta(seconds=-self.db.settings["utc_offset"])
ts = prettydate(original_date)
# self.db.settings[self.name_buffer][self.list.get_selected()]["created_at"] = tweet["created_at"].replace("+0000 ", "")
original_date = arrow.get(self.db.settings[self.name_buffer][self.list.get_selected()]["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en")
# original_date = datetime.datetime.strptime(self.db.settings[self.name_buffer][self.list.get_selected()]["created_at"], "%a %b %d %H:%M:%S +0000 %Y")
# date = original_date-datetime.timedelta(seconds=-self.db.settings["utc_offset"])
ts = original_date.humanize(locale=languageHandler.getLanguage())
# prettydate(original_date)
self.list.list.SetStringItem(self.list.get_selected(), 2, ts)
else:
self.list.list.SetString(self.list.get_selected(), " ".join(self.compose_function(self.db.settings[self.name_buffer][self.list.get_selected()], self.db)))
if twitter.utils.is_audio(tweet):
sound.player.play("audio.ogg", False)
if twitter.utils.is_geocoded(tweet):
sound.player.play("geo.ogg", False)
def start_streams(self):
if self.name_buffer == "sent":
@@ -181,18 +190,21 @@ class basePanel(wx.Panel):
except TwythonError as e:
output.speak(e.message)
for i in items:
if config.main["general"]["reverse_timelines"] == False:
self.db.settings[self.name_buffer].insert(0, i)
else:
self.db.settings[self.name_buffer].append(i)
if twitter.utils.is_allowed(i) == True:
if config.main["general"]["reverse_timelines"] == False:
self.db.settings[self.name_buffer].insert(0, i)
else:
self.db.settings[self.name_buffer].append(i)
if config.main["general"]["reverse_timelines"] == False:
for i in items:
tweet = self.compose_function(i, self.db)
self.list.insert_item(True, *tweet)
if twitter.utils.is_allowed(i) == True:
tweet = self.compose_function(i, self.db)
self.list.insert_item(True, *tweet)
else:
for i in items:
tweet = self.compose_function(i, self.db)
self.list.insert_item(False, *tweet)
if twitter.utils.is_allowed(i) == True:
tweet = self.compose_function(i, self.db)
self.list.insert_item(False, *tweet)
output.speak(_(u"%s items retrieved") % (len(items)))
def put_items(self, num):
@@ -200,7 +212,7 @@ class basePanel(wx.Panel):
for i in self.db.settings[self.name_buffer]:
tweet = self.compose_function(i, self.db)
self.list.insert_item(False, *tweet)
self.set_list_position()
self.set_list_position()
elif self.list.get_count() > 0:
if config.main["general"]["reverse_timelines"] == False:
for i in self.db.settings[self.name_buffer][:num]:
@@ -278,10 +290,15 @@ class basePanel(wx.Panel):
if self.name_buffer in config.main["other_buffers"]["autoread_buffers"]:
output.speak(" ".join(tweet[:2]))
def get_tweet(self):
""" Gets a tweet or retweet."""
if self.db.settings[self.name_buffer][self.list.get_selected()].has_key("retweeted_status"): tweet = self.db.settings[self.name_buffer][self.list.get_selected()]["retweeted_status"]
else: tweet = self.db.settings[self.name_buffer][self.list.get_selected()]
return tweet
def interact(self, ev):
try:
if self.db.settings[self.name_buffer][self.list.get_selected()].has_key("retweeted_status"): tweet = self.db.settings[self.name_buffer][self.list.get_selected()]["retweeted_status"]
else: tweet = self.db.settings[self.name_buffer][self.list.get_selected()]
tweet = self.get_tweet()
urls = twitter.utils.find_urls_in_text(tweet["text"])
except:
urls = []
@@ -297,14 +314,21 @@ class basePanel(wx.Panel):
ev.Skip()
return
if event == "audio" and len(urls) > 0:
self.streamer(urls[0])
if len(urls) == 1:
self.streamer(urls[0])
elif len(urls) > 1:
urlList = gui.dialogs.urlList.urlList(urls)
if urlList.ShowModal() == wx.ID_OK:
self.streamer(urls[urlList.lista.GetSelection()])
elif event == "url":
if len(urls) == 0: return
elif len(urls) == 1:
output.speak(_(u"Opening URL..."), True)
webbrowser.open(urls[0])
elif len(urls) > 1:
gui.dialogs.urlList.urlList(urls).ShowModal()
urlList = gui.dialogs.urlList.urlList(urls)
if urlList.ShowModal() == wx.ID_OK:
webbrowser.open_new_tab(urls[urlList.lista.GetSelection()])
elif event == "volume_down":
if config.main["sound"]["volume"] > 0.05:
config.main["sound"]["volume"] = config.main["sound"]["volume"]-0.05
@@ -362,3 +386,18 @@ class basePanel(wx.Panel):
self.list.select_item(len(self.db.settings[self.name_buffer])-1)
else:
self.list.select_item(0)
def showMenu(self, ev):
if self.list.get_count() == 0: return
if self.name_buffer == "sent":
self.PopupMenu(menus.sentPanelMenu(self), ev.GetPosition())
else:
self.PopupMenu(menus.basePanelMenu(self), ev.GetPosition())
def showMenuByKey(self, ev):
if self.list.get_count() == 0: return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
if self.name_buffer == "sent":
self.PopupMenu(menus.sentPanelMenu(self), self.list.list.GetPosition())
else:
self.PopupMenu(menus.basePanelMenu(self), self.list.list.GetPosition())

View File

@@ -19,6 +19,7 @@
import wx
import sound
import gui.dialogs
import menus
import logging as original_logger
from base import basePanel
from mysc.thread_utils import call_threaded
@@ -30,6 +31,7 @@ class dmPanel(basePanel):
super(dmPanel, self).__init__(parent, window, name_buffer, function, argumento=argumento, sound=sound)
self.retweetBtn.Disable()
self.responseBtn.Disable()
self.type = "direct_message"
def destroy_status(self, ev):
index = self.list.get_selected()
@@ -45,4 +47,13 @@ class dmPanel(basePanel):
if dlg.ShowModal() == wx.ID_OK:
call_threaded(self.twitter.api_call, call_name="send_direct_message", _sound="dm_sent.ogg", text=dlg.text.GetValue(), screen_name=dlg.cb.GetValue())
if ev != None:
self.list.list.SetFocus()
self.list.list.SetFocus()
def showMenu(self, ev):
if self.list.get_count() == 0: return
self.PopupMenu(menus.dmPanelMenu(self), ev.GetPosition())
def showMenuByKey(self, ev):
if self.list.get_count() == 0: return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.PopupMenu(menus.dmPanelMenu(self), self.list.list.GetPosition())

View File

@@ -21,6 +21,7 @@ import sound
import config
import platform
import gui.dialogs
import menus
import output
import logging as original_logger
from multiplatform_widgets import widgets
@@ -36,6 +37,8 @@ class eventsPanel(wx.Panel):
def bind_events(self):
self.Bind(event.MyEVT_OBJECT, self.update)
self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.showMenu, self.list.list)
self.Bind(wx.EVT_LIST_KEY_DOWN, self.showMenuByKey, self.list.list)
def put_items(self, items):
pass
@@ -131,4 +134,13 @@ class eventsPanel(wx.Panel):
try:
ev.Skip()
except:
pass
pass
def showMenu(self, ev):
if self.list.get_count() == 0: return
self.PopupMenu(menus.eventsPanelMenu(self), ev.GetPosition())
def showMenuByKey(self, ev):
if self.list.get_count() == 0: return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.PopupMenu(menus.eventsPanelMenu(self), self.list.list.GetPosition())

View File

@@ -30,7 +30,7 @@ class favsPanel(basePanel):
self.type = "favourites_timeline"
def start_streams(self):
num = twitter.starting.get_favourites_timeline(self.db, self.twitter, self.name_buffer, param=self.argumento, count=200)
num = twitter.starting.get_favourites_timeline(self.db, self.twitter, self.name_buffer, param=self.argumento, count=config.main["general"]["max_tweets_per_call"])
if self.sound != "" and num > 0:
sound.player.play(self.sound)
if self.list.get_count() > 0: self.put_items(num)

View File

@@ -35,7 +35,7 @@ class listPanel(basePanel):
def start_streams(self):
self.retrieve_ids()
num = twitter.starting.start_list(self.db, self.twitter, self.name_buffer, list_id=self.argumento)
num = twitter.starting.start_list(self.db, self.twitter, self.name_buffer, list_id=self.argumento, count=config.main["general"]["max_tweets_per_call"])
return num
def retrieve_ids(self):

134
src/gui/buffers/menus.py Normal file
View File

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

View File

@@ -20,18 +20,20 @@ import wx
from multiplatform_widgets import widgets
class accountPanel(wx.Panel):
def __init__(self, parent):
def __init__(self, parent, name_buffer):
super(accountPanel, self).__init__(parent=parent)
self.type = "account"
self.name_buffer = name_buffer
sizer = wx.BoxSizer(wx.VERTICAL)
self.list = widgets.list(self, _(u"Announce"))
sizer.Add(self.list.list, 0, wx.ALL, 5)
self.SetSizer(sizer)
def get_more_items(self):
output.speak(_(u"This action is not supported for this buffer"))
class emptyPanel(accountPanel):
def __init__(self, parent):
super(emptyPanel, self).__init__(parent=parent)
super(emptyPanel, self).__init__(parent=parent, name_buffer="")
self.type = "empty"
def get_more_items(self):
output.speak(_(u"This action is not supported for this buffer"))

View File

@@ -21,6 +21,7 @@ import sound
import config
import twitter
import gui.dialogs
import menus
import logging as original_logger
import output
from multiplatform_widgets import widgets
@@ -36,13 +37,15 @@ class peoplePanel(basePanel):
self.Bind(event.MyEVT_OBJECT, self.update)
self.Bind(event.MyEVT_DELETED, self.Remove)
self.list.list.Bind(wx.EVT_CHAR_HOOK, self.interact)
self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.showMenu, self.list.list)
self.Bind(wx.EVT_LIST_KEY_DOWN, self.showMenuByKey, self.list.list)
def create_list(self):
self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800))
def __init__(self, parent, window, name_buffer, function, argumento=None, sound="", timeline=False):
self.type = "people"
super(peoplePanel, self).__init__(parent, window, name_buffer, function, argumento=argumento, sound=sound)
self.type = "people"
self.responseBtn.SetLabel(_(u"Mention"))
self.retweetBtn.Disable()
self.compose_function = twitter.compose.compose_followers_list
@@ -140,3 +143,18 @@ class peoplePanel(basePanel):
def remove_buffer(self):
pos = None
return pos
def get_message(self, dialog=False):
if dialog == False: return " ".join(self.compose_function(self.db.settings[self.name_buffer][self.list.get_selected()], self.db))
else:
list = self.compose_function(self.db.settings[self.name_buffer][self.list.get_selected()], self.db)
return " ".join(list)
def showMenu(self, ev):
if self.list.get_count() == 0: return
self.PopupMenu(menus.peoplePanelMenu(self), ev.GetPosition())
def showMenuByKey(self, ev):
if self.list.get_count() == 0: return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.PopupMenu(menus.peoplePanelMenu(self), self.list.list.GetPosition())

View File

@@ -17,35 +17,155 @@
#
############################################################
import wx
import sound
import config
import twitter
import gui.dialogs
import twitter
import config
import sound
import logging as original_logger
from base import basePanel
import output
import platform
import menus
from multiplatform_widgets import widgets
from mysc.thread_utils import call_threaded
log = original_logger.getLogger("buffers.base")
class trendPanel(basePanel):
def __init__(self, parent, window, name_buffer, *args, **kwargs):
super(searchPanel, self).__init__(parent, window, name_buffer, sound)
self.type = "trend"
self.args = kwargs
class trendsPanel(wx.Panel):
def compose_function(self, trend):
return [trend["name"]]
def start_streams(self):
num = twitter.starting.search(self.db, self.twitter, self.name_buffer, **self.args)
if num > 0: sound.player.play("search_updated.ogg")
self.put_items(num)
return num
def bind_events(self):
self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.showMenu, self.list.list)
self.Bind(wx.EVT_LIST_KEY_DOWN, self.showMenuByKey, self.list.list)
self.list.list.Bind(wx.EVT_CHAR_HOOK, self.interact)
def get_message(self, dialog=False):
return self.compose_function(self.trends[self.list.get_selected()])[0]
def create_list(self):
self.list = widgets.list(self, _(u"Trending topic"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES)
if self.system == "Windows":
self.list.set_windows_size(0, 30)
self.list.set_size()
def __init__(self, parent, window, name_buffer, argumento=None, sound=""):
self.type = "trends"
self.twitter = window.twitter
self.name_buffer = name_buffer
self.argumento = argumento
self.sound = sound
self.parent = window
self.system = platform.system()
wx.Panel.__init__(self, parent)
self.trends = []
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.create_list()
self.btn = wx.Button(self, -1, _(u"Tweet"))
self.btn.Bind(wx.EVT_BUTTON, self.post_status)
self.tweetTrendBtn = wx.Button(self, -1, _(u"Tweet about this trend"))
self.tweetTrendBtn.Bind(wx.EVT_BUTTON, self.onResponse)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add(self.btn, 0, wx.ALL, 5)
btnSizer.Add(self.tweetTrendBtn, 0, wx.ALL, 5)
self.sizer.Add(btnSizer, 0, wx.ALL, 5)
self.sizer.Add(self.list.list, 0, wx.ALL, 5)
self.bind_events()
self.SetSizer(self.sizer)
def remove_buffer(self):
dlg = wx.MessageDialog(self, _(u"Do you really want to delete this search term?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO)
dlg = wx.MessageDialog(self, _(u"Do you really want to delete this buffer?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO)
if dlg.ShowModal() == wx.ID_YES:
names = config.main["other_buffers"]["tweet_searches"]
user = self.name_buffer[:-7]
log.info(u"Deleting %s's search term" % user)
if user in names:
names.remove(user)
self.db.settings.pop(self.name_buffer)
pos = self.db.settings["buffers"].index(self.name_buffer)
self.db.settings["buffers"].remove(self.name_buffer)
return pos
topics = config.main["other_buffers"]["trending_topic_buffers"]
topic = self.name_buffer[:-3]
log.info(u"Deleting %s's trending topics buffer" % topic)
if topic in topics:
topics.remove(topic)
return 0
def start_streams(self):
data = self.twitter.twitter.get_place_trends(id=self.argumento)
if not hasattr(self, "name"):
self.name = data[0]["locations"][0]["name"]
self.trends = data[0]["trends"]
sound.player.play(self.sound)
return len(self.trends)
def get_more_items(self):
output.speak(_(u"This action is not supported for this buffer"))
def put_items(self, num):
selected_item = self.list.get_selected()
self.list.clear()
for i in self.trends:
tweet = self.compose_function(i)
self.list.insert_item(False, *tweet)
self.set_list_position()
self.list.select_item(selected_item)
def post_status(self, ev=None):
text = gui.dialogs.message.tweet(_(u"Write the tweet here"), _(u"Tweet"), "", self)
if text.ShowModal() == wx.ID_OK:
if text.image == None:
call_threaded(self.twitter.api_call, call_name="update_status", _sound="tweet_send.ogg", status=text.text.GetValue())
else:
call_threaded(self.twitter.api_call, call_name="update_status_with_media", _sound="tweet_send.ogg", status=text.text.GetValue(), media=text.file)
if ev != None: self.list.list.SetFocus()
def onRetweet(self, event=None): pass
def onResponse(self, ev):
trend = self.trends[self.list.get_selected()]["name"]
text = gui.dialogs.message.tweet(_(u"Write the tweet here"), _(u"Tweet"), trend+" ", self)
if text.ShowModal() == wx.ID_OK:
if text.image == None:
call_threaded(self.twitter.api_call, call_name="update_status", _sound="tweet_send.ogg", status=text.text.GetValue())
else:
call_threaded(self.twitter.api_call, call_name="update_status_with_media", _sound="tweet_send.ogg", status=text.text.GetValue(), media=text.file)
if ev != None: self.list.list.SetFocus()
def interact(self, ev):
if type(ev) is str: event = ev
else:
if ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up"
elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list"
else:
ev.Skip()
return
if event == "volume_down":
if config.main["sound"]["volume"] > 0.05:
config.main["sound"]["volume"] = config.main["sound"]["volume"]-0.05
sound.player.play("volume_changed.ogg", False)
if hasattr(self.parent, "audioStream"):
self.parent.audioStream.stream.volume = config.main["sound"]["volume"]
elif event == "volume_up":
if config.main["sound"]["volume"] < 0.95:
config.main["sound"]["volume"] = config.main["sound"]["volume"]+0.05
sound.player.play("volume_changed.ogg", False)
if hasattr(self.parent, "audioStream"):
self.parent.audioStream.stream.volume = config.main["sound"]["volume"]
elif event == "clear_list" and self.list.get_count() > 0:
dlg = wx.MessageDialog(self, _(u"Do you really want to empty this buffer? It's items will be removed from the list"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO)
if dlg.ShowModal() == wx.ID_YES:
self.trends = []
self.list.clear()
try:
ev.Skip()
except:
pass
def set_list_position(self):
if config.main["general"]["reverse_timelines"] == False:
self.list.select_item(len(self.trends)-1)
else:
self.list.select_item(0)
def showMenu(self, ev):
if self.list.get_count() == 0: return
self.PopupMenu(menus.trendsPanelMenu(self), ev.GetPosition())
def showMenuByKey(self, ev):
if self.list.get_count() == 0: return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.PopupMenu(menus.trendsPanelMenu(self), self.list.list.GetPosition())

View File

@@ -40,7 +40,7 @@ class searchUsersPanel(peoplePanel):
self.create_list()
self.args = args
self.kwargs = kwargs
self.type = "timeline"
self.type = "user_search"
def start_streams(self):
num = twitter.starting.search_users(self.db, self.twitter, self.name_buffer, **self.kwargs)

View File

@@ -1 +1 @@
import message, urlList, follow, utils, show_user, update_profile, configuration, lists, search
import message, urlList, follow, utils, show_user, update_profile, configuration, lists, search, trending

View File

@@ -29,6 +29,7 @@ import webbrowser
import paths
import platform
from mysc import restart
from extra.autocompletionUsers import settings
log = original_logger.getLogger("configuration")
system = platform.system()
@@ -50,9 +51,13 @@ class general(wx.Panel):
langBox.Add(language, 0, wx.ALL, 5)
langBox.Add(self.language, 0, wx.ALL, 5)
sizer.Add(langBox, 0, wx.ALL, 5)
self.au = wx.Button(self, -1, _(u"Set the autocomplete function"))
self.ask_at_exit = wx.CheckBox(self, -1, _(U"ask before exiting TwBlue?"))
self.ask_at_exit.SetValue(config.main["general"]["ask_at_exit"])
sizer.Add(self.ask_at_exit, 0, wx.ALL, 5)
self.use_invisible_shorcuts = wx.CheckBox(self, -1, _(u"Use invisible interface's keyboard shorcuts on the GUI"))
self.use_invisible_shorcuts.SetValue(config.main["general"]["use_invisible_keyboard_shorcuts"])
sizer.Add(self.use_invisible_shorcuts, 0, wx.ALL, 5)
self.relative_time = wx.CheckBox(self, -1, _(U"Relative times"))
self.relative_time.SetValue(config.main["general"]["relative_times"])
sizer.Add(self.relative_time, 0, wx.ALL, 5)
@@ -84,6 +89,7 @@ class general(wx.Panel):
sizer.Add(self.reverse_timelines, 0, wx.ALL, 5)
self.SetSizer(sizer)
class other_buffers(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
@@ -264,6 +270,7 @@ class configurationDialog(wx.Dialog):
self.general = general(notebook)
notebook.AddPage(self.general, _(u"General"))
self.general.SetFocus()
self.Bind(wx.EVT_BUTTON, self.autocompletion, self.general.au)
self.buffers = other_buffers(notebook)
notebook.AddPage(self.buffers, _(u"Show other buffers"))
self.ignored_clients = ignoredClients(notebook)
@@ -285,6 +292,9 @@ class configurationDialog(wx.Dialog):
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def autocompletion(self, ev):
configuration = settings.autocompletionSettings(self.parent)
def check_followers_change(self):
if self.buffers.followers.GetValue() != self.buffers.followers_value:
if self.buffers.followers.GetValue() == True:
@@ -376,6 +386,13 @@ class configurationDialog(wx.Dialog):
if platform.system() == "Windows":
config.main["general"]["voice_enabled"] = self.general.disable_sapi5.GetValue()
config.main["general"]["ask_at_exit"] = self.general.ask_at_exit.GetValue()
if (self.general.use_invisible_shorcuts.GetValue() == True and config.main["general"]["use_invisible_keyboard_shorcuts"] != True) and self.parent.showing == True:
km = self.parent.create_invisible_keyboard_shorcuts()
self.parent.register_invisible_keyboard_shorcuts(km)
elif (self.general.use_invisible_shorcuts.GetValue() == False and config.main["general"]["use_invisible_keyboard_shorcuts"] != False) and self.parent.showing == True:
km = self.parent.create_invisible_keyboard_shorcuts()
self.parent.unregister_invisible_keyboard_shorcuts(km)
config.main["general"]["use_invisible_keyboard_shorcuts"] = self.general.use_invisible_shorcuts.GetValue()
config.main["general"]["hide_gui"] = self.general.show_gui.GetValue()
config.main["general"]["max_api_calls"] = self.general.apiCalls.GetValue()
config.main["general"]["max_tweets_per_call"] = self.general.itemsPerApiCall.GetValue()

View File

@@ -23,6 +23,7 @@ import twitter
from twitter import utils
from twython import TwythonError
import output
import re
class follow(wx.Dialog):
def __init__(self, parent, default="follow"):
@@ -48,6 +49,7 @@ class follow(wx.Dialog):
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)
actionSizer.Add(label2)
actionSizer.Add(self.follow)
@@ -57,6 +59,7 @@ class follow(wx.Dialog):
actionSizer.Add(self.block)
actionSizer.Add(self.unblock)
actionSizer.Add(self.reportSpam)
actionSizer.Add(self.ignore_client)
sizer = wx.BoxSizer(wx.VERTICAL)
ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
ok.Bind(wx.EVT_BUTTON, self.onok)
@@ -133,6 +136,16 @@ class follow(wx.Dialog):
self.Destroy()
except TwythonError as err:
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
elif self.ignore_client.GetValue() == True:
tweet = self.parent.get_tweet()
if tweet.has_key("sender"):
output.speak(_(u"You can't ignore direct messages"))
return
else:
client = re.sub(r"(?s)<.*?>", "", tweet["source"])
if client not in config.main["twitter"]["ignored_clients"]:
config.main["twitter"]["ignored_clients"].append(client)
self.Destroy()
def setup_default(self, default):
if default == "follow":

View File

@@ -127,7 +127,7 @@ class listViewer(wx.Dialog):
output.speak(_(u"This list is arready opened."))
return
listUI = gui.buffers.lists.listPanel(self.nb, self.parent, list_updated["slug"]+"-list", argumento=utils.find_list(list_updated["slug"], self.db.settings["lists"]))
self.nb.AddPage(listUI, _(u"List for %s") % (list_updated["slug"],))
self.nb.InsertSubPage(self.db.settings["buffers"].index("lists"), listUI, _(u"List for %s") % (list_updated["slug"],))
self.db.settings["buffers"].append(list_updated["slug"]+"-list")
num = listUI.start_streams()
listUI.put_items(num)
@@ -165,6 +165,14 @@ class userListViewer(listViewer):
self.db.settings["lists"].append(list)
except TwythonError as e:
output.speak("error %s: %s" % (e.status_code, e.msg))
def onDelete(self, event=None):
list_id = self.lists[self.lista.get_selected()]["id"]
try:
list = self.twitter.twitter.unsubscribe_from_list(list_id=list_id)
item = utils.find_item(list["id"], self.db.settings["lists"])
self.db.settings["lists"].remove(list)
except TwythonError as e:
output.speak("error %s: %s" % (e.msg))
class createListDialog(wx.Dialog):

View File

@@ -30,6 +30,7 @@ from twython import TwythonError
from extra import translator, AudioUploader
import platform
from extra.AudioUploader import transfer
from extra.autocompletionUsers import completion
if platform.system() != "Darwin":
from extra.AudioUploader import dropbox_transfer
from extra.SpellChecker import gui as spellCheckerGUI
@@ -183,6 +184,8 @@ class tweet(textLimited):
self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Send"), size=wx.DefaultSize)
self.okButton.Bind(wx.EVT_BUTTON, self.onSend)
self.okButton.SetDefault()
autocompletionButton = wx.Button(self.panel, -1, _(u"&Autocomplete users"))
self.Bind(wx.EVT_BUTTON, self.autocompletion, autocompletionButton)
cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize)
cancelButton.Bind(wx.EVT_BUTTON, self.onCancel)
self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL)
@@ -202,8 +205,11 @@ class tweet(textLimited):
self.mainBox.Add(self.ok_cancelSizer)
selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
# autocompletionId = wx.NewId()
# self.Bind(wx.EVT_MENU, self.autocompletion, id=autocompletionId)
self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),
#(wx.ACCEL_ALT, ord('A'), autocompletionId),
])
self.SetAcceleratorTable(self.accel_tbl)
self.panel.SetSizer(self.mainBox)
@@ -215,6 +221,10 @@ class tweet(textLimited):
self.onTimer(wx.EVT_CHAR_HOOK)
self.SetClientSize(self.mainBox.CalcMin())
def autocompletion(self, event=None):
c = completion.autocompletionUsers(self)
c.show_menu()
def onUpload_image(self, ev):
if self.upload_image.GetLabel() == _(u"Discard image"):
self.image = None
@@ -305,7 +315,7 @@ class reply(tweet):
super(reply, self).__init__(message, title, text, parent)
self.in_reply_to = parent.db.settings[parent.name_buffer][parent.list.get_selected()]["id"]
self.text.SetInsertionPoint(len(self.text.GetValue()))
self.mentionAll = wx.Button(self, -1, _(u"Mention to all"), size=wx.DefaultSize)
self.mentionAll = wx.Button(self, -1, _(u"Men&tion all"), size=wx.DefaultSize)
self.mentionAll.Disable()
self.mentionAll.Bind(wx.EVT_BUTTON, self.mentionAllUsers)
self.buttonsBox1.Add(self.mentionAll, 0, wx.ALL, 5)
@@ -332,10 +342,14 @@ class reply(tweet):
class viewTweet(wx.Dialog):
def __init__(self, tweet):
super(viewTweet, self).__init__(None, size=(850,850))
self.SetTitle(_(u"Tweet - %i characters ") % (len(tweet)))
self.SetTitle(_(u"Tweet - %i characters ") % (len(tweet["text"])))
panel = wx.Panel(self)
label = wx.StaticText(panel, -1, _(u"Tweet"))
self.text = wx.TextCtrl(panel, -1, tweet, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180))
if tweet.has_key("retweeted_status"):
text = "rt @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], tweet["retweeted_status"]["text"])
else:
text = tweet["text"]
self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180))
dc = wx.WindowDC(self.text)
dc.SetFont(self.text.GetFont())
(x, y, z) = dc.GetMultiLineTextExtent("0"*140)
@@ -346,6 +360,20 @@ class viewTweet(wx.Dialog):
textBox.Add(self.text, 1, wx.EXPAND, 5)
mainBox = wx.BoxSizer(wx.VERTICAL)
mainBox.Add(textBox, 0, wx.ALL, 5)
rtCountLabel = wx.StaticText(panel, -1, _(u"Retweets: "))
rtCount = wx.TextCtrl(panel, -1, str(tweet["retweet_count"]), size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE)
rtBox = wx.BoxSizer(wx.HORIZONTAL)
rtBox.Add(rtCountLabel, 0, wx.ALL, 5)
rtBox.Add(rtCount, 0, wx.ALL, 5)
favsCountLabel = wx.StaticText(panel, -1, _(u"Favourites: "))
favsCount = wx.TextCtrl(panel, -1, str(tweet["favorite_count"]), size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE)
favsBox = wx.BoxSizer(wx.HORIZONTAL)
favsBox.Add(favsCountLabel, 0, wx.ALL, 5)
favsBox.Add(favsCount, 0, wx.ALL, 5)
infoBox = wx.BoxSizer(wx.HORIZONTAL)
infoBox.Add(rtBox, 0, wx.ALL, 5)
infoBox.Add(favsBox, 0, wx.ALL, 5)
mainBox.Add(infoBox, 0, wx.ALL, 5)
if platform.system() != "Darwin":
spellcheck = wx.Button(panel, -1, _("Spelling correction"), size=wx.DefaultSize)
spellcheck.Bind(wx.EVT_BUTTON, self.onCheck)
@@ -417,3 +445,87 @@ class viewTweet(wx.Dialog):
urlList.unshorten(urls, self).ShowModal()
self.text.SetFocus()
class viewNonTweet(wx.Dialog):
def __init__(self, tweet):
super(viewNonTweet, self).__init__(None, size=(850,850))
self.SetTitle(_(u"View"))
panel = wx.Panel(self)
label = wx.StaticText(panel, -1, _(u"Item"))
self.text = wx.TextCtrl(parent=panel, id=-1, value=tweet, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180))
dc = wx.WindowDC(self.text)
dc.SetFont(self.text.GetFont())
(x, y, z) = dc.GetMultiLineTextExtent("0"*140)
self.text.SetSize((x, y))
self.text.SetFocus()
textBox = wx.BoxSizer(wx.HORIZONTAL)
textBox.Add(label, 0, wx.ALL, 5)
textBox.Add(self.text, 1, wx.EXPAND, 5)
mainBox = wx.BoxSizer(wx.VERTICAL)
mainBox.Add(textBox, 0, wx.ALL, 5)
spellcheck = wx.Button(panel, -1, _("Spelling correction"), size=wx.DefaultSize)
spellcheck.Bind(wx.EVT_BUTTON, self.onCheck)
self.unshortenButton = wx.Button(panel, -1, _(u"Expand URL"), size=wx.DefaultSize)
self.unshortenButton.Bind(wx.EVT_BUTTON, self.onUnshorten)
self.unshortenButton.Disable()
translateButton = wx.Button(panel, -1, _(u"Translate message"), size=wx.DefaultSize)
translateButton.Bind(wx.EVT_BUTTON, self.onTranslate)
cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"Close"), size=wx.DefaultSize)
cancelButton.SetDefault()
buttonsBox = wx.BoxSizer(wx.HORIZONTAL)
buttonsBox.Add(spellcheck, 0, wx.ALL, 5)
buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5)
buttonsBox.Add(translateButton, 0, wx.ALL, 5)
buttonsBox.Add(cancelButton, 0, wx.ALL, 5)
mainBox.Add(buttonsBox, 0, wx.ALL, 5)
selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),
])
self.SetAcceleratorTable(self.accel_tbl)
panel.SetSizer(mainBox)
self.SetClientSize(mainBox.CalcMin())
self.check_urls()
def check_urls(self):
if len(twitter.utils.find_urls_in_text(self.text.GetValue())) > 0:
self.unshortenButton.Enable()
def onCheck(self, ev):
text = self.text.GetValue()
dlg = spellCheckerGUI.spellCheckerDialog(text, "")
if dlg.ShowModal() == wx.ID_OK:
self.text.ChangeValue(dlg.checker.get_text())
dlg.Destroy()
def onTranslate(self, ev):
dlg = translator.gui.translateDialog()
selection = dlg.ShowModal()
if selection != wx.ID_CANCEL:
text_to_translate = self.text.GetValue().encode("utf-8")
source = [x[0] for x in translator.available_languages()][dlg.source_lang.GetSelection()]
dest = [x[0] for x in translator.available_languages()][dlg.dest_lang.GetSelection()]
t = translator.translator.Translator()
t.from_lang = source
t.to_lang = dest
msg = t.translate(text_to_translate)
self.text.ChangeValue(msg)
output.speak(_(u"Translated"))
self.text.SetFocus()
else:
return
dlg.Destroy()
def onSelect(self, ev):
self.text.SelectAll()
def onUnshorten(self, ev):
urls = twitter.utils.find_urls_in_text(self.text.GetValue())
if len(urls) == 0:
output.speak(_(u"There's no URL to be expanded"))
elif len(urls) == 1:
self.text.SetValue(self.text.GetValue().replace(urls[0], url_shortener.unshorten(urls[0])))
output.speak(_(u"URL expanded"))
elif len(urls) > 1:
urlList.unshorten(urls, self).ShowModal()
self.text.SetFocus()

View File

@@ -19,24 +19,34 @@
import wx
class trendingTopicsDialog(wx.Dialog):
def __init__(self):
super(searchDialog, self).__init__(None, -1)
def __init__(self, information):
super(trendingTopicsDialog, self).__init__(None, -1)
self.countries = {}
self.cities = {}
self.information = information
self.split_information()
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetTitle(_(u"Search on Twitter"))
label = wx.StaticText(panel, -1, _(u"Search"))
self.term = wx.TextCtrl(panel, -1,)
dc = wx.WindowDC(self.term)
dc.SetFont(self.term.GetFont())
self.term.SetSize(dc.GetTextExtent("0"*40))
self.SetTitle(_(u"View trending topics"))
label = wx.StaticText(panel, -1, _(u"Trending topics by"))
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"))
self.country = wx.RadioButton(panel, -1, _(u"Country"), style=wx.RB_GROUP)
self.city = wx.RadioButton(panel, -1, _(u"City"))
self.Bind(wx.EVT_RADIOBUTTON, self.get_places, self.country)
self.Bind(wx.EVT_RADIOBUTTON, self.get_places, self.city)
radioSizer = wx.BoxSizer(wx.HORIZONTAL)
radioSizer.Add(self.tweets, 0, wx.ALL, 5)
radioSizer.Add(self.users, 0, wx.ALL, 5)
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)
self.get_places()
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"))
@@ -46,3 +56,25 @@ class trendingTopicsDialog(wx.Dialog):
sizer.Add(btnsizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def split_information(self):
# self.countries["World wide"] = 1
# self.cities["World wide"] = 1
for i in self.information:
if i["placeType"]["name"] == "Country":
self.countries[i["name"]] = i["woeid"]
else:
self.cities[i["name"]] = i["woeid"]
def get_places(self, event=None):
values = []
if self.country.GetValue() == True:
for i in self.information:
if i["placeType"]["name"] == "Country":
values.append(i["name"])
elif self.city.GetValue() == True:
for i in self.information:
if i["placeType"]["name"] != "Country":
values.append(i["name"])
self.location.Set(values)

View File

@@ -46,8 +46,7 @@ class urlList(wx.Dialog):
self.SetClientSize(sizer.CalcMin())
def onGo(self, ev):
webbrowser.open(self.lista.GetStringSelection())
self.Destroy()
self.EndModal(wx.ID_OK)
def populate_list(self):
for i in self.urls:

View File

@@ -32,10 +32,16 @@ import output
import platform
import urllib2
import sysTrayIcon
import switchModule
from wx.lib.pubsub import pub
import languageHandler
from extra.autocompletionUsers import settings as autocompletionUsersSettings
import pygeocoder
from pygeolib import GeocoderError
from sessionmanager import manager
from issueReporter import gui as issueReporterGUI
from mysc import event
from mysc.thread_utils import call_threaded
from mysc.thread_utils import call_threaded, stream_threaded
from twython import TwythonError
from urllib2 import URLError
from mysc.repeating_timer import RepeatingTimer
@@ -46,6 +52,8 @@ from extra import SoundsTutorial
from keystrokeEditor import gui as keystrokeEditorGUI
log = original_logger.getLogger("gui.main")
geocoder = pygeocoder.Geocoder()
function_reconnect_streams_running = False
class mainFrame(wx.Frame):
""" Main class of the Frame. This is the Main Window."""
@@ -56,12 +64,16 @@ class mainFrame(wx.Frame):
# Application menu
app = wx.Menu()
switch_account = app.Append(wx.NewId(), _(u"S&witch account"))
self.Bind(wx.EVT_MENU, self.switch_account, switch_account)
updateProfile = app.Append(wx.NewId(), _(u"&Update profile"))
self.Bind(wx.EVT_MENU, self.update_profile, updateProfile)
show_hide = app.Append(wx.NewId(), _(u"&Hide window"))
self.Bind(wx.EVT_MENU, self.show_hide, show_hide)
search = app.Append(wx.NewId(), _(u"&Search"))
self.Bind(wx.EVT_MENU, self.search, search)
trends = app.Append(wx.NewId(), _(u"View &trending topics"))
self.Bind(wx.EVT_MENU, self.get_trending_topics, trends)
lists = app.Append(wx.NewId(), _(u"&Lists manager"))
self.Bind(wx.EVT_MENU, self.list_manager, lists)
sounds_tutorial = app.Append(wx.NewId(), _(u"Sounds &tutorial"))
@@ -87,6 +99,8 @@ class mainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.unfav, unfav)
view = tweet.Append(wx.NewId(), _(u"&Show tweet"))
self.Bind(wx.EVT_MENU, self.view, view)
view_coordinates = tweet.Append(wx.NewId(), _(u"View &address"))
self.Bind(wx.EVT_MENU, self.reverse_geocode, view_coordinates)
delete = tweet.Append(wx.NewId(), _(u"&Delete"))
self.Bind(wx.EVT_MENU, self.delete, delete)
@@ -208,17 +222,17 @@ class mainFrame(wx.Frame):
log.debug("Getting Twitter's Rest API...")
self.twitter = twitter.twitter.twitter()
super(mainFrame, self).__init__(None, -1, "TW Blue", size=(1600, 1600))
self.Bind(wx.EVT_QUERY_END_SESSION, self.exit)
self.Bind(wx.EVT_END_SESSION, self.exit)
wx.GetApp().Bind(wx.EVT_QUERY_END_SESSION, self.exit)
wx.GetApp().Bind(wx.EVT_END_SESSION, self.exit)
log.debug(u"Creating the system tray icon... ")
sysTray=sysTrayIcon.SysTrayIcon(self)
self.sysTray=sysTrayIcon.SysTrayIcon(self)
panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.SetTitle("TW Blue")
try:
updater.update_manager.check_for_update()
except:
pass
wx.MessageDialog(self, _(u"An error occurred while looking for an update. It may be due to any problem either on our server or on your DNS servers. Please, try again later."), _(u"Error!"), wx.OK|wx.ICON_ERROR).ShowModal()
self.SetMenuBar(self.makeMenus())
self.setup_twitter(panel)
@@ -233,7 +247,7 @@ class mainFrame(wx.Frame):
# Gets the tabs for home, mentions, send and direct messages.
log.debug("Creating buffers...")
self.db.settings["buffers"] = []
account = buffers.accountPanel(self.nb)
account = buffers.accountPanel(self.nb, self.db.settings["user_name"])
self.nb.AddPage(account, self.db.settings["user_name"])
self.db.settings["buffers"].append(self.db.settings["user_name"])
account_index = self.db.settings["buffers"].index(self.db.settings["user_name"])
@@ -310,11 +324,23 @@ class mainFrame(wx.Frame):
self.db.settings["buffers"].append(i+"favs")
self.fav_stream = RepeatingTimer(180, self.get_fav_buffers)
self.fav_stream.start()
for i in config.main["other_buffers"]["trending_topic_buffers"]:
buff = buffers.trendsPanel(self.nb, self, "%s_tt" % (i,), argumento=i, sound="trends_updated.ogg")
timer = RepeatingTimer(300, buff.start_streams)
timer.start()
num = buff.start_streams()
buff.put_items(num)
self.nb.InsertSubPage(self.db.settings["buffers"].index(self.db.settings["user_name"]), buff, _(u"Trending topics for %s") % (buff.name,))
self.sizer.Add(self.nb, 0, wx.ALL, 5)
if config.main["general"]["use_invisible_keyboard_shorcuts"] == True:
km = self.create_invisible_keyboard_shorcuts()
self.register_invisible_keyboard_shorcuts(km)
panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin())
self.Bind(event.MyEVT_STARTED, self.onInit)
self.Bind(event.EVT_RESULT, self.onMemberAdded)
pub.subscribe(self.listen_streamerror, "streamError")
pub.subscribe(self.listen_for_friends, "friendsReceived")
call_threaded(self.init, run_streams=True)
def init(self, run_streams=False):
@@ -325,7 +351,7 @@ class mainFrame(wx.Frame):
if i == self.nb.GetPageCount() and deleted > 0:
i = i-1
deleted = deleted-1
log.debug("Starting stream for %s..." % self.nb.GetPage(i).name_buffer)
# log.debug(u"Starting stream for %s..." % self.nb.GetPage(i).name_buffer)
info_event = event.infoEvent(event.EVT_STARTED, 1)
try:
if self.nb.GetPage(i).type == "search":
@@ -347,6 +373,7 @@ class mainFrame(wx.Frame):
self.check_streams.start()
# If all it's done, then play a nice sound saying that all it's OK.
sound.player.play("ready.ogg")
autocompletionUsersSettings.execute_at_startup(window=self)
def remove_list(self, id):
for i in range(0, self.nb.GetPageCount()):
@@ -369,21 +396,21 @@ class mainFrame(wx.Frame):
def setup_twitter(self, panel):
""" Setting up the connection for twitter, or authenticate if the config file has valid credentials."""
try:
self.twitter.login(self.user_key, self.user_secret)
self.logging_in_twblue(panel)
log.info("Authorized in Twitter.")
del self.user_key; del self.user_secret
except:
dlg1 = wx.MessageDialog(panel, _(u"Connection error. Try again later."), _(u"Error!"), wx.ICON_ERROR)
dlg1.ShowModal()
self.Close(True)
# try:
self.twitter.login(self.user_key, self.user_secret)
self.logging_in_twblue(panel)
log.info("Authorized in Twitter.")
del self.user_key; del self.user_secret
# except:
# dlg1 = wx.MessageDialog(panel, _(u"Connection error. Try again later."), _(u"Error!"), wx.ICON_ERROR)
# dlg1.ShowModal()
# self.Close(True)
def get_home(self):
""" Gets the home stream, that manages home timeline, mentions, direct messages and sent."""
try:
self.stream = twitter.buffers.stream.streamer(application.app_key, application.app_secret, config.main["twitter"]["user_key"], config.main["twitter"]["user_secret"], parent=self)
call_threaded(self.stream.user)
stream_threaded(self.stream.user)
except:
self.stream.disconnect()
@@ -406,29 +433,36 @@ class mainFrame(wx.Frame):
ids+= str(z)+", "
if ids != "":
# try:
call_threaded(self.stream2.statuses.filter, follow=ids)
stream_threaded(self.stream2.statuses.filter, follow=ids)
# except:
# pass
# except:
# self.stream2.disconnect()
def check_stream_up(self):
try:
urllib2.urlopen("http://74.125.228.231", timeout=5)
except urllib2.URLError:
if self.stream.connected == True: self.stream.disconnect()
if hasattr(self, "stream2") and self.stream2.connected: self.stream2.disconnect()
if config.main["general"]["announce_stream_status"] == True: output.speak(_(u"Streams disconnected. TW Blue will try to reconnect in a minute."))
global function_reconnect_streams_running
if function_reconnect_streams_running == True: return
if not hasattr(self, "stream") and not hasattr(self, "stream2"):
function_reconnect_streams_running = True
self.init(run_streams=True)
return
if self.stream.connected == False:
del self.stream
if config.main["general"]["announce_stream_status"] == True: output.speak(_(u"Reconnecting streams..."))
call_threaded(self.init)
self.get_home()
if hasattr(self, "stream2") and self.stream2.connected == False:
log.debug("Trying reconnects the timelines stream...")
del self.stream2
self.get_tls()
# try:
# urllib2.urlopen("http://74.125.228.231", timeout=5)
# except urllib2.URLError:
# if self.stream.connected == True: self.stream.disconnect()
# if hasattr(self, "stream2") and self.stream2.connected: self.stream2.disconnect()
# if config.main["general"]["announce_stream_status"] == True: output.speak(_(u"Streams disconnected. TW Blue will try to reconnect in a minute."))
# return
# if self.stream.connected == False:
# del self.stream
# if config.main["general"]["announce_stream_status"] == True: output.speak(_(u"Reconnecting streams..."))
# call_threaded(self.init)
# self.get_home()
# if hasattr(self, "stream2") and self.stream2.connected == False:
# log.debug("Trying reconnects the timelines stream...")
# del self.stream2
# self.get_tls()
function_reconnect_streams_running = False
### Events
@@ -501,7 +535,7 @@ class mainFrame(wx.Frame):
dlg = dialogs.lists.removeUserListDialog(self)
if dlg.ShowModal() == wx.ID_OK:
try:
list = self.twitter.twitter.delete_list_member(list_id=self.db.settings["lists"][dlg.get_selected()]["id"], screen_name=user)
list = self.twitter.twitter.delete_list_member(list_id=self.db.settings["lists"][dlg.lista.get_selected()]["id"], screen_name=user)
older_list = twitter.utils.find_item(self.db.settings["lists"][dlg.get_selected()]["id"], self.db.settings["lists"])
if list["mode"] == "private":
self.db.settings["lists"].pop(older_list)
@@ -546,8 +580,7 @@ class mainFrame(wx.Frame):
webbrowser.open("http://twblue.com.mx")
def onReportBug(self, ev):
webbrowser.open("https://github.com/manuelcortez/TWBlue/issues")
# issueReporterGUI.reportBug(self.db.settings["user_name"]).ShowModal()
issueReporterGUI.reportBug(self.db.settings["user_name"]).ShowModal()
def onCheckForUpdates(self, ev):
updater.update_manager.check_for_update(msg=True)
@@ -574,7 +607,7 @@ class mainFrame(wx.Frame):
output.speak(self.nb.GetPageText(self.nb.GetSelection())+",", True)
def skip_blank_pages(self, forward=True):
if self.nb.GetCurrentPage().type == "account" or self.nb.GetCurrentPage().type == "empty" and (self.showing == False or platform.system() == "Darwin"):
if self.nb.GetCurrentPage().type == "account" or self.nb.GetCurrentPage().type == "empty":
self.nb.AdvanceSelection(forward)
def close(self, ev=None):
@@ -590,6 +623,8 @@ class mainFrame(wx.Frame):
def exit(self, event=None):
config.main.write()
log.debug("Exiting...")
self.sysTray.RemoveIcon()
self.sysTray.Destroy()
try:
self.check_streams.cancel()
except AttributeError:
@@ -661,8 +696,18 @@ class mainFrame(wx.Frame):
self.nb.GetCurrentPage().onRetweet(ev)
def view(self, ev=None):
tweet = self.nb.GetCurrentPage().get_message(dialog=True)
dialogs.message.viewTweet(tweet).ShowModal()
tp = self.nb.GetCurrentPage().type
if tp == "buffer" or tp == "timeline" or tp == "favourites_timeline" or tp == "list" or tp == "search":
try:
id = self.db.settings[self.nb.GetCurrentPage().name_buffer][self.nb.GetCurrentPage().list.get_selected()]["id"]
tweet = self.twitter.twitter.show_status(id=id)
dialogs.message.viewTweet(tweet).ShowModal()
except TwythonError as e:
non_tweet = self.nb.GetCurrentPage().get_message(dialog=True)
dialogs.message.viewNonTweet(non_tweet).ShowModal()
else:
non_tweet = self.nb.GetCurrentPage().get_message(dialog=True)
dialogs.message.viewNonTweet(non_tweet).ShowModal()
def fav(self, ev=None):
if self.nb.GetCurrentPage().name_buffer != "direct_messages" and self.nb.GetCurrentPage().name_buffer != "followers" and self.nb.GetCurrentPage().name_buffer != "friends":
@@ -778,6 +823,8 @@ class mainFrame(wx.Frame):
except:
msg = _(u"%s. Empty") % (self.nb.GetPageText(self.nb.GetSelection()))
output.speak(msg, 1)
if self.showing == True:
self.nb.GetCurrentPage().list.list.SetFocus()
def right(self, event=None):
num = self.nb.GetSelection()
@@ -791,21 +838,37 @@ class mainFrame(wx.Frame):
except:
msg = _(u"%s. Empty") % (self.nb.GetPageText(self.nb.GetSelection()))
output.speak(msg, 1)
if self.showing == True:
self.nb.GetCurrentPage().list.list.SetFocus()
def show_hide(self, ev=None):
# if platform.system() == "Linux" or platform.system() == "Darwin": return
def create_invisible_keyboard_shorcuts(self):
keymap = {}
for i in config.main["keymap"]:
if hasattr(self, i):
keymap[config.main["keymap"][i]] = getattr(self, i)
return keymap
def register_invisible_keyboard_shorcuts(self, keymap):
self.keyboard_handler = WXKeyboardHandler(self)
self.keyboard_handler.register_keys(keymap)
def unregister_invisible_keyboard_shorcuts(self, keymap):
try:
self.keyboard_handler.unregister_keys(keymap)
del self.keyboard_handler
except AttributeError:
pass
def show_hide(self, ev=None):
km = self.create_invisible_keyboard_shorcuts()
if self.showing == True:
self.keyboard_handler = WXKeyboardHandler(self)
self.keyboard_handler.register_keys(keymap)
if config.main["general"]["use_invisible_keyboard_shorcuts"] == False:
self.register_invisible_keyboard_shorcuts(km)
self.Hide()
self.showing = False
else:
self.keyboard_handler.unregister_keys(keymap)
del self.keyboard_handler
if config.main["general"]["use_invisible_keyboard_shorcuts"] == False:
self.unregister_invisible_keyboard_shorcuts(km)
self.Show()
self.showing = True
@@ -959,6 +1022,72 @@ class mainFrame(wx.Frame):
return page
return page
def switch_account(self, ev):
switchModule.switcher(self)
def reverse_geocode(self, event=None):
try:
tweet = self.nb.GetCurrentPage().get_tweet()
if tweet["coordinates"] != None:
x = tweet["coordinates"]["coordinates"][0]
y = tweet["coordinates"]["coordinates"][1]
address = geocoder.reverse_geocode(y, x)
if event == None: output.speak(address[0].__str__().decode("utf-8"))
else: wx.MessageDialog(self, address[0].__str__().decode("utf-8"), _(u"Address"), wx.OK).ShowModal()
else:
output.speak(_(u"There are no coordinates in this tweet"))
except GeocoderError:
output.speak(_(u"There are no results for the coordinates in this tweet"))
except ValueError:
output.speak(_(u"Error decoding coordinates. Try again later."))
except KeyError:
pass
def view_reverse_geocode(self, event=None):
try:
tweet = self.nb.GetCurrentPage().get_tweet()
if tweet["coordinates"] != None:
x = tweet["coordinates"]["coordinates"][0]
y = tweet["coordinates"]["coordinates"][1]
address = geocoder.reverse_geocode(y, x)
dialogs.message.viewNonTweet(address[0].__str__().decode("utf-8")).ShowModal()
else:
output.speak(_(u"There are no coordinates in this tweet"))
except GeocoderError:
output.speak(_(u"There are no results for the coordinates in this tweet"))
except ValueError:
output.speak(_(u"Error decoding coordinates. Try again later."))
except KeyError:
pass
def get_trending_topics(self, event=None):
info = self.twitter.twitter.get_available_trends()
trendingDialog = dialogs.trending.trendingTopicsDialog(info)
if trendingDialog.ShowModal() == wx.ID_OK:
if trendingDialog.country.GetValue() == True:
woeid = trendingDialog.countries[trendingDialog.location.GetStringSelection()]
elif trendingDialog.city.GetValue() == True:
woeid = trendingDialog.cities[trendingDialog.location.GetStringSelection()]
buff = buffers.trendsPanel(self.nb, self, "%s_tt" % (woeid,), argumento=woeid, sound="trends_updated.ogg")
self.nb.InsertSubPage(self.db.settings["buffers"].index(self.db.settings["user_name"]), buff, _(u"Trending topics for %s") % (trendingDialog.location.GetStringSelection(),))
timer = RepeatingTimer(300, buff.start_streams)
timer.start()
num = buff.start_streams()
config.main["other_buffers"]["trending_topic_buffers"].append(woeid)
buff.put_items(num)
def listen_streamerror(self):
log.error("There is a connection error")
if hasattr(self, "stream"):
self.stream.disconnect()
del self.stream
if hasattr(self, "stream2"):
self.stream2.disconnect()
del self.stream2
def listen_for_friends(self):
self.stream2.set_friends(self.stream.friends)
### Close App
def Destroy(self):
self.sysTray.Destroy()

23
src/gui/switchModule.py Normal file
View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
import wx
import gui
import config
from sessionmanager import gui as sessionManagerUI
class switcher(object):
def __init__(self, window):
self.hold_window = window
self.hold_window.Hide()
sessionManagerWindow = sessionManagerUI.sessionManagerWindow()
if sessionManagerWindow.ShowModal() == wx.ID_OK:
self.hold_window.Destroy()
self.window = gui.main.mainFrame()
self.window.Show()
self.window.showing = True
if config.main != None and config.main["general"]["hide_gui"] == True:
self.window.show_hide()
self.window.Hide()
wx.GetApp().SetTopWindow(self.window)
else:
self.hold_window.Show()

View File

@@ -55,7 +55,7 @@ class SysTrayIcon(wx.TaskBarIcon):
if (self.frame.showing):
self.frame.SetFocus()
else:
self.frame.onShow_hide()
self.frame.show_hide()
def Destroy(self):
self.menu.Destroy()

View File

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
############################################################
# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo <manuel@manuelcortez.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
############################################################
categories = ["General", "documentation", "translation"]
reproducibilities = ["always", "sometimes", "random", "have not tried", "unable to duplicate"]
severities = ["block", "crash", "major", "minor", "tweak", "text", "trivial", "feature"]

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
############################################################
# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo <manuel@manuelcortez.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
############################################################
import paths
import os
def get_logs_files():
files = {}
for i in os.listdir(paths.logs_path()):
if i == "debug.log": continue
f = open(paths.logs_path(i), "r")
files[i] = f.readlines()
f.close()
try: os.remove(paths.logs_path("tracebacks.log"))
except: pass
return files

124
src/issueReporter/gui.py Normal file
View File

@@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
############################################################
# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo <manuel@manuelcortez.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
############################################################
import wx
import application
from suds.client import Client
import constants
class reportBug(wx.Dialog):
def __init__(self, user_name):
self.user = "reporter1"
self.user_name = user_name
self.password = "contrasena"
self.url = application.report_bugs_url
self.categories = [_(u"General"), _(u"Documentation"), _(u"Translation")]
self.reproducibilities = [_(u"always"), _(u"sometimes"), _(u"random"), _(u"have not tried"), _(u"unable to duplicate")]
self.severities = [_(u"block"), _(u"crash"), _(u"major"), _(u"minor"), _(u"tweak"), _(u"text"), _(u"trivial"), _(u"feature")]
wx.Dialog.__init__(self, None, -1)
self.SetTitle(_(u"Report an error"))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
categoryLabel = wx.StaticText(panel, -1, _(u"Select a category"), size=wx.DefaultSize)
self.category = wx.ComboBox(panel, -1, choices=self.categories, style=wx.CB_READONLY)
self.category.SetSize(self.category.GetBestSize())
self.category.SetSelection(0)
categoryB = wx.BoxSizer(wx.HORIZONTAL)
categoryB.Add(categoryLabel, 0, wx.ALL, 5)
categoryB.Add(self.category, 0, wx.ALL, 5)
self.category.SetFocus()
sizer.Add(categoryB, 0, wx.ALL, 5)
summaryLabel = wx.StaticText(panel, -1, _(u"Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize)
self.summary = wx.TextCtrl(panel, -1)
dc = wx.WindowDC(self.summary)
dc.SetFont(self.summary.GetFont())
self.summary.SetSize(dc.GetTextExtent("a"*80))
# self.summary.SetFocus()
summaryB = wx.BoxSizer(wx.HORIZONTAL)
summaryB.Add(summaryLabel, 0, wx.ALL, 5)
summaryB.Add(self.summary, 0, wx.ALL, 5)
sizer.Add(summaryB, 0, wx.ALL, 5)
descriptionLabel = wx.StaticText(panel, -1, _(u"Here, you can describe the bug in detail"), size=wx.DefaultSize)
self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
dc = wx.WindowDC(self.description)
dc.SetFont(self.description.GetFont())
(x, y, z) = dc.GetMultiLineTextExtent("0"*2000)
self.description.SetSize((x, y))
descBox = wx.BoxSizer(wx.HORIZONTAL)
descBox.Add(descriptionLabel, 0, wx.ALL, 5)
descBox.Add(self.description, 0, wx.ALL, 5)
sizer.Add(descBox, 0, wx.ALL, 5)
reproducibilityLabel = wx.StaticText(panel, -1, _(u"how often does this bug happen?"), size=wx.DefaultSize)
self.reproducibility = wx.ComboBox(panel, -1, choices=self.reproducibilities, style=wx.CB_READONLY)
self.reproducibility.SetSelection(3)
self.reproducibility.SetSize(self.reproducibility.GetBestSize())
reprB = wx.BoxSizer(wx.HORIZONTAL)
reprB.Add(reproducibilityLabel, 0, wx.ALL, 5)
reprB.Add(self.reproducibility, 0, wx.ALL, 5)
sizer.Add(reprB, 0, wx.ALL, 5)
severityLabel = wx.StaticText(panel, -1, _(u"Select the importance that you think this bug has"))
self.severity = wx.ComboBox(panel, -1, choices=self.severities, style=wx.CB_READONLY)
self.severity.SetSize(self.severity.GetBestSize())
self.severity.SetSelection(3)
severityB = wx.BoxSizer(wx.HORIZONTAL)
severityB.Add(severityLabel, 0, wx.ALL, 5)
severityB.Add(self.severity, 0, wx.ALL, 5)
sizer.Add(severityB, 0, wx.ALL, 5)
self.agree = wx.CheckBox(panel, -1, _(u"I know that the TW Blue bug system will get my Twitter username to contact me and fix the bug quickly"))
self.agree.SetValue(False)
sizer.Add(self.agree, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK, _(u"Send report"))
ok.Bind(wx.EVT_BUTTON, self.onSend)
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel"))
btnBox = wx.BoxSizer(wx.HORIZONTAL)
btnBox.Add(ok, 0, wx.ALL, 5)
btnBox.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnBox, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def onSend(self, ev):
if self.summary.GetValue() == "" or self.description.GetValue() == "":
wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal()
return
if self.agree.GetValue() == False:
wx.MessageDialog(self, _(u"You need to mark the checkbox to provide us your twitter username to contact to you if is necessary."), _(u"Error"), wx.ICON_ERROR).ShowModal()
return
# try:
client = Client(self.url)
issue = client.factory.create('IssueData')
issue.project.name = "TWBlue"
issue.project.id = 0
issue.summary = self.summary.GetValue(),
issue.description = "Reported by @%s\n\n" % (self.user_name) + self.description.GetValue()
issue.category = constants.categories[self.category.GetSelection()]
issue.reproducibility.name = constants.reproducibilities[self.reproducibility.GetSelection()]
issue.severity.name = constants.severities[self.severity.GetSelection()]
issue.priority.name = "normal"
issue.view_state.name = "public"
issue.resolution.name = "open"
issue.projection.name = "none"
issue.eta.name = "eta"
issue.status.name = "new"
id = client.service.mc_issue_add(self.user, self.password, issue)
wx.MessageDialog(self, _(u"Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You've reported the bug number %i") % (id), _(u"reported"), wx.OK).ShowModal()
self.EndModal(wx.ID_OK)
# except:
# wx.MessageDialog(self, _(u"Something unexpected occurred while trying to report the bug. Please, try again later"), _(u"Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal()
# self.EndModal(wx.ID_CANCEL)

View File

@@ -42,4 +42,7 @@ actions = {
"edit_keystrokes": _(u"Shows the keystroke editor"),
"view_user_lists": _(u"Show lists for a specified user"),
"get_more_items": _(u"loads previous items to any buffer"),
"reverse_geocode": _(u"Get location of any tweet"),
"view_reverse_geocode": _(u"Displays the tweet's location in a dialog"),
"get_trending_topics": _(u"Creates a buffer for displaying trends for a desired place"),
}

View File

@@ -126,23 +126,27 @@ def setLanguage(lang):
elif system == "Darwin":
import Foundation
localeName = Foundation.NSLocale.currentLocale().identifier()
# 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
# else:
# localeName=locale.getdefaultlocale()[0]
# trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName])
# curLang=localeName
else:
trans=gettext.translation("twblue", localedir=paths.locale_path(), languages=[lang])
curLang=lang
localeChanged=False
#Try setting Python's locale to lang
try:
# try:
if system == "Windows":
locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang))
localeChanged=True
else:
locale.setlocale(locale.LC_ALL, lang)
localeChanged=True
except:
pass
# except:
# pass
if not localeChanged and '_' in lang:
#Python couldn'tsupport the language_country locale, just try language.
try:
@@ -158,7 +162,7 @@ def setLanguage(lang):
curLang="en"
trans.install(unicode=True)
# Install our pgettext function.
__builtin__.__dict__["pgettext"] = makePgettext(trans)
# __builtin__.__dict__["pgettext"] = makePgettext(trans)
def getLanguage():
return curLang
@@ -178,3 +182,21 @@ def normalizeLanguage(lang):
ld[1]=ld[1].upper()
return "_".join(ld)
def langToWindowsLocale(lang):
languages = {"en": "eng",
"ar": "ara",
"ca": "cat",
"de": "deu",
"es": "esp",
"fi": "fin",
"fr": "fre_FRA",
"gl": "glc",
"eu": "euq",
"hu": "hun",
"it": "ita",
"pl": "plk",
"pt": "ptb",
"ru": "rus",
"tr": "trk"
}
return languages[lang]

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ import sys
APP_LOG_FILE = 'debug.log'
ERROR_LOG_FILE = "error.log"
MESSAGE_FORMAT = "%(asctime)s %(name)s %(levelname)s: %(message)s"
DATE_FORMAT = "%a %b %d, %Y %H:%M:%S"
MESSAGE_FORMAT = u"%(asctime)s %(name)s %(levelname)s: %(message)s"
DATE_FORMAT = u"%b %d, %Y %H:%M:%S"
formatter = logging.Formatter(MESSAGE_FORMAT, datefmt=DATE_FORMAT)

View File

@@ -17,4 +17,16 @@
#
############################################################
import requests
import re
api_key = "d757b8e7f9221d8b95880a02bab524b7"
def get_tweet(uri):
global api_key
data = requests.get("http://api.twishort.com/1.1/get.json", params={"uri": uri, "api_key": api_key})
return data.json()["text"]
def get_uri(url):
url_ = re.search("twishort.com/", url)
return url[url_.end():]

View File

@@ -19,63 +19,80 @@ A twitter accessible, easy of use and cross platform application."""
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
############################################################
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 wx
ssmg = None
import gui
import wxLangs
import paths
import config
import commandline
import platform
if platform.system() == "Windows":
from logger import logger as logging
if platform.system() == "Darwin":
import osx_prepare
osx_prepare.setup()
from logger import logger as logging
from sessionmanager import manager
from sessionmanager import gui as smGUI
manager.setup()
import sys
import config
import output
import sound
import languageHandler
#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
#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')
class app(wx.App):
def __init__(self, *args, **kwargs):
super(app, self).__init__(*args, **kwargs)
if platform.system() != "Darwin":
self.start()
else:
self.mac()
def mac(self):
self.hold_frame = wx.Frame(title="None", parent=None)
self.hold_frame.Show()
wx.CallLater(10, self.start)
def start(self):
ssmg = smGUI.sessionManagerWindow()
if ssmg.ShowModal() == wx.ID_OK:
frame = gui.main.mainFrame()
frame.Show()
frame.showing = True
if config.main != None and config.main["general"]["hide_gui"] == True and platform.system() == "Windows":
frame.show_hide()
frame.Hide()
self.SetTopWindow(frame)
if hasattr(self, "frame"): self.hold_frame.Hide()
# If the user press on cancel.
else:
self.Exit()
ap = app()
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)
app = wx.App()
#app = wx.App(redirect=True, useBestVisual=True, filename=paths.logs_path('tracebacks.log'))
configured = False
configs = []
for i in os.listdir(paths.config_path()):
if os.path.isdir(paths.config_path(i)): configs.append(i)
if len(configs) == 1:
manager.manager.set_current_session(configs[0])
config.MAINFILE = "%s/session.conf" % (manager.manager.get_current_session())
config.setup()
lang=config.main['general']['language']
languageHandler.setLanguage(lang)
sound.setup()
output.setup()
configured = True
else:
ssmg = smGUI.sessionManagerWindow()
if configured == True or ssmg.ShowModal() == wx.ID_OK:
frame = gui.main.mainFrame()
frame.Show()
frame.showing = True
if config.main != None and config.main["general"]["hide_gui"] == True and platform.system() == "Windows":
frame.show_hide()
frame.Hide()
app.SetTopWindow(frame)
else:
app.Exit()
### I should uncomment this
#if platform.system() != "Windows":
# local = wx.Locale(wx.LANGUAGE_DEFAULT)
# local.AddCatalogLookupPathPrefix(paths.locale_path())
# local.AddCatalog("twblue")
if languageHandler.getLanguage() != "en":
local = wx.Locale(wxLangs.getLanguage())
local.AddCatalogLookupPathPrefix(paths.locale_path())
local.AddCatalog("twblue")
#languageHandler.setLanguage(lang)
#ap = app(redirect=True, useBestVisual=True, filename=paths.logs_path('tracebacks.log'))
#wx.CallLater(10, start)
ap.MainLoop()
app.MainLoop()

View File

@@ -1,7 +1,12 @@
import gettext_windows, os
import os
import languageHandler
def get(rootFolder):
defaultLocale = gettext_windows.get_language()[0][:2]
# defaultLocale = gettext_windows.get_language()[0][:2]
defaultLocale = languageHandler.curLang
if len(defaultLocale) > 2:
defaultLocale = defaultLocale[:2]
print defaultLocale
if os.path.exists(rootFolder+"/"+defaultLocale):
return defaultLocale
else:

View File

@@ -3,6 +3,7 @@ import threading
import wx
from twython import TwythonRateLimitError
import time
from wx.lib.pubsub import pub
def call_threaded(func, *args, **kwargs):
#Call the given function in a daemonized thread and return the thread.
@@ -19,3 +20,14 @@ def call_threaded(func, *args, **kwargs):
thread.daemon = True
thread.start()
return thread
def stream_threaded(func, *args, **kwargs):
def new_func(*a, **k):
try:
func(*a, **k)
except:
pub.sendMessage("streamError")
thread = threading.Thread(target=new_func, args=args, kwargs=kwargs)
thread.daemon = True
thread.start()
return thread

Some files were not shown because too many files have changed in this diff Show More