pax_global_header00006660000000000000000000000064135113700140014505gustar00rootroot0000000000000052 comment=6fd4b1b90b191c00a763db96b6bb76544bd9e40b pytrainer-2.0.0/000077500000000000000000000000001351137001400135215ustar00rootroot00000000000000pytrainer-2.0.0/.gitignore000066400000000000000000000001031351137001400155030ustar00rootroot00000000000000*.pyc /messages.pot build *~ __pycache__ .eggs/ pytrainer.egg-info pytrainer-2.0.0/.travis.yml000066400000000000000000000020071351137001400156310ustar00rootroot00000000000000dist: xenial language: generic addons: apt: packages: - python-gi - gir1.2-gtk-3.0 - python-lxml - python-matplotlib - python-tornado - python-cairo - python-mock - python3-setuptools - python3-gi - python3-lxml - python3-cairo - python3-gi-cairo - python3-matplotlib - python3-mock services: - mysql env: - PYTHON_VERSION=2.7 PYTRAINER_ALCHEMYURL="sqlite://" - PYTHON_VERSION=3.5 PYTRAINER_ALCHEMYURL="sqlite://" - PYTHON_VERSION=2.7 PYTRAINER_ALCHEMYURL="mysql://pytrainer@localhost/pytrainer" - PYTHON_VERSION=3.5 PYTRAINER_ALCHEMYURL="mysql://pytrainer@localhost/pytrainer" before_install: - mysql -e "CREATE USER 'pytrainer'@'localhost';" - mysql -e "CREATE DATABASE pytrainer;" - mysql -e "GRANT ALL PRIVILEGES ON pytrainer . * TO 'pytrainer'@'localhost';" script: "TZ=Europe/Kaliningrad xvfb-run python$PYTHON_VERSION -Wall setup.py test" notifications: irc: channels: "ircs://chat.freenode.net:7000/#pytrainer" pytrainer-2.0.0/COPYING000066400000000000000000000431021351137001400145540ustar00rootroot00000000000000 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 Library 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. Copyright (C) 19yy 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) 19yy 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. , 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 Library General Public License instead of this License. pytrainer-2.0.0/INSTALL000066400000000000000000000041221351137001400145510ustar00rootroot00000000000000pytrainer basic installation =========================== These are generic installation instructions to use with *.tar.gz files 1.- Dependency Overview Here you are dependencies for pytrainer. Of course you must have a working environment with proper shell configuration and typical GNU tools to uncompress (gunzip) and untar (tar) files. 1.1.- Packages python >= 2.5 (python >= 3.0 not checked on 2011/11!) distutils >= 2.5 (python-devel, to run installation from tarball) dateutil >= 1.5 (python-dateutil) GTK+ >= 2.6.0 PyGTK >= 2.6.0 libglade >= 2.6.4 (libglade, pygtk2-libglade) webkit2gtk-4.0 >= 2.0 requests certify matplotlib >= 0.99.x (python-matplotlib) python-lxml >= 2.2 libxml2 >= 2.7.8 libxml2-python >= 2.7.8 libxslt >= 1.1.26 libxslt-python >= 1.1.26 sqlite >= 3.2.0 (sqlite is preferred to mysql as database, MySQL-python has been reported to be installed if so) sqlalchemy >= 0.6.4 sqlalchemy-migrate >= 0.5.4 zenity >= 2.30 - Only needed if correspondent plugin or extension is enabled: gpsbabel == 1.3.5 ("GoogleEarth" and "Garmin via GPSBabel 1.3.5" aka "garmin_hr") garmintools >= 0.10 ("Import from Garmin GPS device (via garmintools)" aka "garmintools_full" plugin) wordpresslib (already distributed within pytrainer tarball, wordpress extension) httplib2 >= 0.6.0 (wordpress extension) SOAPpy >= 0.11.6 (dotclear extension) GDAL (Elevation correction, via "gdal-python" or "python-gdal") perl (garmin-fit plugin, tested with perl v5.16.2 on Fedora 18, see ticket #5) 2.- Installation process Copy tarball file to a location where you have write and execution rights (e.g. /tmp or your $HOME directory). Make sure executables are under your $PATH. $ tar -xzf pytrainer-X.Y.Z.tar.gz $ cd pytrainer-X.Y.Z $ sudo python setup.py install $ pytrainer -i For more information about the process, please check http://docs.python.org/distutils/setupscript.html 3.- USB access pytrainer can use gpsbabel (http://www.gpsbabel.org) to retrieve information from Garmin devices. There are some problems regarding driver to access usb ports, please take a look at http://www.gpsbabel.org/os/Linux_Hotplug.html pytrainer-2.0.0/PLUGINS.README000066400000000000000000000017601351137001400155250ustar00rootroot00000000000000Information on creating Plugins =========================================== Plugins are created by: 1) Making a directory in /plugins/ 2) Creating a python class in a file in your directory - class must have run(self) function - run(self) returns tuple of GPX files to import 3) Creating a conf.xml configuration file in your directory with at least the following information: Where name: is the name of your plugin description: is the description plugincode: is the name of the class in your plugin file pluginbutton: is the label that the menu option will have once your plugin is enabled executable: is the file that the python class in in (without the .py extension) pytrainer-2.0.0/README.md000066400000000000000000000031621351137001400150020ustar00rootroot00000000000000pytrainer - Free your sports ================================================== Source Repository Structure --------------------------- * **bin** pytrainer executable *python script* files * **extensions** addons to extend pytrainer basic functionality * **glade** user interface design * **imports** files to parse different source formats * **locale** localization files * **man** source manpage * **plugins** files to retrieve data from different sources * **pytrainer** core files * **schemas** schemas to support correct xml parsing * **utils** localization shell script Installation from source tarball ----------------- Copy tarball file to a location where you have write and execution rights (e.g. `/tmp` or your `$HOME` directory). Make sure executables are under your `$PATH`. `$ tar -xzf pytrainer-X.Y.Z.tar.gz` `$ cd pytrainer-X.Y.Z` `$ sudo python setup.py install` `$ pytrainer -i` For more information about the process, please check [Distutils documentation] (http://docs.python.org/distutils/setupscript.html) Further Resources ----------------- * FAQ [https://github.com/pytrainer/pytrainer/wiki/FAQ](https://github.com/pytrainer/pytrainer/wiki/FAQ) * Distribution list: pytrainer-devel@lists.sourceforge.net * Development guide: [https://github.com/pytrainer/pytrainer/wiki/Development-guide](https://github.com/pytrainer/pytrainer/wiki/Development-guide) * Localization guide: [https://github.com/pytrainer/pytrainer/wiki/Localization-guide](https://github.com/pytrainer/pytrainer/wiki/Localization-guide) * Report an Issue: [https://github.com/pytrainer/pytrainer/issues](https://github.com/pytrainer/pytrainer/issues) pytrainer-2.0.0/bin/000077500000000000000000000000001351137001400142715ustar00rootroot00000000000000pytrainer-2.0.0/bin/pytrainer000077500000000000000000000061551351137001400162430ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- #Copyright (C) Fiz Vazquez vud1@sindominio.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, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. from __future__ import print_function import sys import os import glob import platform def _max(one, two): '''Function to determine the max of two versions of format /xx/xxx/????-1.2.3 ''' if one is None: return two elif two is None: return one try: one_v = os.path.basename(one).split('-')[1] two_v = os.path.basename(two).split('-')[1] except IndexError: #Got format that doesnt fit what we expect #Do simple comparison if os.path.basename(one) > os.path.basename(two): return one else: return two one_v_nos = one_v.split('.') two_v_nos = two_v.split('.') for index, no in enumerate(one_v_nos): if index >= len(two_v_nos): return one elif no > two_v_nos[index]: return one elif no < two_v_nos[index]: return two else: pass if len(one_v_nos) >= len(two_v_nos): return one return two bin_path = os.path.realpath(os.path.dirname(__file__)) # directory that the pytrainer script executes from e.g. /usr/bin or /usr/local/bin base_path = os.path.dirname(bin_path) #Get the version of the running python interpreter ver = platform.python_version_tuple() if (os.path.exists(base_path + "/INSTALL") and os.path.exists(base_path + "/setup.py") and os.path.exists(base_path + "/pytrainer/main.py") and os.path.exists(base_path + "/locale")): print("running pytrainer from source path") data_path = base_path + "/" site_path = base_path gettext_path = base_path + "/locale" else: print("running pytrainer from egg installation") parts = os.path.split(base_path) if parts[1] == 'EGG-INFO': base_path = parts[0] data_path = base_path + "/share/pytrainer/" site_path = "%s/lib/python%s.%s/site-packages" % (base_path, ver[0], ver[1]) gettext_path = base_path + "/share/locale" print("data_path: " + data_path) print("gettext_path: " + gettext_path) print("site_path: " + site_path) #ensure pytrainer directory is included in import path sys.path.insert(0, site_path) def main(): import pytrainer.lib.localization pytrainer.lib.localization.initialize_gettext(gettext_path) from pytrainer.main import pyTrainer pytrainer = pyTrainer(None, data_path) if __name__ == "__main__": main() pytrainer-2.0.0/extensions/000077500000000000000000000000001351137001400157205ustar00rootroot00000000000000pytrainer-2.0.0/extensions/dotclear/000077500000000000000000000000001351137001400175155ustar00rootroot00000000000000pytrainer-2.0.0/extensions/dotclear/README.txt000066400000000000000000000131641351137001400212200ustar00rootroot00000000000000 Dotclear pytrainer extension =============================== This extension allows you to post your sport record directly into your dotclear weblog. It work only on a Dotclear 2.0 blog It's a small program to learn python, it's not a revolution but is work First section in english (for all over the world) Second section the same but in french (because dotclear is primary use in France) CONFIG OPTIONS ============== You have to fill in all the fields. xmlrpcserver: to send a new post on your blog, you have to activate the xml/rpc server. when this service is activated dotclear give you a xml/rpc adress ( like http://yourblog.be/index.php/xmlrpc/default ) bloguser: Your user id for your blog blogpass : Your password that you use on connect you to your blog blogid: dotclear 2.0 can accept somes blogs with one install, you have to define the blog id (by default it's 1 ) blogcategory: It's the category's number where this extension post your record on youR blog USAGE ===== Simply submit the dotclear extension preferences form and then go to the record tab and press "post it in dotclear". ON YOUR BLOG ============ I have created a category only for my pytrainer record. I have excluded this category on my homepage and took a section on the sidebard for show only this category To exclude the category ------------------------ You must (HAVE TO ENCORE ET TOUJOURS) edit the home.html file on your template directory. And change the to the name of your category is the dotclear name for your categories (without accents and spécial char) To only show the record category on your sidebar -------------------------------------------------

{{tpl:EntryTitle encode_html="1"}}

{{tpl:EntryExcerpt}}
{{tpl:EntryContent}}
you have to replace training by the category's name THANKS ====== Fiz for pytrainer, and is help for every stupid question that i have sent. Gnomefiles for the promotion of somes app's My stupid stage, where if i wanT take something i must have do wath i want IN FRENCH Dotclear pytrainer extension =============================== Cette extension vous permet d'envoyer vos scores de pytrainer vers votre blog dotclear 2.0 Options de configuration ======================== Vous devez remplir tous les champs xmlrpcserver: pour envoyer un nouveau post sur votre blog, vous devez activer l'interface xml/rpc de votre blog dotclear 2.0. Pour cela rendez-vous sur la page Parametres du blog, il y a une section xml/rpc à activer. Après activation de l'interface, dotclear vous indiquerea une adresse ( comme http://votre blog.be/index.php/xmlrpc/default ) bloguser: Votre identifiant de connections a votre blog, votre nom d'utilisateur quoi blogpass : Le mot de passe que vous utilisez pour vous connecter a votre blog (n'ayez crainte personne, ne le verra) blogid: Dotclear 2.0 peut faire plusieurs blogs différents avec une seule installation (le multiblog que ça s'appelle) pour que cette extension sache où envoyer votre post, il faut lui dire vers quel blog (par défaut c'est 1 ) blogcategory: Chaque catégorie crée dans votre blog à un nº (par ordre de création, donc général a le nº 1), il s'agit de la catégorie dans laquelle cette extension enverra les données de votre score. Pour trouver le nº de la catégorie vous cliquez sur Catégories dans la colonne de gauche de l'interface d'administration de votre blog, vous cliquez sur la catégorie et dans la barre d'adresse de votre navigateur vous trouverez un truc comme admin/category.php?id=5 et bien ici le nº de la catégorie est 5 UTILISATION =========== Dans la fenêtre qui donne les détails sur un record, vous devez avoir en bas à droite un petit bouton "Post in Dotclear" et hop cette extension grâce a l'aide de pytrainer enverra certaines informations de votre score sur votre blog SUR VOTRE BLOG ============ J'ai créé une catégorie exprès pour mes scores de pytrainer. J'ai exclu cette catégorie de ma page d'accueil et utilisé une partie de ma barre latérale pour montrer uniquement cette catégorie Pour exclure la catégorie ------------------------ Vous devez éditer le fichier home.html dans le dossier de votre template. Et remplacer le code par . le nom de la catégorie doit être le nom de votre catégorie selon dotclear (sans accents et sans caractères spéciaux) Pour uniquement montrer la catégorie avec vos record dans la barre latérale -------------------------------------------------

{{tpl:EntryTitle encode_html="1"}}

{{tpl:EntryExcerpt}}
{{tpl:EntryContent}}
il faut remplacer entrainements par le nom de votre catégorie, et 4 dans lastn="" c'est le nombre de billets affichés pytrainer-2.0.0/extensions/dotclear/conf.xml000066400000000000000000000010241351137001400211610ustar00rootroot00000000000000 pytrainer-2.0.0/extensions/dotclear/main.py000077500000000000000000000122471351137001400210240ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- #Copyright (C) DJ dj@namurlug.org http://blog.dedj.be #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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import xmlrpclib import SOAPpy import os from pytrainer.lib.date import second2time from pytrainer.lib.soapUtils import * from optparse import OptionParser class Main: def __init__(self,options): # on definit les parametres de connection au blog self.xmlrpcserver = options.xmlrpcserver self.blogid = options.blogid self.user = options.bloguser self.password = options.blogpass self.category_nbr = options.blogcategory #if you want accept comment, replace False by True self.comment = False #or ping self.ping = False self.category = [{'isPrimary': True, "categoryId" : self.category_nbr}] self.error = "" self.log ="" self.idrecord = options.idrecord self.webserviceserver = SOAPpy.SOAPProxy("http://localhost:8081/") #we try the connection to the xml/rpc server try : self.connect = xmlrpclib.Server(self.xmlrpcserver) self.error = False except : print("can't connect the server") def loadRecordInfo(self): record = self.webserviceserver.getRecordInfo(self.idrecord) self.sport = record["sport"] self.date = record["date"] self.distance = record["distance"] self.time = second2time(float(record["time"])) self.heure = self.time[0] self.minute = self.time[1] self.seconde = self.time[2] self.beats = record["beats"] self.comments = record["comments"] self.average = record["average"] self.calories = record["calories"] self.title = record["title"] self.upositive = record["upositive"] self.unegative = record["unegative"] def construction(self): #this methode create the content post content, the section between the ''' are on html thake wath you want #self.date, self.distance, self.time, self.beats, self.comments, self.average, self.calories, self.title, self.title, self.upositive, self.unegative, self.sport description_table = '''

%s %s

With a average of %s km/h


I have lost %s kcalories and my heart have %s pulsations (on average)

''' %(self.sport, self.title,self.average, self.calories, self.beats) return description_table def chapeau(self): chapeau_table = '''

A %s score on a distance of %s km on %sh %sm %s


''' %(self.sport,self.distance,self.heure, self.minute, self.seconde) return chapeau_table def run(self): #we load all info for the record self.loadRecordInfo() blog_desc = self.construction() blog_chap = self.chapeau() if self.error == False: #post_description = "Du " + str(self.sport) + " sur une distance de " + str(self.distance) +"km " + " en " + str(self.time) + " ce qui nous fait une moyenne de " + str(self.average) server = xmlrpclib.Server(options.xmlrpcserver) content = {'title' : self.date, 'description' : blog_desc, 'mt_allow_comments' : self.comment, 'mt_allow_pings' : self.ping,'mt_excerpt' : blog_chap} post = server.metaWeblog.newPost(self.blogid, self.user, self.password, content , True) #we change the post categories because, i( or it's the false of xml/rpc) can't select the categories before the upload on the blog change_cat = server.mt.setPostCategories(post,self.user,self.password, self.category) return "The post has been submited" self.webserviceserver.stop else: return self.log parser = OptionParser() parser.add_option("-d", "--device", dest="device") parser.add_option("-k", "--xmlrpcserver", dest="xmlrpcserver") parser.add_option("-u", "--bloguser", dest="bloguser") parser.add_option("-p", "--blogpass", dest="blogpass") parser.add_option("-l", "--blogid", dest="blogid") parser.add_option("-c", "--blogcategory", dest="blogcategory") parser.add_option("-g", "--gpxfile", dest="gpxfile") parser.add_option("-i", "--idrecord", dest="idrecord") (options,args) = parser.parse_args() try : x = Main(options) x.run() print(("le score du %s a ete envoye" % x.date)) except xmlrpclib.Fault as f: print(("ERROR on the server\n Code %i\n Reason %s" % (f.faultCode, f.faultString))) pytrainer-2.0.0/extensions/fixelevation/000077500000000000000000000000001351137001400204155ustar00rootroot00000000000000pytrainer-2.0.0/extensions/fixelevation/README.txt000066400000000000000000000030331351137001400221120ustar00rootroot00000000000000 Fix Elevation pytrainer extension =============================== This extension allows you to correct elevations within gpx data. Code is based on Wojciech Lichota's gpxtools http://lichota.pl/blog/topics/gpxtools Elevations are corrected using SRTM data, therefore on first usage the necessary SRTM tile will be downloaded (large!). Tiles will be cached. Extension requires 'GDAL python bindings'. Install e.g. apt-get install python-gdal or yum install gdal-python CONFIG OPTIONS ============== n.n. USAGE ===== Simply submit the fixelevation extension preferences form and then go to the record tab and press "Fix Elevation". --------------------------- IMPORTANT ========= - On first use, the extension will download a geo_tif File (about 79mb) for your region, there is no warning dialog or similiar. - Original gpx data (in '.pytrainer/gpx/') will be overwritten. - The main record isn't forced to be reloaded at the moment, so restart pytrainer to study the manipulated heights. TODO ==== (?) Interface to specify source of SRTM data (at the moment hardcoded CGIAR mirror) (?) Interface to specify where to store SRTM data (at the moment .pytrainer/SRTM_data) (?) Store original gpx elevation data (gpx extension or whole backup file?); offer revert possibility (?) Improve Wojciech's border trick. (?) Offer alternative SRTM/DEM Sources eg http://www.viewfinderpanoramas.org/dem3.html (?) Offer batch mode to fix bundle of tracks (?) Higher order of interpolation (ie bicubic) pytrainer-2.0.0/extensions/fixelevation/conf.xml000066400000000000000000000004331351137001400220640ustar00rootroot00000000000000 pytrainer-2.0.0/extensions/fixelevation/fixelevation.py000066400000000000000000000146431351137001400234740ustar00rootroot00000000000000#!/usr/bin/env python import os #, stat, sys import logging from gi.repository import Gtk from lxml import etree from pytrainer.lib.srtmlayer import SrtmLayer class fixelevation: _data = None _srtm = SrtmLayer() def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): self.parent = parent self.pytrainer_main = pytrainer_main self.options = options self.conf_dir = conf_dir def run(self, aid, activity=None): #TODO Convert to use activity... #print activity logging.debug(">>") gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, aid) ele_fixed = True if os.path.isfile(gpx_file): # Backup original raw data as *.orig.gpx #orig_file = open(gpx_file, 'r') #orig_data = orig_file.read() #orig_file.close() #backup_file = open("%s/gpx/%s.orig.gpx" % (self.conf_dir, id), 'w') #backup_file.write(orig_data) #backup_file.close() #GPX file is ok and found, so open it logging.debug("ELE GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) """ Parse GPX file to ElementTree instance. """ self._data = etree.parse(gpx_file) self._xmlns = self._data.getroot().nsmap[None] nsmap = self._data.getroot().nsmap pyt_ns = "http://sourceforge.net.project/pytrainer/GPX/0/1" PYTRAINER = "{%s}" % pyt_ns self._trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (self._xmlns, self._xmlns, self._xmlns) def addExt(trackpoint, ele_new): #Add new elevation to extension tag ''' 31.1 ''' ext = etree.Element("extensions") py_ele = etree.SubElement(ext, PYTRAINER + "ele", method="srtm_bilinear") py_ele.text = str(ele_new) trackpoint.append(ext) """ Replace elevation from GPX by data from SRTM. TODO (Arnd) make a function within class fixelevation out of this for better reuse """ trackpoints = self._data.findall(self._trkpt_path) for trkpt in trackpoints: lat = float(trkpt.attrib['lat']) lon = float(trkpt.attrib['lon']) ele = trkpt.find('{%s}ele' % self._xmlns) ele_new = self._srtm.get_elevation(lat, lon) if not ele_new: ele_fixed = False break addExt(trkpt, ele_new) if not ele_fixed: # Try Google maps elevation API import cjson, urllib2, math steps = len(trackpoints) / 300 path = '' lat_prev, long_prev = 0, 0 t = 0 for t in xrange(0,len(trackpoints),steps): lat = float(trackpoints[t].attrib['lat']) lon = float(trackpoints[t].attrib['lon']) encoded_lat, lat_prev = encode_coord(lat, lat_prev) encoded_long, long_prev = encode_coord(lon, long_prev) path += encoded_lat + encoded_long t += 1 url = "http://maps.googleapis.com/maps/api/elevation/json?sensor=true&samples=%d&path=enc:" % int((len(trackpoints) / steps)) url += path try: google_ele = cjson.decode(urllib2.urlopen(url).read()) if google_ele['status'] == "OK": t_idx = 0 ele_points = len(google_ele['results']) for ele_new in xrange(0,ele_points): addExt(trackpoints[t_idx], google_ele['results'][ele_new]['elevation']) for intermediate in xrange(ele_new+1, ele_new+steps): if intermediate= 32: b.append(n & 31) n = n >> 5 b = [(c | 0x20) for c in b] b.append(n) b = [(i + 63) for i in b] return ''.join([chr(i) for i in b]) pytrainer-2.0.0/extensions/gpx2garmin/000077500000000000000000000000001351137001400177765ustar00rootroot00000000000000pytrainer-2.0.0/extensions/gpx2garmin/README000066400000000000000000000017561351137001400206670ustar00rootroot00000000000000Summary: gpx2garmin is a pytrainer (https://github.com/pytrainer/pytrainer) extension that will export the current record's gpx track to a garmin device. Requirements: gbsbabel - http://www.gpsbabel.org/ (typically installable via your repository) Usage: 1) Plug your device in via USB, switch it on. 2) Click the 'Export to device' button = export to garmin device! Caveats: - Some (all?) devices will truncate the track because they only support a limited amount of track points. The extension can (via gpsbabel) simplify a track using the limit supplied by the user. Beware of track changes (e.g. sharp bends on the map may show the trace cutting corners)! - Track names aren't part of the track data so are added by the extension from the metadata. Some devices, however, truncate the name (e.g. biking2010-08-23 > biking2010-08) so rename tracks where necessary. You may also need to fix the device permissions as documented here: http://www.gpsbabel.org/os/Linux_Hotplug.html pytrainer-2.0.0/extensions/gpx2garmin/conf.xml000066400000000000000000000006201351137001400214430ustar00rootroot00000000000000 pytrainer-2.0.0/extensions/gpx2garmin/gpx2garmin.py000077500000000000000000000036661351137001400224440ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import Gtk import subprocess import re class gpx2garmin: def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): self.limit = options["gpx2garminmaxpoints"] self.device = options["gpx2garmindevice"] self.conf_dir = conf_dir self.gpxfile = None self.tmpgpxfile = "/tmp/_gpx2garmin.gpx" self.pytrainer_main = pytrainer_main def prepareGPX(self): ' create an output file and insert a name into the stanza ' f = open(self.tmpgpxfile, 'w') name = 'default' for line in open(self.gpxfile): if re.search('^.+$', line): name = line elif re.search('^$', line): line = '%s%s' % (line, name) f.write(line) f.close() def exportGPX(self): ' export the GPX file using gpsbabel ' cmd = ["gpsbabel", "-t", "-i", "gpx", "-f", self.tmpgpxfile, "-o", "garmin"] if self.limit is not None: cmd = cmd + ["-x", "simplify,count=%s" % self.limit] cmd = cmd + ["-F", self.device] return subprocess.call(cmd) def run(self, id, activity=None): ' main extension method ' self.gpxfile = "%s/gpx/%s.gpx" % (self.conf_dir, id) self.log = "Export " try: self.prepareGPX() if self.exportGPX() == 1: # assume no device present? self.log = self.log + "failed - no device present?" else: self.log = self.log + "succeeded!" except: self.log = self.log + "failed!" md = Gtk.MessageDialog(self.pytrainer_main.windowmain.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, self.log) md.set_title(_("gpx2garmin Extension")) md.set_modal(False) md.run() md.destroy() pytrainer-2.0.0/extensions/openstreetmap/000077500000000000000000000000001351137001400206065ustar00rootroot00000000000000pytrainer-2.0.0/extensions/openstreetmap/OSM_AnonSelection.glade000066400000000000000000000057561351137001400251000ustar00rootroot00000000000000 Select your private area True center 600 400 True True vertical True vertical 0 True 3 _Ok True True True True 1 _Cancel True True True GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK True 3 False 1 pytrainer-2.0.0/extensions/openstreetmap/README.txt000066400000000000000000000007351351137001400223110ustar00rootroot00000000000000 Openstreetmap pytrainer extension =============================== This extension allows you to post your sport record directly into Openstreetmap. CONFIG OPTIONS ============== You MUST fill in all the fields username: A valid Openstreetmap username password: The password for the Openstreetmap username. USAGE ===== Simply submit the openstreetmap extension preferences form and then go to the record tab and press "Post to Openstreetmap". pytrainer-2.0.0/extensions/openstreetmap/conf.xml000066400000000000000000000006531351137001400222610ustar00rootroot00000000000000 pytrainer-2.0.0/extensions/openstreetmap/openstreetmap.py000066400000000000000000000422161351137001400240530ustar00rootroot00000000000000#!/usr/bin/env python from optparse import OptionParser import os, stat import sys import logging from gi.repository import Gtk import string from lxml import etree import httplib, httplib2 import urllib2 import mimetools, mimetypes from json import dumps, loads # for deserializing JSON data form javascript from pytrainer.extensions.mapviewer import MapViewer from pytrainer.extensions.osm import Osm from pytrainer.lib.localization import gtk_str class openstreetmap: def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): self.parent = parent self.pytrainer_main = pytrainer_main self.options = options self.conf_dir = conf_dir self.description = " " self.tags = "" self.visibility = "private" self.mozTitle="" # Keeps embedded mozilla document title while displaying map for private area selection self.privBounds=[] # Bounds of areas to be anonymized def run(self, id, activity=None): #TODO Convert to use activity... logging.debug(">>") try: uri = "http://api.openstreetmap.org/api/0.6/gpx/create" #URI for uploading traces to OSM if 'username' not in self.options or self.options['username'] == "" or 'password' not in self.options or self.options['password'] == "": logging.error("Must have username and password configured") raise Exception("Must have username and password configured") username = self.options['username'] password = self.options['password'] gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) if not os.path.isfile(gpx_file): raise Exception(str(gps_file) + ' File not found') #GPX file is ok and found, so open it logging.debug("GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) f = open(gpx_file, 'r') file_contents = f.read() #TODO Fix to use etree functionality..... if file_contents.find("") != -1: logging.debug("GPX file: %s has ASCII encoding - updating to UTF-8 for OSM support" % gpx_file) f.close() #Close readonly file f = open(gpx_file, 'w') #and open file for writing file_contents = file_contents.replace("","", 1) f.write(file_contents) #Write new content f.close() #Close f = open(gpx_file, 'r') #Reopen in readonly mode #Get extra info from user response=self.display_options_window() if not response==Gtk.ResponseType.ACCEPT: f.close() logging.debug("User abort") return if self.makeanon: logging.debug("User requested anonymizing of GPX data") f.close() #Close standard gpxfile gpx_file = self.make_gpx_private(gpx_file) f = open(gpx_file, 'r') #Open anonymous gpxfile in readonly mode fields = (("description",self.description), ("tags",self.tags), ("visibility",self.visibility)) logging.debug("Added fields: %s" % str(fields)) #Multipart encode the request boundary, body = self.multipart_encode(fields=fields, files=(("file", f),)) content_type = 'multipart/form-data; boundary=%s' % boundary #Finished with the file so close it f.close() #Add the http headers to the request h = httplib2.Http() headers = { 'Content-Type': content_type } #Add basic authentication credentials to the request h.add_credentials(username, password) #Show user something is happening msg = _("Posting GPX trace to Openstreetmap\n\nPlease wait this could take several minutes") md = Gtk.MessageDialog(self.pytrainer_main.windowmain.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.NONE, msg) md.set_title(_("Openstreetmap Extension Processing")) md.set_modal(True) md.show() while Gtk.events_pending(): # This allows the GUI to update Gtk.main_iteration() # before completion of this entire action logging.debug("before request posting") #POST request to OSM res, content = h.request(uri, 'POST', body=body, headers=headers) logging.debug("after request posting") logging.debug("Got response status: %s, reason: %s, content: %s" % (res.status, res.reason, content)) if res.reason == 'OK': res_msg = "Successfully posted to OSM.\nYou should get an email with the outcome of the upload soon\n\nTrace id is %s" % content else: res_msg = "Some error occured\nGot a status %s, reason %s\nContent was: %s" % (res.status, res.reason, content) #Close 'Please wait' dialog md.destroy() #Show the user the result md = Gtk.MessageDialog(self.pytrainer_main.windowmain.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, res_msg) md.set_title(_("Openstreetmap Extension Upload Complete")) md.set_modal(False) md.run() md.destroy() except Exception as e: msg = _("Error while uploading file to OSM: " + str(e)) md = Gtk.MessageDialog(self.pytrainer_main.windowmain.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, msg) md.set_title(_("Openstreetmap Extension Error")) md.run() md.destroy() return finally: logging.debug("<<") def display_options_window(self): self.prefwindow = Gtk.Dialog(title=_("Please add any additional information for this upload"), parent=None, flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, buttons=(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT, Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)) self.prefwindow.set_modal(False) table = Gtk.Table(1,3) self.entryList = [] #Add description label = Gtk.Label(label="Description") label.set_use_markup(True) entry = Gtk.Entry() self.entryList.append(entry) table.attach(label,0,1,0,1) table.attach(entry,1,2,0,1) #Add tags label = Gtk.Label(label="Tags") label.set_use_markup(True) entry = Gtk.Entry() self.entryList.append(entry) table.attach(label,0,1,1,2) table.attach(entry,1,2,1,2) #Add visibility label = Gtk.Label(label="Visibility") label.set_use_markup(True) combobox = Gtk.ComboBoxText() combobox.append_text("private") combobox.append_text("public") combobox.append_text("trackable") combobox.append_text("identifiable") combobox.set_active(0) table.attach(combobox,1,2,2,3) self.entryList.append(combobox) table.attach(label,0,1,2,3) #Add anonymize GPX option label = Gtk.Label(label="Anonymize GPX Data") label.set_use_markup(True) table.attach(label,0,1,3,4) checkbutton = Gtk.CheckButton() table.attach(checkbutton,1,2,3,4) self.entryList.append(checkbutton) #Add anon area selection button button = Gtk.Button("Area selection") button.connect("clicked",self.areaSelect) table.attach(button,1,2,4,5) self.entryList.append(button) #Build dialog and show self.prefwindow.vbox.pack_start(table, True, True, 0) self.prefwindow.show_all() self.prefwindow.connect("response", self.on_options_ok_clicked) response=self.prefwindow.run() self.prefwindow.destroy() return response def on_options_ok_clicked(self, widget, response_id): if not response_id == Gtk.ResponseType.ACCEPT: return response_id self.description = gtk_str(self.entryList[0].get_text()) if self.description == "": logging.debug("A description is required - setting to default") self.description = "Uploaded from pytrainer" self.tags = gtk_str(self.entryList[1].get_text()) self.visibility = gtk_str(self.entryList[2].get_active_text()) self.makeanon = self.entryList[3].get_active() logging.debug("Description: %s, tags: %s, visibility: %s, makeanon: %s" % ( self.description, self.tags, self.visibility, self.makeanon) ) def areaSelect(self,dc): """ Open a window with OSM map so user could select his private/anonymized area - all GPX dots in this area will be removed before uploading to OSM """ try: wTree = Gtk.glade.XML(self.pytrainer_main.data_path+"extensions/openstreetmap/OSM_AnonSelection.glade") self.privAreaWindow = wTree.get_widget("OSM_AnonSelection") dic = { "on_buttonOk_clicked" : self.privArea_Ok, "on_buttonCancel_clicked" : self.privArea_Cancel } wTree.signal_autoconnect( dic ) mapviewer = MapViewer(self.pytrainer_main.data_path, pytrainer_main=self.pytrainer_main, box=wTree.get_widget("mapBox")) json=None if 'privPolygon' in self.options: json=self.options['privPolygon'] htmlfile = Osm(data_path=self.pytrainer_main.data_path, waypoint=json, pytrainer_main=self.pytrainer_main).selectArea() mapviewer.display_map(htmlfile=htmlfile) mapviewer.moz.connect('title', self.parseTitle) self.privAreaWindow.show() except Exception as e: msg = "Could not init map selection screen, Error: " + str(e) md = Gtk.MessageDialog(self.pytrainer_main.windowmain.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, msg) md.set_title(_("Error")) md.run() md.destroy() return def parseTitle(self, moz): "Event fired when document title was changed -> meaning polygon was changed" if moz.get_title() != "": self.mozTitle=str(moz.get_title()) def privArea_Cancel(self,button): "Event fired when cancel button was pressed" self.privAreaWindow.destroy() def privArea_Ok(self,button): "Event fired when ok button was pressed" logging.debug(">> privArea_Ok") # save new private area polygon if changed if self.mozTitle=="": return # try parsing JSON try: # verify json is correct by deserializing and serializing it polygonString=dumps(loads(self.mozTitle)) # try saving extensionDir = self.pytrainer_main.data_path + "/extensions" + "/openstreetmap" if not os.path.isdir(extensionDir): loggin.error(str(e)) raise Exception("Could not find extension path: " + str(extensionDir)) # save new options self.options['privPolygon'] = polygonString # convert dictionary to a lists set savedOptions = [] for key in self.options: savedOptions.append((key,self.options[key])) # write new xml config file self.parent.setExtensionConfParams(extensionDir, savedOptions) except Exception as e: logging.error(str(e)) msg = _(str(e)) md = Gtk.MessageDialog(self.pytrainer_main.windowmain.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, msg) md.set_title(_("Error while saving extension configuration")) md.run() md.destroy() finally: self.privAreaWindow.destroy() def multipart_encode(self, fields, files, boundary = None, buffer = None): ''' Multipart encode data for posting from examples at from http://odin.himinbi.org/MultipartPostHandler.py & http://bitworking.org/projects/httplib2/doc/html/libhttplib2.html ''' if boundary is None: boundary = mimetools.choose_boundary() if buffer is None: buffer = '' for (key, value) in fields: buffer += '--%s\r\n' % boundary buffer += 'Content-Disposition: form-data; name="%s"' % key buffer += '\r\n\r\n' + value + '\r\n' for (key, fd) in files: file_size = os.fstat(fd.fileno())[stat.ST_SIZE] filename = os.path.basename(fd.name) contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' buffer += '--%s\r\n' % boundary buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename) buffer += 'Content-Type: %s\r\n' % contenttype # buffer += 'Content-Length: %s\r\n' % file_size fd.seek(0) buffer += '\r\n' + fd.read() + '\r\n' buffer += '--%s--\r\n\r\n' % boundary return boundary, buffer def make_gpx_private(self, gpx_file=None): ''' wipes out private data from gpx files converts laps to waypoints ''' logging.debug(">>") if gpx_file is None: return None filen = os.path.basename(gpx_file) tmpdir = self.pytrainer_main.profile.tmpdir anon_gpx_file = "%s/%s" % (tmpdir, filen) # get saved private area polygon pP=loads(self.options['privPolygon']) pP=pP['geometry']['coordinates'][0] # converts polygon's 2D matrix into a vector of just the lats or lons vector = lambda lonLat: [pP[i][lonLat] for i in range(len(pP))] # 0:lon, 1:lat # try reading private area's bounds, stored as [lon,lat] NE_LAT = max([pP[i][1] for i in range(len(pP))]) NE_LON = max([pP[i][0] for i in range(len(pP))]) SW_LAT = min([pP[i][1] for i in range(len(pP))]) SW_LON = min([pP[i][0] for i in range(len(pP))]) logging.info("Anonymizing Area: NE:%f,%f -> SW: %f,%f" % (NE_LON, NE_LAT, SW_LON, SW_LAT)) # Config parameters, not used yet FILTER_BOX = True ERASE_TIME = True LAP_TO_WAYPOINT = True tree = etree.parse(gpx_file) _xmlns = tree.getroot().nsmap[None] _trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (_xmlns, _xmlns, _xmlns) # namespace of gpx files NS = dict(ns='http://www.topografix.com/GPX/1/1') myroot = tree.getroot() gpxdataNS = string.Template(\ ".//{http://www.cluetrust.com/XML/GPXDATA/1/0}$tag") lapTag = gpxdataNS.substitute(tag="lap") endPointTag = gpxdataNS.substitute(tag="endPoint") triggerTag = gpxdataNS.substitute(tag="trigger") laps = tree.findall(lapTag) mygpx = tree.find('gpx') for lap in laps: trigger = lap.find(triggerTag) # Watch out for manually triggered laps if trigger.text == 'manual': endPoint = lap.find(endPointTag) lat = endPoint.get("lat") lon = endPoint.get("lon") # Create waypt if not in home box try: if not ((SW_LAT < float(lat) < NE_LAT) and (SW_LON < float(lon) < NE_LON)): etree.SubElement(myroot, 'wpt', attrib= {'lat':lat, 'lon':lon}) except: pass etree.strip_attributes(myroot, 'creator') # Wipe out home box for trkpt in tree.findall(_trkpt_path): lat = float(trkpt.attrib['lat']) lon = float(trkpt.attrib['lon']) if (lat < NE_LAT) & (lon < NE_LON) & (lat > SW_LAT) & (lon > SW_LON): par = trkpt.getparent() par.remove(trkpt) time = tree.xpath('//ns:trkpt/ns:time', namespaces=NS) for i in time: i.text = '1970-01-01T00:00:00+00:00' # osm regards