├── .coveragerc
├── .gitignore
├── .travis.yml
├── MANIFEST.in
├── README.rst
├── bin
├── everpad
├── everpad-lens
└── everpad-provider
├── data
├── editor-icons
│ ├── everpad-checkbox.png
│ ├── everpad-insert-image.png
│ ├── everpad-insert-table.png
│ ├── everpad-justify-center.png
│ ├── everpad-justify-fill.png
│ ├── everpad-justify-left.png
│ ├── everpad-justify-right.png
│ ├── everpad-link.png
│ ├── everpad-list-ordered.png
│ ├── everpad-list-unordered.png
│ ├── everpad-pin.png
│ ├── everpad-share.png
│ ├── everpad-text-bold.png
│ ├── everpad-text-italic.png
│ ├── everpad-text-strikethrough.png
│ └── everpad-text-underline.png
├── everpad-app.service
├── everpad-black.png
├── everpad-file.png
├── everpad-lens.png
├── everpad-mono.png
├── everpad-note.png
├── everpad-provider.service
├── everpad.desktop
├── everpad.lens
├── everpad.png
├── everpad.xcf
├── metadata.desktop
├── plasma-runner-everpad.desktop
└── unity-lens-everpad.service
├── dev_requirements.txt
├── docs
├── everpad.1
└── license.txt
├── evernote
├── __init__.py
└── edam
│ ├── __init__.py
│ ├── error
│ ├── __init__.py
│ ├── constants.py
│ └── ttypes.py
│ ├── limits
│ ├── __init__.py
│ ├── constants.py
│ └── ttypes.py
│ ├── notestore
│ ├── NoteStore-remote
│ ├── NoteStore.py
│ ├── __init__.py
│ ├── constants.py
│ └── ttypes.py
│ ├── type
│ ├── __init__.py
│ ├── constants.py
│ └── ttypes.py
│ └── userstore
│ ├── UserStore-remote
│ ├── UserStore.py
│ ├── __init__.py
│ ├── constants.py
│ └── ttypes.py
├── everpad.pro
├── everpad
├── __init__.py
├── basetypes.py
├── const.py
├── interface
│ ├── __init__.py
│ ├── editor.py
│ ├── editor.ui
│ ├── findbar.py
│ ├── findbar.ui
│ ├── image.py
│ ├── image.ui
│ ├── list.py
│ ├── list.ui
│ ├── management.py
│ ├── management.ui
│ ├── notebook.py
│ ├── notebook.ui
│ ├── share_note.py
│ ├── share_note.ui
│ ├── tableinsert.py
│ └── tableinsert.ui
├── monkey.py
├── pad
│ ├── __init__.py
│ ├── editor
│ │ ├── __init__.py
│ │ ├── actions.py
│ │ ├── content.py
│ │ ├── editor.html
│ │ ├── resources.py
│ │ └── widgets.py
│ ├── indicator.py
│ ├── list.py
│ ├── management.py
│ ├── share_note.py
│ ├── tools.py
│ └── treeview.py
├── provider
│ ├── __init__.py
│ ├── daemon.py
│ ├── exceptions.py
│ ├── models.py
│ ├── service.py
│ ├── sync
│ │ ├── __init__.py
│ │ ├── agent.py
│ │ ├── base.py
│ │ ├── note.py
│ │ ├── notebook.py
│ │ └── tag.py
│ └── tools.py
├── specific
│ ├── __init__.py
│ ├── kde
│ │ ├── __init__.py
│ │ └── everpad_runner.py
│ └── unity
│ │ ├── __init__.py
│ │ ├── launcher.py
│ │ └── lens.py
└── tools.py
├── i18n
├── ar
│ └── LC_MESSAGES
│ │ ├── everpad.mo
│ │ └── everpad.po
├── ar_EG.qm
├── ar_EG.ts
├── de
│ └── LC_MESSAGES
│ │ ├── everpad.mo
│ │ └── everpad.po
├── de_AT.qm
├── de_AT.ts
├── de_CH.qm
├── de_CH.ts
├── de_DE.qm
├── de_DE.ts
├── es.qm
├── es.ts
├── es
│ └── LC_MESSAGES
│ │ ├── everpad.mo
│ │ └── everpad.po
├── ja.qm
├── ja.ts
├── ja
│ └── LC_MESSAGES
│ │ ├── everpad.mo
│ │ └── everpad.po
├── messages.pot
├── nl.qm
├── nl.ts
├── ru
│ └── LC_MESSAGES
│ │ ├── everpad.mo
│ │ └── everpad.po
├── ru_RU.qm
├── ru_RU.ts
├── zh_CN.qm
├── zh_CN.ts
├── zh_CN
│ └── LC_MESSAGES
│ │ ├── everpad.mo
│ │ └── everpad.po
├── zh_TW.qm
├── zh_TW.ts
└── zh_TW
│ └── LC_MESSAGES
│ ├── everpad.mo
│ └── everpad.po
├── scripts
└── install_dbus_services.py
├── setup.cfg
├── setup.py
├── tests
├── __init__.py
├── factories.py
├── pad
│ ├── __init__.py
│ └── test_editor.py
├── provider
│ ├── __init__.py
│ ├── test_service.py
│ └── test_sync.py
├── settings
│ ├── __init__.py
│ ├── ci_local.py
│ └── dist.py
├── test.png
└── test_basetypes.py
└── thrift
├── TSCons.py
├── TSerialization.py
├── Thrift.py
├── __init__.py
├── protocol
├── TBase.py
├── TBinaryProtocol.py
├── TCompactProtocol.py
├── TProtocol.py
├── __init__.py
└── fastbinary.c
├── server
├── THttpServer.py
├── TNonblockingServer.py
├── TProcessPoolServer.py
├── TServer.py
└── __init__.py
└── transport
├── THttpClient.py
├── TSSLSocket.py
├── TSocket.py
├── TTransport.py
├── TTwisted.py
├── TZlibTransport.py
├── __init__.py
└── httpslib.py
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | include = everpad*
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | syntax: glob
2 |
3 | *.swp
4 | *.pyc
5 | *pip-delete-this-directory.txt
6 | /build
7 | /.idea
8 | /dist
9 | *.egg
10 | *.egg-info
11 | tests/settings/local.py
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "2.7"
4 | before_install:
5 | - "export TRAVIS_CI=True"
6 | - "export DISPLAY=:99.0"
7 | - sudo apt-get update -qq
8 | - sudo apt-get install -qq python-pyside python-dbus dbus python-magic
9 | - "sh -e /etc/init.d/xvfb start"
10 | install:
11 | - pip install . --use-mirrors
12 | - pip install -r dev_requirements.txt --use-mirrors
13 | before_script:
14 | - ln -s /usr/lib/python2.7/dist-packages/PySide /home/travis/virtualenv/python2.7/lib/python2.7/site-packages/PySide -v
15 | - ln -s /usr/lib/python2.7/dist-packages/dbus /home/travis/virtualenv/python2.7/lib/python2.7/site-packages/dbus -v
16 | - ln -s /usr/lib/python2.7/dist-packages/_dbus_* /home/travis/virtualenv/python2.7/lib/python2.7/site-packages/ -v
17 | - ln -s /usr/lib/python2.7/dist-packages/magic.py /home/travis/virtualenv/python2.7/lib/python2.7/site-packages/ -v
18 | - cp tests/settings/ci_local.py tests/settings/local.py
19 | - mkdir -p /home/travis/.everpad/data/1/
20 | script:
21 | - nosetests --with-coverage
22 | after_success:
23 | - coverage report
24 | - pip install --quiet python-coveralls
25 | - coveralls
26 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-exclude evernote *.pyc
2 | recursive-exclude everpad *.pyc
3 | recursive-exclude thrift *.pyc
4 | recursive-include everpad *html
5 | recursive-include data *
6 | recursive-include i18n *
7 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Everpad
2 | =======
3 | .. image:: https://travis-ci.org/nvbn/django-bower.png
4 | :alt: Build Status
5 | :target: https://travis-ci.org/nvbn/everpad
6 | .. image:: https://coveralls.io/repos/nvbn/everpad/badge.png?branch=develop
7 | :alt: Coverage Status
8 | :target: https://coveralls.io/r/nvbn/everpad
9 |
10 | Evernote client well integrated with linux desktop.
11 |
12 | .. image:: http://ubuntuone.com/4ABojaepuBiaDVv2VsDB7o
13 |
14 | Client has:
15 | - unity lens
16 | - indicator applet
17 | - unity launcher
18 |
19 | Client support:
20 | - notes
21 | - tags
22 | - notebooks
23 | - resources
24 | - places
25 | - en-* tags
26 |
27 | Security information: The client store notes in a SQLite database and communicates with the Evernote API via Thrift via https.
28 |
29 | Installation
30 | ============
31 | Ubuntu 12.04+ users can use `ppa `_:
32 |
33 | ``sudo add-apt-repository ppa:nvbn-rm/ppa``
34 |
35 | ``sudo apt-get update``
36 |
37 | ``sudo apt-get install everpad``
38 |
39 | If you use gnome shell please `read wiki `_
40 |
41 | You can see more about everpad installation, including method for other linux, in `wiki `_
42 |
43 | Some errors?
44 | ============
45 | `Get debug information `_, check your distributive name and version, check your DE version and post bug report.
46 |
47 | Want to help?
48 | =============
49 | `Write code here `_
50 |
51 | Or create bug reports.
52 |
53 | Or donate:
54 |
55 | - **PayPal**: nvbn.rm@gmail.com
56 | - **Yandex Money**: 410011244953574
57 |
--------------------------------------------------------------------------------
/bin/everpad:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import sys
3 | sys.path.append('/opt/extras.ubuntu.com/everpad/')
4 | from everpad.pad import indicator
5 |
6 |
7 | if __name__ == '__main__':
8 | indicator.main()
9 |
--------------------------------------------------------------------------------
/bin/everpad-lens:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import sys
3 | sys.path.append('/opt/extras.ubuntu.com/everpad/')
4 | from everpad.specific.unity import lens
5 |
6 |
7 | if __name__ == '__main__':
8 | lens.main()
9 |
--------------------------------------------------------------------------------
/bin/everpad-provider:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import sys
3 | sys.path.append('/opt/extras.ubuntu.com/everpad/')
4 | from everpad.provider import daemon
5 |
6 |
7 | if __name__ == '__main__':
8 | daemon.main()
9 |
--------------------------------------------------------------------------------
/data/editor-icons/everpad-checkbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-checkbox.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-insert-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-insert-image.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-insert-table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-insert-table.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-justify-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-justify-center.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-justify-fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-justify-fill.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-justify-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-justify-left.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-justify-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-justify-right.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-link.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-list-ordered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-list-ordered.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-list-unordered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-list-unordered.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-pin.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-share.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-text-bold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-text-bold.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-text-italic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-text-italic.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-text-strikethrough.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-text-strikethrough.png
--------------------------------------------------------------------------------
/data/editor-icons/everpad-text-underline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/editor-icons/everpad-text-underline.png
--------------------------------------------------------------------------------
/data/everpad-app.service:
--------------------------------------------------------------------------------
1 | [D-BUS Service]
2 | Name=com.everpad.App
3 | Exec=/usr/bin/everpad
--------------------------------------------------------------------------------
/data/everpad-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad-black.png
--------------------------------------------------------------------------------
/data/everpad-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad-file.png
--------------------------------------------------------------------------------
/data/everpad-lens.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad-lens.png
--------------------------------------------------------------------------------
/data/everpad-mono.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad-mono.png
--------------------------------------------------------------------------------
/data/everpad-note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad-note.png
--------------------------------------------------------------------------------
/data/everpad-provider.service:
--------------------------------------------------------------------------------
1 | [D-BUS Service]
2 | Name=com.everpad.Provider
3 | Exec=/usr/bin/everpad-provider
--------------------------------------------------------------------------------
/data/everpad.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=0.1
3 | Name=Everpad
4 | GenericName=Everpad
5 | Comment=Evernote client
6 | Comment[ru]=Клиент для Evernote
7 | Exec=everpad %U
8 | Terminal=false
9 | Icon=everpad.png
10 | Type=Application
11 | Categories=Network;
12 | X-Ayatana-Desktop-Shortcuts=NewNote;Settings
13 | MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-gray;image/x-icb;image/x-ico;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-xbitmap;image/x-xpixmap;image/x-pcx;image/svg+xml;image/svg+xml-compressed;image/vnd.wap.wbmp;application/pdf;application/x-bzpdf;application/x-gzpdf;application/x-xzpdf;application/postscript;application/x-bzpostscript;application/x-gzpostscript;image/x-eps;image/x-bzeps;image/x-gzeps;application/x-dvi;application/x-bzdvi;application/x-gzdvi;image/vnd.djvu;image/tiff;application/x-cbr;application/x-cbz;application/x-cb7;application/x-cbt;audio/wav;audio/mpeg;
14 |
15 | [Settings Shortcut Group]
16 | Name=Show all notes
17 | Name[ru]=Все заметки
18 | Exec=everpad --all-notes
19 | TargetEnvironment=Unity
20 |
21 | [NewNote Shortcut Group]
22 | Name=Create Note
23 | Name[ru]=Создать заметку
24 | Exec=everpad --create
25 | TargetEnvironment=Unity
26 |
27 | [Settings Shortcut Group]
28 | Name=Settings and Management
29 | Name[ru]=Настройки и Управление
30 | Exec=everpad --settings
31 | TargetEnvironment=Unity
32 |
--------------------------------------------------------------------------------
/data/everpad.lens:
--------------------------------------------------------------------------------
1 | [Lens]
2 | DBusName=net.launchpad.Unity.Lens.EverpadLens
3 | DBusPath=/net/launchpad/unity/lens/everpad
4 | Name=Everpad
5 | Icon=everpad-lens
6 | Description=Everpad notes lens
7 | SearchHint=Search everpad notes
8 | Shortcut=e
9 |
10 | [Desktop Entry]
11 | X-Ubuntu-Gettext-Domain=unity-lens-everpad
--------------------------------------------------------------------------------
/data/everpad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad.png
--------------------------------------------------------------------------------
/data/everpad.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/data/everpad.xcf
--------------------------------------------------------------------------------
/data/metadata.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Everpad runner
3 | Comment=Find and create notes directly from krunner
4 | Type=Service
5 | Icon=everpad
6 | ServiceTypes=Plasma/Runner
7 | X-Plasma-API=python
8 | X-Plasma-MainScript=code/everpad_runner.py
9 | X-KDE-PluginInfo-Author=Vladimir Iakovlev
10 | X-KDE-PluginInfo-Email=nvbn.rm@gmail.com
11 | X-KDE-PluginInfo-Name=everpad
12 | X-KDE-PluginInfo-Version=1
13 | X-KDE-PluginInfo-Website=https://github.com/nvbn/everpad/
14 | X-KDE-PluginInfo-License=BSD
15 | X-KDE-PluginInfo-EnabledByDefault=true
16 |
--------------------------------------------------------------------------------
/data/plasma-runner-everpad.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Everpad runner
3 | Comment=Find and create notes directly from krunner
4 | Type=Service
5 | Icon=everpad
6 | ServiceTypes=Plasma/Runner
7 | X-Plasma-API=python
8 | X-Plasma-MainScript=code/everpad_runner.py
9 | X-KDE-PluginInfo-Author=Vladimir Iakovlev
10 | X-KDE-PluginInfo-Email=nvbn.rm@gmail.com
11 | X-KDE-PluginInfo-Name=everpad
12 | X-KDE-PluginInfo-Version=1
13 | X-KDE-PluginInfo-Website=https://github.com/nvbn/everpad/
14 | X-KDE-PluginInfo-License=BSD
15 | X-KDE-PluginInfo-EnabledByDefault=true
16 |
--------------------------------------------------------------------------------
/data/unity-lens-everpad.service:
--------------------------------------------------------------------------------
1 | [D-BUS Service]
2 | Name=net.launchpad.Unity.Lens.EverpadLens
3 | Exec=/usr/bin/everpad-lens
--------------------------------------------------------------------------------
/dev_requirements.txt:
--------------------------------------------------------------------------------
1 | mock
2 | factory_boy
3 | sqlalchemy==0.7.9
4 | coverage
5 |
--------------------------------------------------------------------------------
/docs/everpad.1:
--------------------------------------------------------------------------------
1 | .TH EVERPAD "1" "February 20, 2014"
2 | .\" Hey, EMACS: -*- nroff -*-
3 | .\" Process this file with
4 | .\" groff -man -Tascii everpad.1
5 | .\" First parameter, NAME, should be all caps
6 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
7 | .\" other parameters are allowed: see man(7), man(1)
8 | .\"
9 | .\" Please adjust this date whenever revising the manpage.
10 | .\"
11 | .\" Some roff macros, for reference:
12 | .\" .nh disable hyphenation
13 | .\" .hy enable hyphenation
14 | .\" .ad l left justify
15 | .\" .ad b justify to both left and right margins
16 | .\" .nf disable filling
17 | .\" .fi enable filling
18 | .\" .br insert line break
19 | .\" .sp insert n+1 empty lines
20 | .\" for manpage-specific macros, see man(7)
21 | .SH NAME
22 | everpad \- Evernote client for GNU/Linux
23 | .SH SYNOPSIS
24 | \fBeverpad\fP [\-\-open OPEN] [\-\-create] [\-\-all\-notes] [\-\-settings]
25 | .br
26 | [\-\-replace] [\-\-version] [\-h] [attachments [attachments ...]]
27 | .SH DESCRIPTION
28 | .\" TeX users may be more comfortable with the \fB\fP and
29 | .\" \fI\fP escape sequences to invode bold face and italics,
30 | .\" respectively.
31 | \fBeverpad\fP allows to interact with the Evernote service
32 | right from your desktop.
33 | .PP
34 | It supports notes, tags, notebooks, resources, places and en-* tags.
35 | .\" Options section originally created using help2man
36 | .SH OPTIONS
37 | .SS "positional arguments:"
38 | .TP
39 | attachments
40 | attach files to new note
41 | .SS "optional arguments:"
42 | .TP
43 | \fB\-\-open\fR OPEN
44 | open note
45 | .TP
46 | \fB\-\-create\fR
47 | create new note
48 | .TP
49 | \fB\-\-all\-notes\fR
50 | show all notes window
51 | .TP
52 | \fB\-\-settings\fR
53 | settings and management
54 | .TP
55 | \fB\-\-replace\fR
56 | replace already running instance
57 | .TP
58 | \fB\-\-version\fR, \fB\-v\fR
59 | show version
60 | .TP
61 | \fB\-h\fR, \fB\-\-help\fR
62 | show this help message and exit
63 | .SH BUGS
64 | To report a bug, please visit https://github.com/nvbn/everpad/issues and/or report bugs to the Debian Bug Tracking System, as usual.
65 | .SH AUTHOR
66 | everpad was written by Vladimir Iakovlev .
67 | .br
68 | Manpage written for Debian by Emilien Klein .
69 |
--------------------------------------------------------------------------------
/docs/license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2007 Vladimir Yakovlev and Contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/evernote/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/evernote/__init__.py
--------------------------------------------------------------------------------
/evernote/edam/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/evernote/edam/__init__.py
--------------------------------------------------------------------------------
/evernote/edam/error/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['ttypes', 'constants']
2 |
--------------------------------------------------------------------------------
/evernote/edam/error/constants.py:
--------------------------------------------------------------------------------
1 | #
2 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
3 | #
4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | #
6 | # options string: py:new_style
7 | #
8 |
9 | from thrift.Thrift import TType, TMessageType, TException, TApplicationException
10 | from ttypes import *
11 |
12 |
--------------------------------------------------------------------------------
/evernote/edam/limits/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['ttypes', 'constants']
2 |
--------------------------------------------------------------------------------
/evernote/edam/limits/constants.py:
--------------------------------------------------------------------------------
1 | #
2 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
3 | #
4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | #
6 | # options string: py:new_style
7 | #
8 |
9 | from thrift.Thrift import TType, TMessageType, TException, TApplicationException
10 | from ttypes import *
11 |
12 | EDAM_ATTRIBUTE_LEN_MIN = 1
13 | EDAM_ATTRIBUTE_LEN_MAX = 4096
14 | EDAM_ATTRIBUTE_REGEX = "^[^\\p{Cc}\\p{Zl}\\p{Zp}]{1,4096}$"
15 | EDAM_ATTRIBUTE_LIST_MAX = 100
16 | EDAM_ATTRIBUTE_MAP_MAX = 100
17 | EDAM_GUID_LEN_MIN = 36
18 | EDAM_GUID_LEN_MAX = 36
19 | EDAM_GUID_REGEX = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
20 | EDAM_EMAIL_LEN_MIN = 6
21 | EDAM_EMAIL_LEN_MAX = 255
22 | EDAM_EMAIL_LOCAL_REGEX = "^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*$"
23 | EDAM_EMAIL_DOMAIN_REGEX = "^[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*\\.([A-Za-z]{2,})$"
24 | EDAM_EMAIL_REGEX = "^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*\\.([A-Za-z]{2,})$"
25 | EDAM_TIMEZONE_LEN_MIN = 1
26 | EDAM_TIMEZONE_LEN_MAX = 32
27 | EDAM_TIMEZONE_REGEX = "^([A-Za-z_-]+(/[A-Za-z_-]+)*)|(GMT(-|\\+)[0-9]{1,2}(:[0-9]{2})?)$"
28 | EDAM_MIME_LEN_MIN = 3
29 | EDAM_MIME_LEN_MAX = 255
30 | EDAM_MIME_REGEX = "^[A-Za-z]+/[A-Za-z0-9._+-]+$"
31 | EDAM_MIME_TYPE_GIF = "image/gif"
32 | EDAM_MIME_TYPE_JPEG = "image/jpeg"
33 | EDAM_MIME_TYPE_PNG = "image/png"
34 | EDAM_MIME_TYPE_WAV = "audio/wav"
35 | EDAM_MIME_TYPE_MP3 = "audio/mpeg"
36 | EDAM_MIME_TYPE_AMR = "audio/amr"
37 | EDAM_MIME_TYPE_MP4_VIDEO = "video/mp4"
38 | EDAM_MIME_TYPE_INK = "application/vnd.evernote.ink"
39 | EDAM_MIME_TYPE_PDF = "application/pdf"
40 | EDAM_MIME_TYPE_DEFAULT = "application/octet-stream"
41 | EDAM_MIME_TYPES = set([
42 | "image/gif",
43 | "image/jpeg",
44 | "image/png",
45 | "audio/wav",
46 | "audio/mpeg",
47 | "audio/amr",
48 | "application/vnd.evernote.ink",
49 | "application/pdf",
50 | "video/mp4",
51 | ])
52 | EDAM_COMMERCE_SERVICE_GOOGLE = "Google"
53 | EDAM_COMMERCE_SERVICE_PAYPAL = "Paypal"
54 | EDAM_COMMERCE_SERVICE_GIFT = "Gift"
55 | EDAM_COMMERCE_SERVICE_TRIALPAY = "TrialPay"
56 | EDAM_COMMERCE_SERVICE_TRIAL = "Trial"
57 | EDAM_COMMERCE_SERVICE_GROUP = "Group"
58 | EDAM_COMMERCE_SERVICE_CYBERSOURCE = "CYBERSRC"
59 | EDAM_COMMERCE_DEFAULT_CURRENCY_COUNTRY_CODE = "USD"
60 | EDAM_SEARCH_QUERY_LEN_MIN = 0
61 | EDAM_SEARCH_QUERY_LEN_MAX = 1024
62 | EDAM_SEARCH_QUERY_REGEX = "^[^\\p{Cc}\\p{Zl}\\p{Zp}]{0,1024}$"
63 | EDAM_HASH_LEN = 16
64 | EDAM_USER_USERNAME_LEN_MIN = 1
65 | EDAM_USER_USERNAME_LEN_MAX = 64
66 | EDAM_USER_USERNAME_REGEX = "^[a-z0-9]([a-z0-9_-]{0,62}[a-z0-9])?$"
67 | EDAM_USER_NAME_LEN_MIN = 1
68 | EDAM_USER_NAME_LEN_MAX = 255
69 | EDAM_USER_NAME_REGEX = "^[^\\p{Cc}\\p{Zl}\\p{Zp}]{1,255}$"
70 | EDAM_TAG_NAME_LEN_MIN = 1
71 | EDAM_TAG_NAME_LEN_MAX = 100
72 | EDAM_TAG_NAME_REGEX = "^[^,\\p{Cc}\\p{Z}]([^,\\p{Cc}\\p{Zl}\\p{Zp}]{0,98}[^,\\p{Cc}\\p{Z}])?$"
73 | EDAM_NOTE_TITLE_LEN_MIN = 1
74 | EDAM_NOTE_TITLE_LEN_MAX = 255
75 | EDAM_NOTE_TITLE_REGEX = "^[^\\p{Cc}\\p{Z}]([^\\p{Cc}\\p{Zl}\\p{Zp}]{0,253}[^\\p{Cc}\\p{Z}])?$"
76 | EDAM_NOTE_CONTENT_LEN_MIN = 0
77 | EDAM_NOTE_CONTENT_LEN_MAX = 5242880
78 | EDAM_APPLICATIONDATA_NAME_LEN_MIN = 3
79 | EDAM_APPLICATIONDATA_NAME_LEN_MAX = 32
80 | EDAM_APPLICATIONDATA_VALUE_LEN_MIN = 0
81 | EDAM_APPLICATIONDATA_VALUE_LEN_MAX = 4092
82 | EDAM_APPLICATIONDATA_ENTRY_LEN_MAX = 4095
83 | EDAM_APPLICATIONDATA_NAME_REGEX = "^[A-Za-z0-9_.-]{3,32}$"
84 | EDAM_APPLICATIONDATA_VALUE_REGEX = "^[^\\p{Cc}]{0,4092}$"
85 | EDAM_NOTEBOOK_NAME_LEN_MIN = 1
86 | EDAM_NOTEBOOK_NAME_LEN_MAX = 100
87 | EDAM_NOTEBOOK_NAME_REGEX = "^[^\\p{Cc}\\p{Z}]([^\\p{Cc}\\p{Zl}\\p{Zp}]{0,98}[^\\p{Cc}\\p{Z}])?$"
88 | EDAM_NOTEBOOK_STACK_LEN_MIN = 1
89 | EDAM_NOTEBOOK_STACK_LEN_MAX = 100
90 | EDAM_NOTEBOOK_STACK_REGEX = "^[^\\p{Cc}\\p{Z}]([^\\p{Cc}\\p{Zl}\\p{Zp}]{0,98}[^\\p{Cc}\\p{Z}])?$"
91 | EDAM_PUBLISHING_URI_LEN_MIN = 1
92 | EDAM_PUBLISHING_URI_LEN_MAX = 255
93 | EDAM_PUBLISHING_URI_REGEX = "^[a-zA-Z0-9.~_+-]{1,255}$"
94 | EDAM_PUBLISHING_URI_PROHIBITED = set([
95 | "..",
96 | ])
97 | EDAM_PUBLISHING_DESCRIPTION_LEN_MIN = 1
98 | EDAM_PUBLISHING_DESCRIPTION_LEN_MAX = 200
99 | EDAM_PUBLISHING_DESCRIPTION_REGEX = "^[^\\p{Cc}\\p{Z}]([^\\p{Cc}\\p{Zl}\\p{Zp}]{0,198}[^\\p{Cc}\\p{Z}])?$"
100 | EDAM_SAVED_SEARCH_NAME_LEN_MIN = 1
101 | EDAM_SAVED_SEARCH_NAME_LEN_MAX = 100
102 | EDAM_SAVED_SEARCH_NAME_REGEX = "^[^\\p{Cc}\\p{Z}]([^\\p{Cc}\\p{Zl}\\p{Zp}]{0,98}[^\\p{Cc}\\p{Z}])?$"
103 | EDAM_USER_PASSWORD_LEN_MIN = 6
104 | EDAM_USER_PASSWORD_LEN_MAX = 64
105 | EDAM_USER_PASSWORD_REGEX = "^[A-Za-z0-9!#$%&'()*+,./:;<=>?@^_`{|}~\\[\\]\\\\-]{6,64}$"
106 | EDAM_NOTE_TAGS_MAX = 100
107 | EDAM_NOTE_RESOURCES_MAX = 1000
108 | EDAM_USER_TAGS_MAX = 100000
109 | EDAM_USER_SAVED_SEARCHES_MAX = 100
110 | EDAM_USER_NOTES_MAX = 100000
111 | EDAM_USER_NOTEBOOKS_MAX = 250
112 | EDAM_USER_RECENT_MAILED_ADDRESSES_MAX = 10
113 | EDAM_USER_MAIL_LIMIT_DAILY_FREE = 50
114 | EDAM_USER_MAIL_LIMIT_DAILY_PREMIUM = 200
115 | EDAM_USER_UPLOAD_LIMIT_FREE = 62914560
116 | EDAM_USER_UPLOAD_LIMIT_PREMIUM = 1073741824
117 | EDAM_NOTE_SIZE_MAX_FREE = 26214400
118 | EDAM_NOTE_SIZE_MAX_PREMIUM = 52428800
119 | EDAM_RESOURCE_SIZE_MAX_FREE = 26214400
120 | EDAM_RESOURCE_SIZE_MAX_PREMIUM = 52428800
121 | EDAM_USER_LINKED_NOTEBOOK_MAX = 100
122 | EDAM_NOTEBOOK_SHARED_NOTEBOOK_MAX = 250
123 | EDAM_NOTE_CONTENT_CLASS_LEN_MIN = 3
124 | EDAM_NOTE_CONTENT_CLASS_LEN_MAX = 32
125 | EDAM_HELLO_APP_CONTENT_CLASS_PREFIX = "evernote.hello."
126 | EDAM_FOOD_APP_CONTENT_CLASS_PREFIX = "evernote.food."
127 | EDAM_NOTE_CONTENT_CLASS_REGEX = "^[A-Za-z0-9_.-]{3,32}$"
128 | EDAM_CONTENT_CLASS_HELLO_ENCOUNTER = "evernote.hello.encounter"
129 | EDAM_CONTENT_CLASS_HELLO_PROFILE = "evernote.hello.profile"
130 | EDAM_CONTENT_CLASS_FOOD_MEAL = "evernote.food.meal"
131 |
--------------------------------------------------------------------------------
/evernote/edam/limits/ttypes.py:
--------------------------------------------------------------------------------
1 | #
2 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
3 | #
4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | #
6 | # options string: py:new_style
7 | #
8 |
9 | from thrift.Thrift import TType, TMessageType, TException, TApplicationException
10 |
11 | from thrift.transport import TTransport
12 | from thrift.protocol import TBinaryProtocol, TProtocol
13 | try:
14 | from thrift.protocol import fastbinary
15 | except:
16 | fastbinary = None
17 |
18 |
19 |
--------------------------------------------------------------------------------
/evernote/edam/notestore/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['ttypes', 'constants', 'NoteStore']
2 |
--------------------------------------------------------------------------------
/evernote/edam/notestore/constants.py:
--------------------------------------------------------------------------------
1 | #
2 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
3 | #
4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | #
6 | # options string: py:new_style
7 | #
8 |
9 | from thrift.Thrift import TType, TMessageType, TException, TApplicationException
10 | from ttypes import *
11 |
12 |
--------------------------------------------------------------------------------
/evernote/edam/type/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['ttypes', 'constants']
2 |
--------------------------------------------------------------------------------
/evernote/edam/type/constants.py:
--------------------------------------------------------------------------------
1 | #
2 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
3 | #
4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | #
6 | # options string: py:new_style
7 | #
8 |
9 | from thrift.Thrift import TType, TMessageType, TException, TApplicationException
10 | from ttypes import *
11 |
12 | EDAM_NOTE_SOURCE_WEB_CLIP = "web.clip"
13 | EDAM_NOTE_SOURCE_MAIL_CLIP = "mail.clip"
14 | EDAM_NOTE_SOURCE_MAIL_SMTP_GATEWAY = "mail.smtp"
15 |
--------------------------------------------------------------------------------
/evernote/edam/userstore/UserStore-remote:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
4 | #
5 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
6 | #
7 | # options string: py:new_style
8 | #
9 |
10 | import sys
11 | import pprint
12 | from urlparse import urlparse
13 | from thrift.transport import TTransport
14 | from thrift.transport import TSocket
15 | from thrift.transport import THttpClient
16 | from thrift.protocol import TBinaryProtocol
17 |
18 | import UserStore
19 | from ttypes import *
20 |
21 | if len(sys.argv) <= 1 or sys.argv[1] == '--help':
22 | print ''
23 | print 'Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] function [arg1 [arg2...]]'
24 | print ''
25 | print 'Functions:'
26 | print ' bool checkVersion(string clientName, i16 edamVersionMajor, i16 edamVersionMinor)'
27 | print ' BootstrapInfo getBootstrapInfo(string locale)'
28 | print ' AuthenticationResult authenticate(string username, string password, string consumerKey, string consumerSecret)'
29 | print ' AuthenticationResult refreshAuthentication(string authenticationToken)'
30 | print ' User getUser(string authenticationToken)'
31 | print ' PublicUserInfo getPublicUserInfo(string username)'
32 | print ' PremiumInfo getPremiumInfo(string authenticationToken)'
33 | print ' string getNoteStoreUrl(string authenticationToken)'
34 | print ''
35 | sys.exit(0)
36 |
37 | pp = pprint.PrettyPrinter(indent = 2)
38 | host = 'localhost'
39 | port = 9090
40 | uri = ''
41 | framed = False
42 | http = False
43 | argi = 1
44 |
45 | if sys.argv[argi] == '-h':
46 | parts = sys.argv[argi+1].split(':')
47 | host = parts[0]
48 | if len(parts) > 1:
49 | port = int(parts[1])
50 | argi += 2
51 |
52 | if sys.argv[argi] == '-u':
53 | url = urlparse(sys.argv[argi+1])
54 | parts = url[1].split(':')
55 | host = parts[0]
56 | if len(parts) > 1:
57 | port = int(parts[1])
58 | else:
59 | port = 80
60 | uri = url[2]
61 | if url[4]:
62 | uri += '?%s' % url[4]
63 | http = True
64 | argi += 2
65 |
66 | if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':
67 | framed = True
68 | argi += 1
69 |
70 | cmd = sys.argv[argi]
71 | args = sys.argv[argi+1:]
72 |
73 | if http:
74 | transport = THttpClient.THttpClient(host, port, uri)
75 | else:
76 | socket = TSocket.TSocket(host, port)
77 | if framed:
78 | transport = TTransport.TFramedTransport(socket)
79 | else:
80 | transport = TTransport.TBufferedTransport(socket)
81 | protocol = TBinaryProtocol.TBinaryProtocol(transport)
82 | client = UserStore.Client(protocol)
83 | transport.open()
84 |
85 | if cmd == 'checkVersion':
86 | if len(args) != 3:
87 | print 'checkVersion requires 3 args'
88 | sys.exit(1)
89 | pp.pprint(client.checkVersion(args[0],eval(args[1]),eval(args[2]),))
90 |
91 | elif cmd == 'getBootstrapInfo':
92 | if len(args) != 1:
93 | print 'getBootstrapInfo requires 1 args'
94 | sys.exit(1)
95 | pp.pprint(client.getBootstrapInfo(args[0],))
96 |
97 | elif cmd == 'authenticate':
98 | if len(args) != 4:
99 | print 'authenticate requires 4 args'
100 | sys.exit(1)
101 | pp.pprint(client.authenticate(args[0],args[1],args[2],args[3],))
102 |
103 | elif cmd == 'refreshAuthentication':
104 | if len(args) != 1:
105 | print 'refreshAuthentication requires 1 args'
106 | sys.exit(1)
107 | pp.pprint(client.refreshAuthentication(args[0],))
108 |
109 | elif cmd == 'getUser':
110 | if len(args) != 1:
111 | print 'getUser requires 1 args'
112 | sys.exit(1)
113 | pp.pprint(client.getUser(args[0],))
114 |
115 | elif cmd == 'getPublicUserInfo':
116 | if len(args) != 1:
117 | print 'getPublicUserInfo requires 1 args'
118 | sys.exit(1)
119 | pp.pprint(client.getPublicUserInfo(args[0],))
120 |
121 | elif cmd == 'getPremiumInfo':
122 | if len(args) != 1:
123 | print 'getPremiumInfo requires 1 args'
124 | sys.exit(1)
125 | pp.pprint(client.getPremiumInfo(args[0],))
126 |
127 | elif cmd == 'getNoteStoreUrl':
128 | if len(args) != 1:
129 | print 'getNoteStoreUrl requires 1 args'
130 | sys.exit(1)
131 | pp.pprint(client.getNoteStoreUrl(args[0],))
132 |
133 | else:
134 | print 'Unrecognized method %s' % cmd
135 | sys.exit(1)
136 |
137 | transport.close()
138 |
--------------------------------------------------------------------------------
/evernote/edam/userstore/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['ttypes', 'constants', 'UserStore']
2 |
--------------------------------------------------------------------------------
/evernote/edam/userstore/constants.py:
--------------------------------------------------------------------------------
1 | #
2 | # Autogenerated by Thrift Compiler (0.5.0-en-262021)
3 | #
4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | #
6 | # options string: py:new_style
7 | #
8 |
9 | from thrift.Thrift import TType, TMessageType, TException, TApplicationException
10 | from ttypes import *
11 |
12 | EDAM_VERSION_MAJOR = 1
13 | EDAM_VERSION_MINOR = 21
14 |
--------------------------------------------------------------------------------
/everpad.pro:
--------------------------------------------------------------------------------
1 | SOURCES = everpad/tools.py \
2 | everpad/__init__.py \
3 | everpad/specific/kde/__init__.py \
4 | everpad/specific/kde/everpad_runner.py \
5 | everpad/specific/__init__.py \
6 | everpad/specific/unity/__init__.py \
7 | everpad/specific/unity/launcher.py \
8 | everpad/specific/unity/lens.py \
9 | everpad/basetypes.py \
10 | everpad/pad/tools.py \
11 | everpad/pad/list.py \
12 | everpad/pad/__init__.py \
13 | everpad/pad/treeview.py \
14 | everpad/pad/editor/widgets.py \
15 | everpad/pad/editor/actions.py \
16 | everpad/pad/editor/__init__.py \
17 | everpad/pad/editor/resources.py \
18 | everpad/pad/editor/content.py \
19 | everpad/pad/indicator.py \
20 | everpad/pad/management.py \
21 | everpad/const.py \
22 | everpad/provider/tools.py \
23 | everpad/provider/daemon.py \
24 | everpad/provider/__init__.py \
25 | everpad/provider/models.py \
26 | everpad/provider/sync.py \
27 | everpad/provider/service.py \
28 | everpad/interface/list.py \
29 | everpad/interface/__init__.py \
30 | everpad/interface/notebook.py \
31 | everpad/interface/editor.py \
32 | everpad/interface/findbar.py \
33 | everpad/interface/tableinsert.py \
34 | everpad/interface/image.py \
35 | everpad/interface/management.py \
36 | everpad/monkey.py
37 |
38 | TRANSLATIONS = i18n/ru_RU.ts \
39 | i18n/ar_EG.ts \
40 | i18n/zh_CN.ts \
41 | i18n/zh_TW.ts \
42 | i18n/ja.ts \
43 | i18n/nl.ts \
44 | i18n/de_DE.ts \
45 | i18n/de_AT.ts \
46 | i18n/de_CH.ts
47 |
48 |
--------------------------------------------------------------------------------
/everpad/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/everpad/__init__.py
--------------------------------------------------------------------------------
/everpad/basetypes.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.orm.exc import NoResultFound
2 |
3 |
4 | NONE_ID = 0
5 | NONE_VAL = 0
6 |
7 |
8 | class DbusSendableList(object):
9 | """Dbus sendable list"""
10 |
11 | def __init__(self, cls):
12 | self._cls = cls
13 |
14 | def __rshift__(self, other):
15 | """Shortcut to from_obj and struct"""
16 | return [self._cls.from_obj(item).struct for item in other]
17 |
18 | def __lshift__(self, other):
19 | """Shortcut to from_tuple"""
20 | return [self._cls.from_tuple(item) for item in other]
21 |
22 |
23 | class BaseDbusSendable(type):
24 | @property
25 | def signature(cls):
26 | return '(' + ''.join(map(
27 | lambda field: field[1],
28 | cls.fields,
29 | )) + ')'
30 |
31 | def __rshift__(cls, other):
32 | """Shortcut to from_obj and struct"""
33 | return cls.from_obj(other).struct
34 |
35 | def __lshift__(cls, other):
36 | """Shortcut to from_tuple"""
37 | return cls.from_tuple(other)
38 |
39 | @property
40 | def list(cls):
41 | """Return shortcut for list mapping"""
42 | return DbusSendableList(cls)
43 |
44 |
45 | class DbusSendable(object):
46 | __metaclass__ = BaseDbusSendable
47 | fields = tuple()
48 |
49 | def __init__(self, **kwargs):
50 | for key, val in kwargs.items():
51 | setattr(self, key, val)
52 |
53 | @classmethod
54 | def from_obj(cls, data):
55 | inst = cls()
56 | for field in cls.fields:
57 | if hasattr(data, field[0] + '_dbus'):
58 | val = getattr(data, field[0] + '_dbus')
59 | else:
60 | val = getattr(data, field[0], None)
61 | if hasattr(val, '__call__'):
62 | val = val()
63 | setattr(inst, field[0], val)
64 | return inst
65 |
66 | @classmethod
67 | def from_tuple(cls, data):
68 | inst = cls()
69 | for num, field in enumerate(cls.fields):
70 | setattr(inst, field[0], data[num])
71 | return inst
72 |
73 | @property
74 | def struct(self):
75 | result = []
76 | for field in self.fields:
77 | result.append(getattr(self, field[0], None))
78 | return tuple(result)
79 |
80 | def give_to_obj(self, obj):
81 | for field in self.fields:
82 | val = getattr(self, field[0])
83 | try:
84 | # check exists, hasattr fails with fresh sqlalchemy
85 | # with object has no attribute '_sa_instance_state'
86 | try:
87 | getattr(obj, field[0] + '_dbus')
88 | except NoResultFound:
89 | # pass when fields is one-to-one relation
90 | pass
91 |
92 | setattr(obj, field[0] + '_dbus', val)
93 | except AttributeError:
94 | setattr(obj, field[0], val)
95 |
96 | def __repr__(self):
97 | return "<%s:\n%s>" % (
98 | type(self).__name__,
99 | "\n".join(map(
100 | lambda field: '%s: %s' % (
101 | field[0], str(getattr(self, field[0], '')),
102 | ), self.fields,
103 | ))
104 | )
105 |
106 |
107 | class Note(DbusSendable):
108 | ORDER_TITLE = 0
109 | ORDER_UPDATED = 1
110 | ORDER_TITLE_DESC = 2
111 | ORDER_UPDATED_DESC = 3
112 |
113 | fields = (
114 | ('id', 'i'),
115 | ('title', 's'),
116 | ('content', 's'),
117 | ('created', 'x'),
118 | ('updated', 'x'),
119 | ('notebook', 'i'),
120 | ('tags', 'as'),
121 | ('place', 's'),
122 | ('pinnded', 'b'),
123 | ('conflict_parent', 'i'),
124 | ('conflict_items', 'ai'),
125 | ('share_date', 'x'),
126 | ('share_url', 's'),
127 | )
128 |
129 |
130 | class Notebook(DbusSendable):
131 | fields = (
132 | ('id', 'i'),
133 | ('name', 's'),
134 | ('default', 'i'),
135 | ('stack', 's')
136 | )
137 |
138 |
139 | class Tag(DbusSendable):
140 | fields = (
141 | ('id', 'i'),
142 | ('name', 's'),
143 | )
144 |
145 |
146 | class Resource(DbusSendable):
147 | fields = (
148 | ('id', 'i'),
149 | ('file_name', 's'),
150 | ('file_path', 's'),
151 | ('mime', 's'),
152 | ('hash', 's'),
153 | )
154 |
155 |
156 | class Place(DbusSendable):
157 | fields = (
158 | ('id', 'i'),
159 | ('name', 's'),
160 | )
161 |
--------------------------------------------------------------------------------
/everpad/const.py:
--------------------------------------------------------------------------------
1 | CONSUMER_KEY = 'nvbn-1422'
2 | CONSUMER_SECRET = 'c17c0979d0054310'
3 | HOST = 'www.evernote.com'
4 | STATUS_NONE = 0
5 | STATUS_SYNC = 1
6 | DEFAULT_SYNC_DELAY = 30000 * 60
7 | SYNC_STATE_START = 0
8 | SYNC_STATE_NOTEBOOKS_LOCAL = 1
9 | SYNC_STATE_TAGS_LOCAL = 2
10 | SYNC_STATE_NOTES_LOCAL = 3
11 | SYNC_STATE_NOTEBOOKS_REMOTE = 4
12 | SYNC_STATE_TAGS_REMOTE = 5
13 | SYNC_STATE_NOTES_REMOTE = 6
14 | SYNC_STATE_SHARE = 7
15 | SYNC_STATE_STOP_SHARE = 8
16 | SYNC_STATE_FINISH = 9
17 | SYNC_MANUAL = -1
18 | SYNC_STATES = (
19 | SYNC_STATE_START, SYNC_STATE_NOTEBOOKS_LOCAL,
20 | SYNC_STATE_TAGS_LOCAL, SYNC_STATE_NOTES_LOCAL,
21 | SYNC_STATE_NOTEBOOKS_REMOTE, SYNC_STATE_TAGS_REMOTE,
22 | SYNC_STATE_NOTES_REMOTE, SYNC_STATE_FINISH,
23 | )
24 | DEFAULT_FONT = 'Sans'
25 | DEFAULT_FONT_SIZE = 14
26 | DEFAULT_INDICATOR_LAYOUT = [
27 | 'create_note', 'pin_notes', 'notes', 'all_notes', 'sync',
28 | ]
29 |
30 | SCHEMA_VERSION = 5
31 | API_VERSION = 6
32 | VERSION = '2.5'
33 | DB_PATH = "~/.everpad/everpad.%s.db" % SCHEMA_VERSION
34 |
35 | ACTION_NONE = 0
36 | ACTION_CREATE = 1
37 | ACTION_DELETE = 2
38 | ACTION_CHANGE = 3
39 | ACTION_NOEXSIST = 4
40 | ACTION_CONFLICT = 5
41 | ACTION_DUPLICATE = 6
42 |
43 | DISABLED_ACTIONS = (ACTION_DELETE, ACTION_NOEXSIST, ACTION_CONFLICT)
44 |
45 | SHARE_NONE = 0
46 | SHARE_NEED_SHARE = 1
47 | SHARE_SHARED = 2
48 | SHARE_NEED_STOP = 3
49 |
50 | NONE_ID = 0
51 | NONE_VAL = 0
52 |
53 | ORDER_TITLE = 0
54 | ORDER_UPDATED = 1
55 | ORDER_TITLE_DESC = 2
56 | ORDER_UPDATED_DESC = 3
57 |
58 | DEFAULT_LIMIT = 100
59 | NOT_PINNDED = -1
60 |
--------------------------------------------------------------------------------
/everpad/interface/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/everpad/interface/__init__.py
--------------------------------------------------------------------------------
/everpad/interface/editor.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Editor
4 |
5 |
6 |
7 | 0
8 | 0
9 | 565
10 | 381
11 |
12 |
13 |
14 | Everpad
15 |
16 |
17 |
18 | -
19 |
20 |
-
21 |
22 |
23 |
24 | 0
25 | 0
26 |
27 |
28 |
29 |
30 | about:blank
31 |
32 |
33 |
34 |
35 |
36 |
37 | -
38 |
39 |
-
40 |
41 |
42 | Select notebook
43 |
44 |
45 |
46 | -
47 |
48 |
49 | Note tags
50 |
51 |
52 | Commas separated tags
53 |
54 |
55 |
56 |
57 |
58 | -
59 |
60 |
61 | %d attached files, <a href='#'>show</a> / <a href='#'> add another</a>
62 |
63 |
64 | Qt::AutoText
65 |
66 |
67 |
68 | -
69 |
70 |
71 | This note has alternative versions: %s
72 |
73 |
74 | true
75 |
76 |
77 |
78 | -
79 |
80 |
81 |
82 | 0
83 | 0
84 |
85 |
86 |
87 | Qt::ScrollBarAlwaysOff
88 |
89 |
90 | Qt::ScrollBarAsNeeded
91 |
92 |
93 | true
94 |
95 |
96 |
97 |
98 | 0
99 | 0
100 | 545
101 | 76
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | toolBar
112 |
113 |
114 | false
115 |
116 |
117 | TopToolBarArea
118 |
119 |
120 | false
121 |
122 |
123 |
152 |
153 |
154 | Save
155 |
156 |
157 |
158 |
159 | Save and close
160 |
161 |
162 |
163 |
164 | Delete
165 |
166 |
167 |
168 |
169 | Close
170 |
171 |
172 |
173 |
174 | Cut
175 |
176 |
177 |
178 |
179 | Copy
180 |
181 |
182 |
183 |
184 | Paste
185 |
186 |
187 |
188 |
189 | Find
190 |
191 |
192 |
193 |
194 |
195 | QWebView
196 | QWidget
197 |
198 |
199 |
200 |
201 |
202 |
203 |
--------------------------------------------------------------------------------
/everpad/interface/findbar.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'everpad/interface/findbar.ui'
4 | #
5 | # Created: Sun Oct 21 07:01:56 2012
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.0
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_FindBar(object):
13 | def setupUi(self, FindBar):
14 | FindBar.setObjectName("FindBar")
15 | FindBar.resize(750, 33)
16 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)
17 | sizePolicy.setHorizontalStretch(0)
18 | sizePolicy.setVerticalStretch(0)
19 | sizePolicy.setHeightForWidth(FindBar.sizePolicy().hasHeightForWidth())
20 | FindBar.setSizePolicy(sizePolicy)
21 | self.horizontalLayout = QtGui.QHBoxLayout(FindBar)
22 | self.horizontalLayout.setContentsMargins(3, 3, 3, 3)
23 | self.horizontalLayout.setObjectName("horizontalLayout")
24 | self.btnClose = QtGui.QPushButton(FindBar)
25 | self.btnClose.setText("")
26 | icon = QtGui.QIcon()
27 | icon.addPixmap(QtGui.QPixmap("../../../../.designer/backup"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
28 | self.btnClose.setIcon(icon)
29 | self.btnClose.setObjectName("btnClose")
30 | self.horizontalLayout.addWidget(self.btnClose)
31 | self.lblFind = QtGui.QLabel(FindBar)
32 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
33 | sizePolicy.setHorizontalStretch(0)
34 | sizePolicy.setVerticalStretch(0)
35 | sizePolicy.setHeightForWidth(self.lblFind.sizePolicy().hasHeightForWidth())
36 | self.lblFind.setSizePolicy(sizePolicy)
37 | self.lblFind.setObjectName("lblFind")
38 | self.horizontalLayout.addWidget(self.lblFind)
39 | self.edtFindText = QtGui.QLineEdit(FindBar)
40 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
41 | sizePolicy.setHorizontalStretch(0)
42 | sizePolicy.setVerticalStretch(0)
43 | sizePolicy.setHeightForWidth(self.edtFindText.sizePolicy().hasHeightForWidth())
44 | self.edtFindText.setSizePolicy(sizePolicy)
45 | self.edtFindText.setMinimumSize(QtCore.QSize(240, 0))
46 | self.edtFindText.setObjectName("edtFindText")
47 | self.horizontalLayout.addWidget(self.edtFindText)
48 | self.btnPrevious = QtGui.QPushButton(FindBar)
49 | icon1 = QtGui.QIcon()
50 | icon1.addPixmap(QtGui.QPixmap("../../../../../../.designer/backup"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
51 | self.btnPrevious.setIcon(icon1)
52 | self.btnPrevious.setObjectName("btnPrevious")
53 | self.horizontalLayout.addWidget(self.btnPrevious)
54 | self.btnNext = QtGui.QPushButton(FindBar)
55 | self.btnNext.setIcon(icon1)
56 | self.btnNext.setObjectName("btnNext")
57 | self.horizontalLayout.addWidget(self.btnNext)
58 | self.btnHighlight = QtGui.QPushButton(FindBar)
59 | self.btnHighlight.setCheckable(True)
60 | self.btnHighlight.setObjectName("btnHighlight")
61 | self.horizontalLayout.addWidget(self.btnHighlight)
62 | self.chkMatchCase = QtGui.QCheckBox(FindBar)
63 | self.chkMatchCase.setObjectName("chkMatchCase")
64 | self.horizontalLayout.addWidget(self.chkMatchCase)
65 | spacerItem = QtGui.QSpacerItem(0, 0, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
66 | self.horizontalLayout.addItem(spacerItem)
67 |
68 | self.retranslateUi(FindBar)
69 | QtCore.QMetaObject.connectSlotsByName(FindBar)
70 |
71 | def retranslateUi(self, FindBar):
72 | FindBar.setWindowTitle(QtGui.QApplication.translate("FindBar", "Form", None, QtGui.QApplication.UnicodeUTF8))
73 | self.lblFind.setText(QtGui.QApplication.translate("FindBar", "Find:", None, QtGui.QApplication.UnicodeUTF8))
74 | self.btnPrevious.setText(QtGui.QApplication.translate("FindBar", "Previous", None, QtGui.QApplication.UnicodeUTF8))
75 | self.btnNext.setText(QtGui.QApplication.translate("FindBar", "Next", None, QtGui.QApplication.UnicodeUTF8))
76 | self.btnHighlight.setText(QtGui.QApplication.translate("FindBar", "Highlight All", None, QtGui.QApplication.UnicodeUTF8))
77 | self.chkMatchCase.setText(QtGui.QApplication.translate("FindBar", "Match Case", None, QtGui.QApplication.UnicodeUTF8))
78 |
79 |
--------------------------------------------------------------------------------
/everpad/interface/findbar.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | FindBar
4 |
5 |
6 |
7 | 0
8 | 0
9 | 750
10 | 33
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 | Form
21 |
22 |
23 |
24 | 3
25 |
26 | -
27 |
28 |
29 |
30 |
31 |
32 |
33 | ../../../../.designer/backup../../../../.designer/backup
34 |
35 |
36 |
37 | -
38 |
39 |
40 |
41 | 0
42 | 0
43 |
44 |
45 |
46 | Find:
47 |
48 |
49 |
50 | -
51 |
52 |
53 |
54 | 0
55 | 0
56 |
57 |
58 |
59 |
60 | 240
61 | 0
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 | Previous
70 |
71 |
72 |
73 | ../../../../../../.designer/backup../../../../../../.designer/backup
74 |
75 |
76 |
77 | -
78 |
79 |
80 | Next
81 |
82 |
83 |
84 | ../../../../../../.designer/backup../../../../../../.designer/backup
85 |
86 |
87 |
88 | -
89 |
90 |
91 | Highlight All
92 |
93 |
94 | true
95 |
96 |
97 |
98 | -
99 |
100 |
101 | Match Case
102 |
103 |
104 |
105 | -
106 |
107 |
108 | Qt::Horizontal
109 |
110 |
111 |
112 | 0
113 | 0
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/everpad/interface/image.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'image.ui'
4 | #
5 | # Created: Sat Sep 29 16:13:53 2012
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.0
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_ImageDialog(object):
13 | def setupUi(self, ImageDialog):
14 | ImageDialog.setObjectName("ImageDialog")
15 | ImageDialog.setWindowModality(QtCore.Qt.WindowModal)
16 | ImageDialog.resize(248, 164)
17 | ImageDialog.setModal(True)
18 | self.gridLayout = QtGui.QGridLayout(ImageDialog)
19 | self.gridLayout.setObjectName("gridLayout")
20 | self.label = QtGui.QLabel(ImageDialog)
21 | self.label.setObjectName("label")
22 | self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
23 | self.widthBox = QtGui.QSpinBox(ImageDialog)
24 | self.widthBox.setMinimum(1)
25 | self.widthBox.setMaximum(99999)
26 | self.widthBox.setObjectName("widthBox")
27 | self.gridLayout.addWidget(self.widthBox, 0, 1, 1, 1)
28 | self.label_2 = QtGui.QLabel(ImageDialog)
29 | self.label_2.setObjectName("label_2")
30 | self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
31 | self.heightBox = QtGui.QSpinBox(ImageDialog)
32 | self.heightBox.setMinimum(1)
33 | self.heightBox.setMaximum(99999)
34 | self.heightBox.setObjectName("heightBox")
35 | self.gridLayout.addWidget(self.heightBox, 1, 1, 1, 1)
36 | self.checkBox = QtGui.QCheckBox(ImageDialog)
37 | self.checkBox.setChecked(True)
38 | self.checkBox.setObjectName("checkBox")
39 | self.gridLayout.addWidget(self.checkBox, 2, 0, 1, 2)
40 | self.buttonBox = QtGui.QDialogButtonBox(ImageDialog)
41 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
42 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
43 | self.buttonBox.setObjectName("buttonBox")
44 | self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2)
45 |
46 | self.retranslateUi(ImageDialog)
47 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), ImageDialog.accept)
48 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), ImageDialog.reject)
49 | QtCore.QMetaObject.connectSlotsByName(ImageDialog)
50 |
51 | def retranslateUi(self, ImageDialog):
52 | ImageDialog.setWindowTitle(QtGui.QApplication.translate("ImageDialog", "Everpad / Image Preferences", None, QtGui.QApplication.UnicodeUTF8))
53 | self.label.setText(QtGui.QApplication.translate("ImageDialog", "Width", None, QtGui.QApplication.UnicodeUTF8))
54 | self.label_2.setText(QtGui.QApplication.translate("ImageDialog", "Height", None, QtGui.QApplication.UnicodeUTF8))
55 | self.checkBox.setText(QtGui.QApplication.translate("ImageDialog", "Discard ratio", None, QtGui.QApplication.UnicodeUTF8))
56 |
57 |
--------------------------------------------------------------------------------
/everpad/interface/image.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ImageDialog
4 |
5 |
6 | Qt::WindowModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 248
13 | 164
14 |
15 |
16 |
17 | Everpad / Image Preferences
18 |
19 |
20 | true
21 |
22 |
23 | -
24 |
25 |
26 | Width
27 |
28 |
29 |
30 | -
31 |
32 |
33 | 1
34 |
35 |
36 | 99999
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Height
44 |
45 |
46 |
47 | -
48 |
49 |
50 | 1
51 |
52 |
53 | 99999
54 |
55 |
56 |
57 | -
58 |
59 |
60 | Discard ratio
61 |
62 |
63 | true
64 |
65 |
66 |
67 | -
68 |
69 |
70 | Qt::Horizontal
71 |
72 |
73 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | buttonBox
83 | accepted()
84 | ImageDialog
85 | accept()
86 |
87 |
88 | 248
89 | 254
90 |
91 |
92 | 157
93 | 274
94 |
95 |
96 |
97 |
98 | buttonBox
99 | rejected()
100 | ImageDialog
101 | reject()
102 |
103 |
104 | 316
105 | 260
106 |
107 |
108 | 286
109 | 274
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/everpad/interface/list.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'list.ui'
4 | #
5 | # Created: Sun Feb 24 10:42:09 2013
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.1
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_List(object):
13 | def setupUi(self, List):
14 | List.setObjectName("List")
15 | List.resize(800, 600)
16 | self.centralwidget = QtGui.QWidget(List)
17 | self.centralwidget.setObjectName("centralwidget")
18 | self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
19 | self.horizontalLayout.setObjectName("horizontalLayout")
20 | self.splitter = QtGui.QSplitter(self.centralwidget)
21 | self.splitter.setOrientation(QtCore.Qt.Horizontal)
22 | self.splitter.setChildrenCollapsible(False)
23 | self.splitter.setObjectName("splitter")
24 | self.layoutWidget = QtGui.QWidget(self.splitter)
25 | self.layoutWidget.setObjectName("layoutWidget")
26 | self.verticalLayout_2 = QtGui.QVBoxLayout(self.layoutWidget)
27 | self.verticalLayout_2.setSizeConstraint(QtGui.QLayout.SetMinimumSize)
28 | self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
29 | self.verticalLayout_2.setObjectName("verticalLayout_2")
30 | self.horizontalLayout_2 = QtGui.QHBoxLayout()
31 | self.horizontalLayout_2.setSizeConstraint(QtGui.QLayout.SetMinimumSize)
32 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
33 | self.newNotebookBtn = QtGui.QPushButton(self.layoutWidget)
34 | self.newNotebookBtn.setObjectName("newNotebookBtn")
35 | self.horizontalLayout_2.addWidget(self.newNotebookBtn)
36 | self.newNoteBtn = QtGui.QPushButton(self.layoutWidget)
37 | self.newNoteBtn.setObjectName("newNoteBtn")
38 | self.horizontalLayout_2.addWidget(self.newNoteBtn)
39 | self.verticalLayout_2.addLayout(self.horizontalLayout_2)
40 | self.notebooksList = EverpadTreeView(self.layoutWidget)
41 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
42 | sizePolicy.setHorizontalStretch(0)
43 | sizePolicy.setVerticalStretch(0)
44 | sizePolicy.setHeightForWidth(self.notebooksList.sizePolicy().hasHeightForWidth())
45 | self.notebooksList.setSizePolicy(sizePolicy)
46 | self.notebooksList.setMinimumSize(QtCore.QSize(200, 0))
47 | self.notebooksList.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
48 | self.notebooksList.setHeaderHidden(True)
49 | self.notebooksList.setObjectName("notebooksList")
50 | self.verticalLayout_2.addWidget(self.notebooksList)
51 | self.tagsList = EverpadTreeView(self.layoutWidget)
52 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
53 | sizePolicy.setHorizontalStretch(0)
54 | sizePolicy.setVerticalStretch(0)
55 | sizePolicy.setHeightForWidth(self.tagsList.sizePolicy().hasHeightForWidth())
56 | self.tagsList.setSizePolicy(sizePolicy)
57 | self.tagsList.setMinimumSize(QtCore.QSize(200, 0))
58 | self.tagsList.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
59 | self.tagsList.setHeaderHidden(True)
60 | self.tagsList.setObjectName("tagsList")
61 | self.verticalLayout_2.addWidget(self.tagsList)
62 | self.notesList = EverpadTreeView(self.splitter)
63 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
64 | sizePolicy.setHorizontalStretch(1)
65 | sizePolicy.setVerticalStretch(0)
66 | sizePolicy.setHeightForWidth(self.notesList.sizePolicy().hasHeightForWidth())
67 | self.notesList.setSizePolicy(sizePolicy)
68 | self.notesList.setMinimumSize(QtCore.QSize(300, 0))
69 | self.notesList.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
70 | self.notesList.setSortingEnabled(True)
71 | self.notesList.setObjectName("notesList")
72 | self.notesList.header().setDefaultSectionSize(200)
73 | self.notesList.header().setSortIndicatorShown(True)
74 | self.horizontalLayout.addWidget(self.splitter)
75 | List.setCentralWidget(self.centralwidget)
76 | self.menubar = QtGui.QMenuBar(List)
77 | self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 25))
78 | self.menubar.setObjectName("menubar")
79 | List.setMenuBar(self.menubar)
80 | self.statusbar = QtGui.QStatusBar(List)
81 | self.statusbar.setObjectName("statusbar")
82 | List.setStatusBar(self.statusbar)
83 |
84 | self.retranslateUi(List)
85 | QtCore.QMetaObject.connectSlotsByName(List)
86 |
87 | def retranslateUi(self, List):
88 | List.setWindowTitle(QtGui.QApplication.translate("List", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
89 | self.newNotebookBtn.setToolTip(QtGui.QApplication.translate("List", "Create Notebook", None, QtGui.QApplication.UnicodeUTF8))
90 | self.newNotebookBtn.setText(QtGui.QApplication.translate("List", "Notebook", None, QtGui.QApplication.UnicodeUTF8))
91 | self.newNoteBtn.setToolTip(QtGui.QApplication.translate("List", "Create Note", None, QtGui.QApplication.UnicodeUTF8))
92 | self.newNoteBtn.setText(QtGui.QApplication.translate("List", "Note", None, QtGui.QApplication.UnicodeUTF8))
93 |
94 | from everpad.pad.treeview import EverpadTreeView
95 |
--------------------------------------------------------------------------------
/everpad/interface/list.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | List
4 |
5 |
6 |
7 | 0
8 | 0
9 | 800
10 | 600
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Qt::Horizontal
22 |
23 |
24 | false
25 |
26 |
27 |
28 |
29 | QLayout::SetMinimumSize
30 |
31 |
-
32 |
33 |
34 | QLayout::SetMinimumSize
35 |
36 |
-
37 |
38 |
39 | Create Notebook
40 |
41 |
42 | Notebook
43 |
44 |
45 |
46 | -
47 |
48 |
49 | Create Note
50 |
51 |
52 | Note
53 |
54 |
55 |
56 |
57 |
58 | -
59 |
60 |
61 |
62 | 0
63 | 0
64 |
65 |
66 |
67 |
68 | 200
69 | 0
70 |
71 |
72 |
73 | QAbstractItemView::NoEditTriggers
74 |
75 |
76 | true
77 |
78 |
79 |
80 | -
81 |
82 |
83 |
84 | 0
85 | 0
86 |
87 |
88 |
89 |
90 | 200
91 | 0
92 |
93 |
94 |
95 | QAbstractItemView::NoEditTriggers
96 |
97 |
98 | true
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | 1
108 | 0
109 |
110 |
111 |
112 |
113 | 300
114 | 0
115 |
116 |
117 |
118 | QAbstractItemView::NoEditTriggers
119 |
120 |
121 | true
122 |
123 |
124 | 200
125 |
126 |
127 | true
128 |
129 |
130 |
131 |
132 |
133 |
134 |
144 |
145 |
146 |
147 |
148 | EverpadTreeView
149 | QTreeView
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/everpad/interface/notebook.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'notebook.ui'
4 | #
5 | # Created: Sun Aug 19 18:09:52 2012
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.0
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_Notebook(object):
13 | def setupUi(self, Notebook):
14 | Notebook.setObjectName("Notebook")
15 | Notebook.resize(296, 60)
16 | self.horizontalLayout = QtGui.QHBoxLayout(Notebook)
17 | self.horizontalLayout.setObjectName("horizontalLayout")
18 | self.verticalLayout = QtGui.QVBoxLayout()
19 | self.verticalLayout.setObjectName("verticalLayout")
20 | self.name = QtGui.QLabel(Notebook)
21 | font = QtGui.QFont()
22 | font.setWeight(75)
23 | font.setBold(True)
24 | self.name.setFont(font)
25 | self.name.setObjectName("name")
26 | self.verticalLayout.addWidget(self.name)
27 | self.content = QtGui.QLabel(Notebook)
28 | font = QtGui.QFont()
29 | font.setWeight(50)
30 | font.setBold(False)
31 | self.content.setFont(font)
32 | self.content.setObjectName("content")
33 | self.verticalLayout.addWidget(self.content)
34 | self.horizontalLayout.addLayout(self.verticalLayout)
35 | spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
36 | self.horizontalLayout.addItem(spacerItem)
37 | self.actionBtn = QtGui.QPushButton(Notebook)
38 | self.actionBtn.setText("")
39 | self.actionBtn.setObjectName("actionBtn")
40 | self.horizontalLayout.addWidget(self.actionBtn)
41 |
42 | self.retranslateUi(Notebook)
43 | QtCore.QMetaObject.connectSlotsByName(Notebook)
44 |
45 | def retranslateUi(self, Notebook):
46 | Notebook.setWindowTitle(QtGui.QApplication.translate("Notebook", "Form", None, QtGui.QApplication.UnicodeUTF8))
47 | self.name.setText(QtGui.QApplication.translate("Notebook", "Notebook name", None, QtGui.QApplication.UnicodeUTF8))
48 | self.content.setText(QtGui.QApplication.translate("Notebook", "Contains 5 notes", None, QtGui.QApplication.UnicodeUTF8))
49 |
50 |
--------------------------------------------------------------------------------
/everpad/interface/notebook.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Notebook
4 |
5 |
6 |
7 | 0
8 | 0
9 | 296
10 | 60
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 |
23 | 75
24 | true
25 |
26 |
27 |
28 | Notebook name
29 |
30 |
31 |
32 | -
33 |
34 |
35 |
36 | 50
37 | false
38 |
39 |
40 |
41 | Contains 5 notes
42 |
43 |
44 |
45 |
46 |
47 | -
48 |
49 |
50 | Qt::Horizontal
51 |
52 |
53 |
54 | 40
55 | 20
56 |
57 |
58 |
59 |
60 | -
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/everpad/interface/share_note.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'share_note.ui'
4 | #
5 | # Created: Tue Jan 22 22:46:18 2013
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.1
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_ShareNote(object):
13 | def setupUi(self, ShareNote):
14 | ShareNote.setObjectName("ShareNote")
15 | ShareNote.resize(442, 197)
16 | ShareNote.setModal(True)
17 | self.verticalLayout = QtGui.QVBoxLayout(ShareNote)
18 | self.verticalLayout.setObjectName("verticalLayout")
19 | self.waitText = QtGui.QLabel(ShareNote)
20 | font = QtGui.QFont()
21 | font.setPointSize(18)
22 | self.waitText.setFont(font)
23 | self.waitText.setScaledContents(False)
24 | self.waitText.setAlignment(QtCore.Qt.AlignCenter)
25 | self.waitText.setObjectName("waitText")
26 | self.verticalLayout.addWidget(self.waitText)
27 | self.sharedWidget = QtGui.QWidget(ShareNote)
28 | self.sharedWidget.setObjectName("sharedWidget")
29 | self.horizontalLayout_2 = QtGui.QHBoxLayout(self.sharedWidget)
30 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
31 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
32 | self.sharedBox = QtGui.QVBoxLayout()
33 | self.sharedBox.setObjectName("sharedBox")
34 | self.horizontalLayout = QtGui.QHBoxLayout()
35 | self.horizontalLayout.setObjectName("horizontalLayout")
36 | self.label = QtGui.QLabel(self.sharedWidget)
37 | self.label.setObjectName("label")
38 | self.horizontalLayout.addWidget(self.label)
39 | self.shareLink = QtGui.QLineEdit(self.sharedWidget)
40 | self.shareLink.setReadOnly(True)
41 | self.shareLink.setObjectName("shareLink")
42 | self.horizontalLayout.addWidget(self.shareLink)
43 | self.sharedBox.addLayout(self.horizontalLayout)
44 | self.horizontalLayout_3 = QtGui.QHBoxLayout()
45 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
46 | self.copyButton = QtGui.QPushButton(self.sharedWidget)
47 | self.copyButton.setObjectName("copyButton")
48 | self.horizontalLayout_3.addWidget(self.copyButton)
49 | self.cancelButton = QtGui.QPushButton(self.sharedWidget)
50 | self.cancelButton.setObjectName("cancelButton")
51 | self.horizontalLayout_3.addWidget(self.cancelButton)
52 | self.sharedBox.addLayout(self.horizontalLayout_3)
53 | self.horizontalLayout_2.addLayout(self.sharedBox)
54 | self.verticalLayout.addWidget(self.sharedWidget)
55 |
56 | self.retranslateUi(ShareNote)
57 | QtCore.QMetaObject.connectSlotsByName(ShareNote)
58 |
59 | def retranslateUi(self, ShareNote):
60 | ShareNote.setWindowTitle(QtGui.QApplication.translate("ShareNote", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
61 | self.waitText.setText(QtGui.QApplication.translate("ShareNote", "wait_text", None, QtGui.QApplication.UnicodeUTF8))
62 | self.label.setText(QtGui.QApplication.translate("ShareNote", "You can share note with link: ", None, QtGui.QApplication.UnicodeUTF8))
63 | self.copyButton.setText(QtGui.QApplication.translate("ShareNote", "Copy url", None, QtGui.QApplication.UnicodeUTF8))
64 | self.cancelButton.setText(QtGui.QApplication.translate("ShareNote", "Cancel sharing", None, QtGui.QApplication.UnicodeUTF8))
65 |
66 |
--------------------------------------------------------------------------------
/everpad/interface/share_note.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ShareNote
4 |
5 |
6 |
7 | 0
8 | 0
9 | 442
10 | 197
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 | true
18 |
19 |
20 | -
21 |
22 |
23 |
24 | 18
25 |
26 |
27 |
28 | wait_text
29 |
30 |
31 | false
32 |
33 |
34 | Qt::AlignCenter
35 |
36 |
37 |
38 | -
39 |
40 |
41 |
-
42 |
43 |
-
44 |
45 |
-
46 |
47 |
48 | You can share note with link:
49 |
50 |
51 |
52 | -
53 |
54 |
55 | true
56 |
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
-
64 |
65 |
66 | Copy url
67 |
68 |
69 |
70 | -
71 |
72 |
73 | Cancel sharing
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/everpad/interface/tableinsert.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file './tableinsert.ui'
4 | #
5 | # Created: Sun Oct 7 06:22:18 2012
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.0
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_TableInsertDialog(object):
13 | def setupUi(self, TableInsertDialog):
14 | TableInsertDialog.setObjectName("TableInsertDialog")
15 | TableInsertDialog.setWindowModality(QtCore.Qt.WindowModal)
16 | TableInsertDialog.resize(433, 191)
17 | self.buttonBox = QtGui.QDialogButtonBox(TableInsertDialog)
18 | self.buttonBox.setGeometry(QtCore.QRect(80, 150, 341, 32))
19 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
20 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
21 | self.buttonBox.setObjectName("buttonBox")
22 | self.gridLayoutWidget = QtGui.QWidget(TableInsertDialog)
23 | self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 411, 121))
24 | self.gridLayoutWidget.setObjectName("gridLayoutWidget")
25 | self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget)
26 | self.gridLayout.setContentsMargins(0, 0, 0, 0)
27 | self.gridLayout.setObjectName("gridLayout")
28 | self.width = QtGui.QLineEdit(self.gridLayoutWidget)
29 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
30 | sizePolicy.setHorizontalStretch(0)
31 | sizePolicy.setVerticalStretch(0)
32 | sizePolicy.setHeightForWidth(self.width.sizePolicy().hasHeightForWidth())
33 | self.width.setSizePolicy(sizePolicy)
34 | self.width.setObjectName("width")
35 | self.gridLayout.addWidget(self.width, 2, 1, 1, 1)
36 | self.label_2 = QtGui.QLabel(self.gridLayoutWidget)
37 | self.label_2.setObjectName("label_2")
38 | self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
39 | self.rows = QtGui.QLineEdit(self.gridLayoutWidget)
40 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
41 | sizePolicy.setHorizontalStretch(0)
42 | sizePolicy.setVerticalStretch(0)
43 | sizePolicy.setHeightForWidth(self.rows.sizePolicy().hasHeightForWidth())
44 | self.rows.setSizePolicy(sizePolicy)
45 | self.rows.setObjectName("rows")
46 | self.gridLayout.addWidget(self.rows, 0, 1, 1, 1)
47 | self.label = QtGui.QLabel(self.gridLayoutWidget)
48 | self.label.setObjectName("label")
49 | self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
50 | self.columns = QtGui.QLineEdit(self.gridLayoutWidget)
51 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
52 | sizePolicy.setHorizontalStretch(0)
53 | sizePolicy.setVerticalStretch(0)
54 | sizePolicy.setHeightForWidth(self.columns.sizePolicy().hasHeightForWidth())
55 | self.columns.setSizePolicy(sizePolicy)
56 | self.columns.setObjectName("columns")
57 | self.gridLayout.addWidget(self.columns, 1, 1, 1, 1)
58 | self.label_3 = QtGui.QLabel(self.gridLayoutWidget)
59 | self.label_3.setObjectName("label_3")
60 | self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
61 | self.widthType = QtGui.QComboBox(self.gridLayoutWidget)
62 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
63 | sizePolicy.setHorizontalStretch(0)
64 | sizePolicy.setVerticalStretch(0)
65 | sizePolicy.setHeightForWidth(self.widthType.sizePolicy().hasHeightForWidth())
66 | self.widthType.setSizePolicy(sizePolicy)
67 | self.widthType.setObjectName("widthType")
68 | self.widthType.addItem("")
69 | self.widthType.addItem("")
70 | self.gridLayout.addWidget(self.widthType, 2, 2, 1, 1)
71 |
72 | self.retranslateUi(TableInsertDialog)
73 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), TableInsertDialog.accept)
74 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), TableInsertDialog.reject)
75 | QtCore.QMetaObject.connectSlotsByName(TableInsertDialog)
76 |
77 | def retranslateUi(self, TableInsertDialog):
78 | TableInsertDialog.setWindowTitle(QtGui.QApplication.translate("TableInsertDialog", "Everpad / Insert Table", None, QtGui.QApplication.UnicodeUTF8))
79 | self.width.setText(QtGui.QApplication.translate("TableInsertDialog", "100", None, QtGui.QApplication.UnicodeUTF8))
80 | self.label_2.setText(QtGui.QApplication.translate("TableInsertDialog", "Columns:", None, QtGui.QApplication.UnicodeUTF8))
81 | self.rows.setText(QtGui.QApplication.translate("TableInsertDialog", "2", None, QtGui.QApplication.UnicodeUTF8))
82 | self.label.setText(QtGui.QApplication.translate("TableInsertDialog", "Rows:", None, QtGui.QApplication.UnicodeUTF8))
83 | self.columns.setText(QtGui.QApplication.translate("TableInsertDialog", "2", None, QtGui.QApplication.UnicodeUTF8))
84 | self.label_3.setText(QtGui.QApplication.translate("TableInsertDialog", "Width:", None, QtGui.QApplication.UnicodeUTF8))
85 | self.widthType.setItemText(0, QtGui.QApplication.translate("TableInsertDialog", "% of page", None, QtGui.QApplication.UnicodeUTF8))
86 | self.widthType.setItemText(1, QtGui.QApplication.translate("TableInsertDialog", "pixels", None, QtGui.QApplication.UnicodeUTF8))
87 |
88 |
--------------------------------------------------------------------------------
/everpad/interface/tableinsert.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | TableInsertDialog
4 |
5 |
6 | Qt::WindowModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 433
13 | 191
14 |
15 |
16 |
17 | Everpad / Insert Table
18 |
19 |
20 |
21 |
22 | 80
23 | 150
24 | 341
25 | 32
26 |
27 |
28 |
29 | Qt::Horizontal
30 |
31 |
32 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
33 |
34 |
35 |
36 |
37 |
38 | 10
39 | 10
40 | 411
41 | 121
42 |
43 |
44 |
45 | -
46 |
47 |
48 |
49 | 0
50 | 0
51 |
52 |
53 |
54 | 100
55 |
56 |
57 |
58 | -
59 |
60 |
61 | Columns:
62 |
63 |
64 |
65 | -
66 |
67 |
68 |
69 | 0
70 | 0
71 |
72 |
73 |
74 | 2
75 |
76 |
77 |
78 | -
79 |
80 |
81 | Rows:
82 |
83 |
84 |
85 | -
86 |
87 |
88 |
89 | 0
90 | 0
91 |
92 |
93 |
94 | 2
95 |
96 |
97 |
98 | -
99 |
100 |
101 | Width:
102 |
103 |
104 |
105 | -
106 |
107 |
108 |
109 | 0
110 | 0
111 |
112 |
113 |
-
114 |
115 | % of page
116 |
117 |
118 | -
119 |
120 | pixels
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | buttonBox
132 | accepted()
133 | TableInsertDialog
134 | accept()
135 |
136 |
137 | 248
138 | 254
139 |
140 |
141 | 157
142 | 274
143 |
144 |
145 |
146 |
147 | buttonBox
148 | rejected()
149 | TableInsertDialog
150 | reject()
151 |
152 |
153 | 316
154 | 260
155 |
156 |
157 | 286
158 | 274
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/everpad/monkey.py:
--------------------------------------------------------------------------------
1 | import httplib2
2 | import ssl
3 |
4 |
5 | def _ssl_wrap_socket(sock, key_file, cert_file,
6 | disable_validation, ca_certs):
7 | if disable_validation:
8 | cert_reqs = ssl.CERT_NONE
9 | else:
10 | cert_reqs = ssl.CERT_REQUIRED
11 | # We should be specifying SSL version 3 or TLS v1, but the ssl module
12 | # doesn't expose the necessary knobs. So we need to go with the default
13 | # of SSLv23.
14 | return ssl.wrap_socket(sock, keyfile=key_file, certfile=cert_file,
15 | cert_reqs=cert_reqs, ca_certs=ca_certs, ssl_version=ssl.PROTOCOL_TLSv1)
16 | httplib2._ssl_wrap_socket = _ssl_wrap_socket
17 |
--------------------------------------------------------------------------------
/everpad/pad/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/everpad/pad/__init__.py
--------------------------------------------------------------------------------
/everpad/pad/editor/actions.py:
--------------------------------------------------------------------------------
1 | from PySide.QtGui import QIcon, QDialog, QWidget, QApplication
2 | from PySide.QtCore import Slot
3 | from PySide.QtWebKit import QWebPage
4 | from everpad.interface.tableinsert import Ui_TableInsertDialog
5 | from everpad.interface.image import Ui_ImageDialog
6 | from everpad.interface.findbar import Ui_FindBar
7 | from everpad.pad.tools import get_icon
8 |
9 |
10 | class ImagePrefs(QDialog):
11 | def __init__(self, res, *args, **kwargs):
12 | QDialog.__init__(self, *args, **kwargs)
13 | self.app = QApplication.instance()
14 | self.res = res
15 | self.ui = Ui_ImageDialog()
16 | self.ui.setupUi(self)
17 | self.setWindowIcon(get_icon())
18 | self.ui.widthBox.setValue(self.res.w)
19 | self.ui.heightBox.setValue(self.res.h)
20 | self.ui.widthBox.valueChanged.connect(self.width_changed)
21 | self.ui.heightBox.valueChanged.connect(self.height_changed)
22 | self._auto_change = False
23 |
24 | def get_size(self):
25 | return self.ui.widthBox.value(), self.ui.heightBox.value()
26 |
27 | @Slot()
28 | def width_changed(self):
29 | if self.ui.checkBox.isChecked() and not self._auto_change:
30 | self._auto_change = True
31 | self.ui.heightBox.setValue(
32 | self.ui.widthBox.value() * self.res.h / self.res.w,
33 | )
34 | else:
35 | self._auto_change = False
36 |
37 | @Slot()
38 | def height_changed(self):
39 | if self.ui.checkBox.isChecked() and not self._auto_change:
40 | self._auto_change = True
41 | self.ui.widthBox.setValue(
42 | self.ui.heightBox.value() * self.res.w / self.res.h,
43 | )
44 | else:
45 | self._auto_change = False
46 |
47 |
48 | class TableWidget(QDialog):
49 | def __init__(self, parent, rows=None, cells=None, *args, **kwargs):
50 | QDialog.__init__(self, parent, *args, **kwargs)
51 | self.ui = Ui_TableInsertDialog()
52 | self.ui.setupUi(self)
53 | self.setWindowIcon(get_icon())
54 | if rows: # typecasting sucks
55 | self.ui.rows.setText(str(int(rows)))
56 | if cells:
57 | self.ui.columns.setText(str(int(cells)))
58 |
59 | def get_width(self):
60 | result = self.ui.width.text()
61 | # 0 is %, 1 is px.
62 | if self.ui.widthType.currentIndex() == 0:
63 | result += '%'
64 | return result
65 |
66 |
67 | class FindBar(QWidget):
68 | def __init__(self, editor, *args, **kwargs):
69 | QWidget.__init__(self, *args, **kwargs)
70 | self.editor = editor
71 | self.ui = Ui_FindBar()
72 | self.ui.setupUi(self)
73 |
74 | # pyside-uic doesn't translate icons from themes correctly, so we have
75 | # to re-set the icons manually here
76 | self.ui.btnPrevious.setIcon(QIcon.fromTheme('go-previous'))
77 | self.ui.btnNext.setIcon(QIcon.fromTheme('go-next'))
78 | self.ui.btnClose.setIcon(QIcon.fromTheme('window-close'))
79 | self.visible = False
80 |
81 | self.ui.btnClose.clicked.connect(self.hide)
82 | self.ui.edtFindText.returnPressed.connect(self.find_next)
83 | self.ui.edtFindText.textChanged.connect(self.find_text_updated)
84 |
85 | self.ui.btnNext.clicked.connect(self.find_next)
86 | self.ui.btnPrevious.clicked.connect(self.find_previous)
87 |
88 | self.ui.btnHighlight.clicked.connect(self.update_highlight)
89 | self.ui.chkMatchCase.clicked.connect(self.match_case_updated)
90 |
91 | def set_search_term(self, search_term):
92 | self.ui.edtFindText.setText(search_term)
93 |
94 | def get_flags(self, default_flags=None):
95 | flags = QWebPage.FindFlag.FindWrapsAroundDocument
96 | if default_flags is not None:
97 | flags |= default_flags
98 | if self.ui.chkMatchCase.isChecked():
99 | flags |= QWebPage.FindFlag.FindCaseSensitively
100 | return flags
101 |
102 | @Slot()
103 | def match_case_updated(self):
104 | flags = self.get_flags()
105 |
106 | # We need the *old* flags value; clear this flag if it's checked
107 | if self.ui.chkMatchCase.isChecked():
108 | flags &= ~QWebPage.FindFlag.FindCaseSensitively
109 | else:
110 | flags |= QWebPage.FindFlag.FindCaseSensitively
111 | self.update_highlight(flags=flags, clear=True)
112 | self.update_highlight()
113 |
114 | @Slot(str)
115 | def find_text_updated(self, text):
116 | self.update_highlight(text=text, clear=True)
117 | self.find()
118 |
119 | @Slot()
120 | def find_next(self, text=None):
121 | self.find()
122 |
123 | @Slot()
124 | def find_previous(self):
125 | self.find(QWebPage.FindFlag.FindBackward)
126 |
127 | def find(self, flags=None):
128 | if not self.visible:
129 | self.show(focus=False)
130 | return
131 |
132 | flags = self.get_flags(flags)
133 | self.editor.note_edit.page.findText(self.ui.edtFindText.text(), flags)
134 | self.update_highlight()
135 |
136 | @Slot()
137 | def update_highlight(self, flags=None, text=None, clear=False):
138 | flags = flags or self.get_flags()
139 | flags |= QWebPage.FindFlag.HighlightAllOccurrences
140 | text = text or self.ui.edtFindText.text()
141 | if clear or not self.ui.btnHighlight.isChecked():
142 | text = ''
143 | self.editor.note_edit.page.findText(text, flags)
144 |
145 | def show(self, flags=None, focus=True):
146 | QWidget.show(self)
147 | if self.visible:
148 | self.find(flags)
149 | else:
150 | self.editor.ui.centralwidget.layout().addWidget(self)
151 | self.visible = True
152 |
153 | self.find(flags)
154 | self.update_highlight()
155 |
156 | if focus:
157 | self.ui.edtFindText.setFocus()
158 |
159 | self.editor.find_action.setChecked(True)
160 |
161 | @Slot()
162 | def hide(self):
163 | QWidget.hide(self)
164 | if not self.visible:
165 | return
166 | self.update_highlight(clear=True)
167 | self.editor.ui.centralwidget.layout().removeWidget(self)
168 | self.setParent(None)
169 | self.visible = False
170 | self.editor.find_action.setChecked(False)
171 |
172 | @Slot()
173 | def toggle_visible(self):
174 | if self.visible:
175 | self.hide()
176 | else:
177 | self.show()
178 |
--------------------------------------------------------------------------------
/everpad/pad/editor/widgets.py:
--------------------------------------------------------------------------------
1 | from PySide.QtGui import QCompleter, QStringListModel, QApplication
2 | from PySide.QtCore import Slot
3 | from everpad.basetypes import Tag, Notebook
4 | import re
5 |
6 |
7 | class TagEdit(object):
8 | """Abstraction for tag edit"""
9 |
10 | def __init__(self, parent, widget, on_change):
11 | """Init and connect signals"""
12 | self.parent = parent
13 | self.app = QApplication.instance()
14 | self.widget = widget
15 | self.tags_list = map(lambda tag:
16 | Tag.from_tuple(tag).name,
17 | self.app.provider.list_tags(),
18 | )
19 | self.completer = QCompleter()
20 | self.completer_model = QStringListModel()
21 | self.completer.setModel(self.completer_model)
22 | self.completer.activated.connect(self.update_completion)
23 | self.update_completion()
24 | self.widget.setCompleter(self.completer)
25 | self.widget.textChanged.connect(Slot()(on_change))
26 | self.widget.textEdited.connect(self.update_completion)
27 |
28 | @property
29 | def tags(self):
30 | """Get tags"""
31 | # Split on comma and Arabic comma
32 | # 0x060c is the Arabic comma
33 | return map(lambda tag: tag.strip(),
34 | re.split(u',|\u060c', self.widget.text()))
35 |
36 | @tags.setter
37 | def tags(self, val):
38 | """Set tags"""
39 | self.widget.setText(', '.join(val))
40 |
41 | @Slot()
42 | def update_completion(self):
43 | """Update completion model with exist tags"""
44 | orig_text = self.widget.text()
45 | text = ', '.join(orig_text.replace(', ', ',').split(',')[:-1])
46 | tags = []
47 | for tag in self.tags_list:
48 | if ',' in orig_text:
49 | if orig_text[-1] not in (',', ' '):
50 | tags.append('%s,%s' % (text, tag))
51 | tags.append('%s, %s' % (text, tag))
52 | else:
53 | tags.append(tag)
54 | if tags != self.completer_model.stringList():
55 | self.completer_model.setStringList(tags)
56 |
57 |
58 | class NotebookEdit(object):
59 | """Abstraction for notebook edit"""
60 |
61 | def __init__(self, parent, widget, on_change):
62 | """Init and connect signals"""
63 | self.parent = parent
64 | self.app = QApplication.instance()
65 | self.widget = widget
66 | for notebook_struct in self.app.provider.list_notebooks():
67 | notebook = Notebook.from_tuple(notebook_struct)
68 | self.widget.addItem(notebook.name, userData=notebook.id)
69 | self.widget.currentIndexChanged.connect(Slot()(on_change))
70 |
71 | @property
72 | def notebook(self):
73 | """Get notebook"""
74 | notebook_index = self.widget.currentIndex()
75 | return self.widget.itemData(notebook_index)
76 |
77 | @notebook.setter
78 | def notebook(self, val):
79 | """Set notebook"""
80 | notebook_index = self.widget.findData(val)
81 | self.widget.setCurrentIndex(notebook_index)
82 |
--------------------------------------------------------------------------------
/everpad/pad/share_note.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.append('../..')
3 | from PySide.QtGui import QDialog, QApplication
4 | from everpad.basetypes import Note
5 | from everpad.interface.share_note import Ui_ShareNote
6 | from everpad.pad.tools import get_icon
7 |
8 |
9 | class ShareNoteDialog(QDialog):
10 | """Share note dialog"""
11 |
12 | def __init__(self, note, *args, **kwargs):
13 | """init dialog and connect signals"""
14 | QDialog.__init__(self, *args, **kwargs)
15 | self.app = QApplication.instance()
16 | self.canceled = False
17 | self.ui = Ui_ShareNote()
18 | self.ui.setupUi(self)
19 | self.setWindowIcon(get_icon())
20 | self.note = Note.from_tuple(
21 | self.app.provider.get_note(note.id),
22 | )
23 | self.app.data_changed.connect(self.data_changed)
24 | self.ui.cancelButton.clicked.connect(self.cancel)
25 | self.ui.copyButton.clicked.connect(self.copy_url)
26 | if not self.note.share_url:
27 | self.start_sharing()
28 | self.update()
29 |
30 | def start_sharing(self):
31 | """Start sharing note"""
32 | self.app.provider.share_note(self.note.id)
33 |
34 | def copy_url(self):
35 | """Copy sharing url"""
36 | url = self.ui.shareLink.text()
37 | self.app.clipboard().setText(url)
38 |
39 | def cancel(self):
40 | """Cancel sharing note"""
41 | self.canceled = True
42 | self.app.provider.stop_sharing_note(self.note.id)
43 | self.update()
44 |
45 | def data_changed(self):
46 | """On data changed slot"""
47 | self.note = Note.from_tuple(
48 | self.app.provider.get_note(self.note.id),
49 | )
50 | self.update()
51 |
52 | def update(self):
53 | """Update dialog behavior"""
54 | self.update_title()
55 | if self.canceled:
56 | self.render_canceled()
57 | elif self.note.share_url:
58 | self.render_shared()
59 | else:
60 | self.render_wait()
61 |
62 | def update_title(self):
63 | """Update dialog title"""
64 | self.setWindowTitle(self.tr(
65 | 'Everpad / sharing "%s"' % self.note.title,
66 | ))
67 |
68 | def render_shared(self):
69 | """Render for already shared note"""
70 | self.ui.waitText.hide()
71 | self.ui.sharedWidget.show()
72 | self.ui.shareLink.setText(self.note.share_url)
73 |
74 | def render_canceled(self):
75 | """Render for canceled sharing"""
76 | self.ui.waitText.show()
77 | self.ui.sharedWidget.hide()
78 | self.ui.waitText.setText(self.tr('Note sharing canceled'))
79 |
80 | def render_wait(self):
81 | """Render for wait sharing"""
82 | self.ui.waitText.show()
83 | self.ui.sharedWidget.hide()
84 | self.ui.waitText.setText(self.tr('Sharing in proccess...'))
85 |
--------------------------------------------------------------------------------
/everpad/pad/tools.py:
--------------------------------------------------------------------------------
1 | from PySide.QtGui import QIcon
2 | import os
3 | import sys
4 | from everpad.tools import resource_filename
5 |
6 |
7 | def get_icon():
8 | return QIcon.fromTheme('everpad', QIcon('../../everpad.png'))
9 |
10 |
11 | def get_file_icon_path():
12 | """
13 | Get path of icon for file
14 | foe embedding in html.
15 | """
16 | paths = (
17 | os.path.join(
18 | os.path.dirname(__file__),
19 | '../../data/everpad-file.png',
20 | ),
21 | resource_filename('share/icons/hicolor/48x48/actions/everpad-file.png'),
22 | '/usr/local/share/icons/hicolor/48x48/actions/everpad-file.png',
23 | '/usr/share/icons/hicolor/48x48/actions/everpad-file.png',
24 | )
25 | for path in paths:
26 | if os.path.isfile(path):
27 | return 'file://%s' % path
28 | file_icon_path = get_file_icon_path()
29 |
--------------------------------------------------------------------------------
/everpad/pad/treeview.py:
--------------------------------------------------------------------------------
1 | from PySide.QtGui import QTreeView, QItemSelection
2 | from PySide.QtCore import Signal
3 |
4 |
5 | class EverpadTreeView(QTreeView):
6 | selection = Signal(QItemSelection, QItemSelection)
7 |
8 | def selectionChanged(self, selected, deselected):
9 | QTreeView.selectionChanged(self, selected, deselected)
10 | self.selection.emit(selected, deselected)
11 |
--------------------------------------------------------------------------------
/everpad/provider/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/everpad/provider/__init__.py
--------------------------------------------------------------------------------
/everpad/provider/daemon.py:
--------------------------------------------------------------------------------
1 | from .service import ProviderService
2 | from .sync.agent import SyncThread
3 | from .tools import set_auth_token, get_auth_token, get_db_session
4 | from ..specific import AppClass
5 | from ..tools import print_version
6 | from . import models
7 | from PySide.QtCore import Slot, QSettings
8 | import dbus
9 | import dbus.mainloop.glib
10 | import signal
11 | import fcntl
12 | import os
13 | import getpass
14 | import argparse
15 | import sys
16 | import logging
17 |
18 |
19 | class ProviderApp(AppClass):
20 |
21 | def __init__(self, verbose, *args, **kwargs):
22 | AppClass.__init__(self, *args, **kwargs)
23 | self.settings = QSettings('everpad', 'everpad-provider')
24 | self.verbose = verbose
25 | session_bus = dbus.SessionBus()
26 | self.bus = dbus.service.BusName("com.everpad.Provider", session_bus)
27 | self.service = ProviderService(session_bus, '/EverpadProvider')
28 | self.sync_thread = SyncThread()
29 | self.sync_thread.sync_state_changed.connect(
30 | Slot(int)(self.service.sync_state_changed),
31 | )
32 | self.sync_thread.data_changed.connect(
33 | Slot()(self.service.data_changed),
34 | )
35 | if get_auth_token():
36 | self.sync_thread.start()
37 | self.service.qobject.authenticate_signal.connect(
38 | self.on_authenticated,
39 | )
40 | self.service.qobject.remove_authenticate_signal.connect(
41 | self.on_remove_authenticated,
42 | )
43 | self.service.qobject.terminate.connect(self.terminate)
44 | # Configure logger.
45 | self.logger = logging.getLogger('everpad-provider')
46 | self.logger.setLevel(logging.DEBUG)
47 | fh = logging.FileHandler(
48 | os.path.expanduser('~/.everpad/logs/everpad-provider.log'))
49 | fh.setLevel(logging.DEBUG)
50 | formatter = logging.Formatter(
51 | '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
52 | fh.setFormatter(formatter)
53 | self.logger.addHandler(fh)
54 | self.logger.debug('Provider started.')
55 |
56 | @Slot(str)
57 | def on_authenticated(self, token):
58 | set_auth_token(token)
59 | self.sync_thread.start()
60 |
61 | @Slot()
62 | def on_remove_authenticated(self):
63 | self.sync_thread.quit()
64 | self.sync_thread.sync_state.update_count = 0
65 | set_auth_token('')
66 | session = get_db_session()
67 | session.query(models.Note).delete(
68 | synchronize_session='fetch',
69 | )
70 | session.query(models.Resource).delete(
71 | synchronize_session='fetch',
72 | )
73 | session.query(models.Notebook).delete(
74 | synchronize_session='fetch',
75 | )
76 | session.query(models.Tag).delete(
77 | synchronize_session='fetch',
78 | )
79 | session.commit()
80 |
81 | def log(self, data):
82 | self.logger.debug(data)
83 | if self.verbose:
84 | print data
85 |
86 | @Slot()
87 | def terminate(self):
88 | self.sync_thread.quit()
89 | self.quit()
90 |
91 |
92 | def _create_dirs(dirs):
93 | """Create everpad dirs"""
94 | for path in dirs:
95 | try:
96 | os.mkdir(os.path.expanduser(path))
97 | except OSError:
98 | continue
99 |
100 |
101 | def main():
102 | signal.signal(signal.SIGINT, signal.SIG_DFL)
103 | _create_dirs(['~/.everpad/', '~/.everpad/data/', '~/.everpad/logs/'])
104 | parser = argparse.ArgumentParser()
105 | parser.add_argument('--verbose', action='store_true', help='verbose output')
106 | parser.add_argument('--version', '-v', action='store_true', help='show version')
107 | args = parser.parse_args(sys.argv[1:])
108 | if args.version:
109 | print_version()
110 | fp = open('/tmp/everpad-provider-%s.lock' % getpass.getuser(), 'w')
111 | try:
112 | fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
113 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
114 | dbus.mainloop.glib.threads_init()
115 | app = ProviderApp(args.verbose, sys.argv)
116 | app.exec_()
117 | except IOError:
118 | print("everpad-provider already ran")
119 | except Exception as e:
120 | logging.exception("failed to start everpad-provider")
121 |
122 | if __name__ == '__main__':
123 | main()
124 |
--------------------------------------------------------------------------------
/everpad/provider/exceptions.py:
--------------------------------------------------------------------------------
1 | class TTypeValidationFailed(Exception):
2 | """TType validation failed"""
3 |
4 |
--------------------------------------------------------------------------------
/everpad/provider/sync/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'nvbn'
2 |
--------------------------------------------------------------------------------
/everpad/provider/sync/agent.py:
--------------------------------------------------------------------------------
1 | from PySide import QtCore
2 | from datetime import datetime
3 | from ... import const
4 | from ...specific import AppClass
5 | from .. import tools
6 | from . import note, notebook, tag
7 | from .. import models
8 | import time
9 | import traceback
10 | import socket
11 |
12 |
13 | class SyncThread(QtCore.QThread):
14 | """Sync notes with evernote thread"""
15 | force_sync_signal = QtCore.Signal()
16 | sync_state_changed = QtCore.Signal(int)
17 | data_changed = QtCore.Signal()
18 |
19 | def __init__(self, *args, **kwargs):
20 | """Init default values"""
21 | QtCore.QThread.__init__(self, *args, **kwargs)
22 | self.app = AppClass.instance()
23 | self._init_timer()
24 | self._init_locks()
25 |
26 | def _init_sync(self):
27 | """Init sync"""
28 | self.status = const.STATUS_NONE
29 | self.last_sync = datetime.now()
30 | self.sync_state = self.session.query(models.Sync).first()
31 | if not self.sync_state:
32 | self.sync_state = models.Sync(
33 | update_count=0, last_sync=self.last_sync)
34 | self.session.add(self.sync_state)
35 | self.session.commit()
36 |
37 | def _init_timer(self):
38 | """Init timer"""
39 | self.timer = QtCore.QTimer()
40 | self.timer.timeout.connect(self.sync)
41 | self.update_timer()
42 |
43 | def _init_locks(self):
44 | """Init locks"""
45 | self.wait_condition = QtCore.QWaitCondition()
46 | self.mutex = QtCore.QMutex()
47 |
48 | def update_timer(self):
49 | """Update sync timer"""
50 | self.timer.stop()
51 | delay = int(self.app.settings.value('sync_delay') or 0)
52 | if not delay:
53 | delay = const.DEFAULT_SYNC_DELAY
54 |
55 | if delay != const.SYNC_MANUAL:
56 | self.timer.start(delay)
57 |
58 | def run(self):
59 | """Run thread"""
60 | self._init_db()
61 | self._init_network()
62 | self._init_sync()
63 | while True:
64 | self.mutex.lock()
65 | self.wait_condition.wait(self.mutex)
66 | self.perform()
67 | self.mutex.unlock()
68 | time.sleep(1) # prevent cpu eating
69 |
70 | def _init_db(self):
71 | """Init database"""
72 | self.session = tools.get_db_session()
73 |
74 | def _init_network(self):
75 | """Init connection to remote server"""
76 | while True:
77 | try:
78 | self.auth_token = tools.get_auth_token()
79 | self.note_store = tools.get_note_store(self.auth_token)
80 | self.user_store = tools.get_user_store(self.auth_token)
81 | break
82 | except socket.error:
83 | time.sleep(30)
84 |
85 | def _need_to_update(self):
86 | """Check need for update notes"""
87 | self.app.log('Checking need for update notes.')
88 | # Try to update_count.
89 | try:
90 | update_count = self.note_store.getSyncState(
91 | self.auth_token).updateCount
92 | except socket.error, e:
93 | self.app.log(
94 | "Couldn't connect to remote server. Got: %s" %
95 | traceback.format_exc())
96 | # This is most likely a network failure. Return False so
97 | # everpad-provider won't lock up and can try to sync up in the
98 | # next run.
99 | return False
100 | #XXX: matsubara probably innefficient as it does a SQL each time it
101 | # accesses the update_count attr?
102 | self.app.log("Local update count: %s Remote update count: %s" % (
103 | self.sync_state.update_count, update_count))
104 | reason = update_count != self.sync_state.update_count
105 | self.sync_state.update_count = update_count
106 | return reason
107 |
108 | def force_sync(self):
109 | """Start sync"""
110 | self.timer.stop()
111 | self.sync()
112 | self.update_timer()
113 |
114 | @QtCore.Slot()
115 | def sync(self):
116 | """Do sync"""
117 | self.wait_condition.wakeAll()
118 |
119 | def perform(self):
120 | """Perform all sync"""
121 | self.app.log("Performing sync")
122 | self.status = const.STATUS_SYNC
123 | self.last_sync = datetime.now()
124 | self.sync_state_changed.emit(const.SYNC_STATE_START)
125 |
126 | need_to_update = self._need_to_update()
127 |
128 | try:
129 | if need_to_update:
130 | self.remote_changes()
131 | self.local_changes()
132 | except Exception, e: # maybe log this
133 | self.session.rollback()
134 | self._init_db()
135 | self.app.log(e)
136 | finally:
137 | self.sync_state_changed.emit(const.SYNC_STATE_FINISH)
138 | self.status = const.STATUS_NONE
139 | self.all_notes = None
140 |
141 | self.data_changed.emit()
142 | self.app.log("Sync performed.")
143 |
144 | def _get_sync_args(self):
145 | """Get sync arguments"""
146 | return self.auth_token, self.session, self.note_store, self.user_store
147 |
148 | def local_changes(self):
149 | """Send local changes to evernote server"""
150 | self.app.log('Running local_changes()')
151 | self.sync_state_changed.emit(const.SYNC_STATE_NOTEBOOKS_LOCAL)
152 | notebook.PushNotebook(*self._get_sync_args()).push()
153 |
154 | self.sync_state_changed.emit(const.SYNC_STATE_TAGS_LOCAL)
155 | tag.PushTag(*self._get_sync_args()).push()
156 |
157 | self.sync_state_changed.emit(const.SYNC_STATE_NOTES_LOCAL)
158 | note.PushNote(*self._get_sync_args()).push()
159 |
160 | def remote_changes(self):
161 | """Receive remote changes from evernote"""
162 | self.app.log('Running remote_changes()')
163 | self.sync_state_changed.emit(const.SYNC_STATE_NOTEBOOKS_REMOTE)
164 | notebook.PullNotebook(*self._get_sync_args()).pull()
165 |
166 | self.sync_state_changed.emit(const.SYNC_STATE_TAGS_REMOTE)
167 | tag.PullTag(*self._get_sync_args()).pull()
168 |
169 | self.sync_state_changed.emit(const.SYNC_STATE_NOTES_REMOTE)
170 | note.PullNote(*self._get_sync_args()).pull()
171 |
--------------------------------------------------------------------------------
/everpad/provider/sync/base.py:
--------------------------------------------------------------------------------
1 | from ...specific import AppClass
2 |
3 |
4 | class BaseSync(object):
5 | """Base class for sync"""
6 |
7 | def __init__(self, auth_token, session, note_store, user_store):
8 | """Set shortcuts"""
9 | self.auth_token = auth_token
10 | self.session = session
11 | self.note_store = note_store
12 | self.user_store = user_store
13 | self.app = AppClass.instance()
14 |
--------------------------------------------------------------------------------
/everpad/provider/sync/notebook.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.orm.exc import NoResultFound
2 | from evernote.edam.error.ttypes import EDAMUserException
3 | from evernote.edam.limits import constants as limits
4 | from evernote.edam.type import ttypes
5 | from ... import const
6 | from ..exceptions import TTypeValidationFailed
7 | from .. import models
8 | from .base import BaseSync
9 | import regex
10 |
11 |
12 | class PushNotebook(BaseSync):
13 | """Notebook sync"""
14 |
15 | def push(self):
16 | """Push notebook changes to server"""
17 | for notebook in self.session.query(models.Notebook).filter(
18 | models.Notebook.action != const.ACTION_NONE,
19 | ):
20 | self.app.log(
21 | 'Pushing notebook "%s" to remote server.' % notebook.name)
22 |
23 | try:
24 | notebook_ttype = self._create_ttype(notebook)
25 | except TTypeValidationFailed:
26 | self.app.log('notebook %s skipped' % notebook.name)
27 | notebook.action = const.ACTION_NONE
28 | continue
29 |
30 | if notebook.action == const.ACTION_CREATE:
31 | self._push_new_notebook(notebook, notebook_ttype)
32 | elif notebook.action == const.ACTION_CHANGE:
33 | self._push_changed_notebook(notebook, notebook_ttype)
34 |
35 | self.session.commit()
36 | self._merge_duplicates()
37 |
38 | def _create_ttype(self, notebook):
39 | """Create notebook ttype"""
40 | kwargs = dict(
41 | name=notebook.name[
42 | :limits.EDAM_NOTEBOOK_NAME_LEN_MAX
43 | ].strip().encode('utf8'),
44 | defaultNotebook=notebook.default,
45 | )
46 |
47 | if notebook.stack:
48 | kwargs['stack'] = notebook.stack[
49 | :limits.EDAM_NOTEBOOK_STACK_LEN_MAX
50 | ].strip().encode('utf8')
51 |
52 | if not regex.search(limits.EDAM_NOTEBOOK_NAME_REGEX, notebook.name):
53 | raise TTypeValidationFailed()
54 |
55 | if notebook.guid:
56 | kwargs['guid'] = notebook.guid
57 |
58 | return ttypes.Notebook(**kwargs)
59 |
60 | def _push_new_notebook(self, notebook, notebook_ttype):
61 | """Push new notebook to server"""
62 | try:
63 | notebook_ttype = self.note_store.createNotebook(
64 | self.auth_token, notebook_ttype,
65 | )
66 | notebook.guid = notebook_ttype.guid
67 | notebook.action = const.ACTION_NONE
68 | except EDAMUserException:
69 | notebook.action = const.ACTION_DUPLICATE
70 | self.app.log('Duplicate %s' % notebook_ttype.name)
71 |
72 | def _push_changed_notebook(self, notebook, notebook_ttype):
73 | """Push changed notebook"""
74 | try:
75 | notebook_ttype = self.note_store.updateNotebook(
76 | self.auth_token, notebook_ttype,
77 | )
78 | notebook.action = const.ACTION_NONE
79 | except EDAMUserException:
80 | notebook.action = const.ACTION_DUPLICATE
81 | self.app.log('Duplicate %s' % notebook_ttype.name)
82 |
83 | def _merge_duplicates(self):
84 | """Merge and remove duplicates"""
85 | for notebook in self.session.query(models.Notebook).filter(
86 | models.Notebook.action == const.ACTION_DUPLICATE,
87 | ):
88 | try:
89 | original = self.session.query(models.Notebook).filter(
90 | (models.Notebook.action != const.ACTION_DUPLICATE)
91 | & (models.Notebook.name == notebook.name)
92 | ).one()
93 | except NoResultFound:
94 | original = self.session.query(models.Notebook).filter(
95 | models.Notebook.default == True,
96 | ).one()
97 |
98 | for note in self.session.query(models.Note).filter(
99 | models.Note.notebook_id == notebook.id,
100 | ):
101 | note.notebook = original
102 |
103 | self.session.delete(notebook)
104 | self.session.commit()
105 |
106 |
107 | class PullNotebook(BaseSync):
108 | """Pull notebook from server"""
109 |
110 | def __init__(self, *args, **kwargs):
111 | super(PullNotebook, self).__init__(*args, **kwargs)
112 | self._exists = []
113 |
114 | def pull(self):
115 | """Receive notebooks from server"""
116 | for notebook_ttype in self.note_store.listNotebooks(self.auth_token):
117 | self.app.log(
118 | 'Pulling notebook "%s" from remote server.' % notebook_ttype.name)
119 | try:
120 | notebook = self._update_notebook(notebook_ttype)
121 | except NoResultFound:
122 | notebook = self._create_notebook(notebook_ttype)
123 | self._exists.append(notebook.id)
124 |
125 | self.session.commit()
126 | self._remove_notebooks()
127 |
128 | def _create_notebook(self, notebook_ttype):
129 | """Create notebook from ttype"""
130 | notebook = models.Notebook(guid=notebook_ttype.guid)
131 | notebook.from_api(notebook_ttype)
132 | self.session.add(notebook)
133 | self.session.commit()
134 | return notebook
135 |
136 | def _update_notebook(self, notebook_ttype):
137 | """Try to update notebook from ttype"""
138 | notebook = self.session.query(models.Notebook).filter(
139 | models.Notebook.guid == notebook_ttype.guid,
140 | ).one()
141 | if notebook.service_updated < notebook_ttype.serviceUpdated:
142 | notebook.from_api(notebook_ttype)
143 | return notebook
144 |
145 | def _remove_notebooks(self):
146 | """Remove not received notebooks"""
147 | if self._exists:
148 | q = (~models.Notebook.id.in_(self._exists)
149 | & (models.Notebook.action != const.ACTION_CREATE)
150 | & (models.Notebook.action != const.ACTION_CHANGE))
151 | else:
152 | q = ((models.Notebook.action != const.ACTION_CREATE)
153 | & (models.Notebook.action != const.ACTION_CHANGE))
154 |
155 | self.session.query(models.Notebook).filter(
156 | q).delete(synchronize_session='fetch')
157 |
--------------------------------------------------------------------------------
/everpad/provider/sync/tag.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.orm.exc import NoResultFound
2 | from evernote.edam.error.ttypes import EDAMUserException
3 | from evernote.edam.limits import constants as limits
4 | from evernote.edam.type import ttypes
5 | from ... import const
6 | from ..exceptions import TTypeValidationFailed
7 | from .. import models
8 | from .base import BaseSync
9 | import regex
10 |
11 |
12 | class PushTag(BaseSync):
13 | """Push tags to server"""
14 |
15 | def push(self):
16 | """Push tags"""
17 | for tag in self.session.query(models.Tag).filter(
18 | models.Tag.action != const.ACTION_NONE,
19 | ):
20 | self.app.log('Pushing tag "%s" to remote server.' % tag.name)
21 |
22 | try:
23 | tag_ttype = self._create_ttype(tag)
24 | except TTypeValidationFailed:
25 | tag.action = const.ACTION_NONE
26 | self.app.log('tag %s skipped' % tag.name)
27 | continue
28 |
29 | if tag.action == const.ACTION_CREATE:
30 | self._push_new_tag(tag, tag_ttype)
31 | elif tag.action == const.ACTION_CHANGE:
32 | self._push_changed_tag(tag, tag_ttype)
33 |
34 | self.session.commit()
35 |
36 | def _create_ttype(self, tag):
37 | """Create tag ttype"""
38 | if not regex.search(limits.EDAM_TAG_NAME_REGEX, tag.name):
39 | raise TTypeValidationFailed()
40 |
41 | kwargs = dict(
42 | name=tag.name[:limits.EDAM_TAG_NAME_LEN_MAX].strip().encode('utf8'),
43 | )
44 |
45 | if tag.guid:
46 | kwargs['guid'] = tag.guid
47 |
48 | return ttypes.Tag(**kwargs)
49 |
50 | def _push_new_tag(self, tag, tag_ttype):
51 | """Push new tag"""
52 | try:
53 | tag_ttype = self.note_store.createTag(
54 | self.auth_token, tag_ttype,
55 | )
56 | tag.guid = tag_ttype.guid
57 | tag.action = const.ACTION_NONE
58 | except EDAMUserException as e:
59 | self.app.log(e)
60 |
61 | def _push_changed_tag(self, tag, tag_ttype):
62 | """Push changed tag"""
63 | try:
64 | self.note_store.updateTag(
65 | self.auth_token, tag_ttype,
66 | )
67 | tag.action = const.ACTION_NONE
68 | except EDAMUserException as e:
69 | self.app.log(e)
70 |
71 |
72 | class PullTag(BaseSync):
73 | """Pull tags from server"""
74 |
75 | def __init__(self, *args, **kwargs):
76 | super(PullTag, self).__init__(*args, **kwargs)
77 | self._exists = []
78 |
79 | def pull(self):
80 | """Pull tags from server"""
81 | for tag_ttype in self.note_store.listTags(self.auth_token):
82 | self.app.log(
83 | 'Pulling tag "%s" from remote server.' % tag_ttype.name)
84 | try:
85 | tag = self._update_tag(tag_ttype)
86 | except NoResultFound:
87 | tag = self._create_tag(tag_ttype)
88 | self._exists.append(tag.id)
89 |
90 | self.session.commit()
91 | self._remove_tags()
92 |
93 | def _create_tag(self, tag_ttype):
94 | """Create tag from server"""
95 | tag = models.Tag(guid=tag_ttype.guid)
96 | tag.from_api(tag_ttype)
97 | self.session.add(tag)
98 | self.session.commit()
99 | return tag
100 |
101 | def _update_tag(self, tag_ttype):
102 | """Update tag if exists"""
103 | tag = self.session.query(models.Tag).filter(
104 | models.Tag.guid == tag_ttype.guid,
105 | ).one()
106 | if tag.name != tag_ttype.name.decode('utf8'):
107 | tag.from_api(tag_ttype)
108 | return tag
109 |
110 | def _remove_tags(self):
111 | """Remove not exist tags"""
112 | if self._exists:
113 | q = (~models.Tag.id.in_(self._exists)
114 | & (models.Tag.action != const.ACTION_CREATE))
115 | else:
116 | q = (models.Tag.action != const.ACTION_CREATE)
117 | self.session.query(models.Tag).filter(q).delete(
118 | synchronize_session='fetch')
119 |
--------------------------------------------------------------------------------
/everpad/provider/tools.py:
--------------------------------------------------------------------------------
1 | from thrift.protocol import TBinaryProtocol
2 | from thrift.transport import THttpClient
3 | from evernote.edam.userstore import UserStore
4 | from evernote.edam.notestore import NoteStore
5 | from sqlalchemy import create_engine
6 | from sqlalchemy.orm import sessionmaker
7 | from urlparse import urlparse
8 | from .models import Base
9 | from ..const import HOST, DB_PATH
10 | from ..tools import get_proxy_config
11 | from ..specific import get_keyring
12 | import os
13 | import logging
14 |
15 |
16 | def _nocase_lower(item):
17 | return unicode(item).lower()
18 |
19 |
20 | def set_auth_token(token):
21 | get_keyring().set_password('everpad', 'oauth_token', token)
22 |
23 |
24 | def get_auth_token():
25 | try:
26 | return get_keyring().get_password('everpad', 'oauth_token')
27 | except Exception as e:
28 | logging.exception("Error getting token from keyring")
29 |
30 |
31 | def get_db_session(db_path=None):
32 | if not db_path:
33 | db_path = os.path.expanduser(DB_PATH)
34 | engine = create_engine('sqlite:///%s' % db_path)
35 | Base.metadata.create_all(engine)
36 | Session = sessionmaker(bind=engine)
37 | session = Session()
38 | conn = session.connection()
39 | conn.connection.create_function('lower', 1, _nocase_lower)
40 | return session
41 |
42 |
43 | def get_user_store(auth_token=None):
44 | if not auth_token:
45 | auth_token = get_auth_token()
46 | user_store_uri = "https://" + HOST + "/edam/user"
47 |
48 | user_store_http_client = THttpClient.THttpClient(user_store_uri,
49 | http_proxy=get_proxy_config(urlparse(user_store_uri).scheme))
50 | user_store_protocol = TBinaryProtocol.TBinaryProtocol(user_store_http_client)
51 | return UserStore.Client(user_store_protocol)
52 |
53 |
54 | def get_note_store(auth_token=None):
55 | if not auth_token:
56 | auth_token = get_auth_token()
57 | user_store = get_user_store(auth_token)
58 | note_store_url = user_store.getNoteStoreUrl(auth_token)
59 | note_store_http_client = THttpClient.THttpClient(note_store_url,
60 | http_proxy=get_proxy_config(urlparse(note_store_url).scheme))
61 | note_store_protocol = TBinaryProtocol.TBinaryProtocol(note_store_http_client)
62 | return NoteStore.Client(note_store_protocol)
63 |
--------------------------------------------------------------------------------
/everpad/specific/__init__.py:
--------------------------------------------------------------------------------
1 | from PySide.QtGui import QIcon
2 | from everpad.specific.unity.launcher import UnityLauncher
3 | import os
4 |
5 |
6 | launchers = {
7 | 'ubuntu': UnityLauncher,
8 | 'default': UnityLauncher,
9 | }
10 |
11 |
12 | def get_launcher(*args, **kwargs):
13 | de = os.environ.get('DESKTOP_SESSION', 'default')
14 | launcher = launchers.get(de, launchers['default'])
15 | return launcher(*args, **kwargs)
16 |
17 |
18 | def get_tray_icon(is_black=False):
19 | if os.environ.get('DESKTOP_SESSION', 'default') == 'gnome':
20 | return QIcon.fromTheme('everpad', QIcon('../../data/everpad.png'))
21 | if is_black:
22 | return QIcon.fromTheme('everpad-black', QIcon('../../data/everpad-black.png'))
23 | else:
24 | return QIcon.fromTheme('everpad-mono', QIcon('../../data/everpad-mono.png'))
25 |
26 |
27 | if 'kde' in os.environ.get('DESKTOP_SESSION', '') or os.environ.get('KDE_FULL_SESSION') == 'true': # kde init qwidget for wallet access
28 | from PySide.QtGui import QApplication
29 | AppClass = QApplication
30 | else:
31 | from PySide.QtCore import QCoreApplication
32 | AppClass = QCoreApplication
33 |
34 |
35 | class QSettingsKeyringAdpdater(object):
36 | def __init__(self, settings):
37 | self._settings = settings
38 |
39 | def _prepare_name(self, app, name):
40 | return '%s_%s' % (app, name)
41 |
42 | def set_password(self, app, name, password):
43 | self._settings.setValue(self._prepare_name(app, name), password)
44 |
45 | def get_password(self, app, name):
46 | self._settings.value(self._prepare_name(app, name))
47 |
48 |
49 | def get_keyring():
50 | if os.environ.get('DESKTOP_SESSION', 'default') in ('Lubuntu', 'LXDE'):
51 | # keyring fails on initialisation in lxde
52 | return QSettingsKeyringAdpdater(AppClass.instance().settings)
53 | else:
54 | import keyring
55 | return keyring
56 |
--------------------------------------------------------------------------------
/everpad/specific/kde/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/everpad/specific/kde/__init__.py
--------------------------------------------------------------------------------
/everpad/specific/kde/everpad_runner.py:
--------------------------------------------------------------------------------
1 | from PyKDE4 import plasmascript
2 | from PyKDE4.plasma import Plasma
3 | from PyKDE4.kdeui import KIcon
4 | from html2text import html2text
5 | from everpad.basetypes import Note
6 | from everpad.tools import get_provider, get_pad
7 | import dbus
8 |
9 |
10 | CREATE = -1
11 | SETTINGS = -2
12 | provider = get_provider()
13 |
14 |
15 | class EverpadRunner(plasmascript.Runner):
16 |
17 | def match(self, context):
18 | if not context.isValid():
19 | return
20 | query = context.query()
21 | search = query.__str__() # PyQt is shit
22 | if len(search) < 3:
23 | return
24 | if search.lower() in 'create note':
25 | action = Plasma.QueryMatch(self.runner)
26 | action.setText("Create new note in everpad")
27 | action.setType(Plasma.QueryMatch.ExactMatch)
28 | action.setIcon(KIcon("everpad"))
29 | action.setData(str(CREATE))
30 | context.addMatch(query, action)
31 | if search.lower() in 'settings and management':
32 | action = Plasma.QueryMatch(self.runner)
33 | action.setText("Open everpad settings")
34 | action.setType(Plasma.QueryMatch.ExactMatch)
35 | action.setIcon(KIcon("everpad"))
36 | action.setData(str(SETTINGS))
37 | context.addMatch(query, action)
38 | blank = dbus.Array([], signature='i')
39 | for note_struct in provider.find_notes(
40 | search, blank, blank, 0,
41 | 1000, Note.ORDER_TITLE, -1,
42 | ):
43 | note = Note.from_tuple(note_struct)
44 | action = Plasma.QueryMatch(self.runner)
45 | action.setText(note.title)
46 | content = html2text(note.content)
47 | content = content[:200]
48 | action.setSubtext(content)
49 | action.setType(Plasma.QueryMatch.ExactMatch)
50 | action.setIcon(KIcon("everpad"))
51 | action.setData(str(note.id))
52 | context.addMatch(query, action)
53 |
54 | def run(self, context, match):
55 | data = match.data().toInt()[0]
56 | pad = get_pad()
57 | if data == CREATE:
58 | pad.create()
59 | elif data == SETTINGS:
60 | pad.settings()
61 | else:
62 | pad.open(data)
63 |
64 |
65 | def CreateRunner(parent):
66 | return EverpadRunner(parent)
67 |
--------------------------------------------------------------------------------
/everpad/specific/unity/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/everpad/specific/unity/__init__.py
--------------------------------------------------------------------------------
/everpad/specific/unity/launcher.py:
--------------------------------------------------------------------------------
1 | import dbus
2 | import dbus.service
3 |
4 |
5 | class UnityLauncher(dbus.service.Object):
6 | def __init__(self, app_uri, *args, **kwargs):
7 | self.app_uri = app_uri
8 | self.data = {}
9 | dbus.service.Object.__init__(self, *args, **kwargs)
10 |
11 | def update(self, data):
12 | self.data = data
13 | self.Update(self.app_uri, data)
14 |
15 | @dbus.service.signal(
16 | dbus_interface='com.canonical.Unity.LauncherEntry',
17 | signature=("sa{sv}")
18 | )
19 | def Update(self, app_uri, properties):
20 | return
21 |
22 | @dbus.service.method(
23 | dbus_interface='com.canonical.Unity.LauncherEntry',
24 | in_signature="", out_signature="sa{sv}",
25 | )
26 | def Query(self):
27 | return self.app_uri, self.data
28 |
--------------------------------------------------------------------------------
/everpad/specific/unity/lens.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.insert(0, '..')
3 | from singlet.lens import SingleScopeLens, ListViewCategory
4 | from gi.repository import Gio, Unity, Notify
5 | from singlet.utils import run_lens
6 | from everpad.tools import get_provider, get_pad, resource_filename
7 | from everpad.basetypes import Note, Tag, Notebook, Place, Resource
8 | from everpad.const import API_VERSION
9 | from html2text import html2text
10 | from datetime import datetime
11 | import dbus
12 | import dbus.mainloop.glib
13 | import sys
14 | import os
15 | import gettext
16 | import json
17 |
18 |
19 | path = os.path.join(os.path.dirname(__file__), '../../../i18n')
20 | if not os.path.isdir(path):
21 | path = resource_filename('share/locale/')
22 | gettext.bindtextdomain('everpad', path)
23 | gettext.textdomain('everpad')
24 | _ = gettext.gettext
25 |
26 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
27 | provider = get_provider()
28 |
29 |
30 | class EverpadLens(SingleScopeLens):
31 |
32 | class Meta:
33 | name = 'everpad'
34 | description = _('Everpad Lens')
35 | search_hint = _('Search Everpad')
36 | icon = 'everpad-lens'
37 | search_on_blank = True
38 | bus_name = 'net.launchpad.Unity.Lens.EverpadLens'
39 | bus_path = '/net/launchpad/unity/lens/everpad'
40 |
41 | def __init__(self):
42 | SingleScopeLens.__init__(self)
43 | provider.connect_to_signal(
44 | 'data_changed',
45 | self.update_props,
46 | dbus_interface="com.everpad.provider",
47 | )
48 | provider.connect_to_signal(
49 | 'settings_changed',
50 | self.settings_changed,
51 | dbus_interface="com.everpad.provider",
52 | )
53 | self.update_props()
54 | self._scope.connect('preview-uri', self.preview)
55 |
56 | def settings_changed(self, name, value):
57 | if name == 'search-on-home':
58 | self.update_props()
59 |
60 | def update_props(self):
61 | icon = Gio.ThemedIcon.new(resource_filename(
62 | "share/icons/unity-icon-theme/places/svg/group-recent.svg",
63 | ))
64 | tags = Unity.CheckOptionFilter.new('tags', _('Tags'), icon, True)
65 | for tag_struct in provider.list_tags():
66 | tag = Tag.from_tuple(tag_struct)
67 | tags.add_option(str(tag.id), tag.name, icon)
68 | notebooks = Unity.RadioOptionFilter.new(
69 | 'notebooks', _('Notebooks'), icon, True,
70 | )
71 | for notebook_struct in provider.list_notebooks():
72 | notebook = Notebook.from_tuple(notebook_struct)
73 | notebooks.add_option(str(notebook.id), notebook.name, icon)
74 | places = Unity.RadioOptionFilter.new('places', _('Places'), icon, True)
75 | for place_struct in provider.list_places():
76 | place = Place.from_tuple(place_struct)
77 | places.add_option(str(place.id), place.name, icon)
78 | self._lens.props.filters = [notebooks, tags, places]
79 | self._lens.props.search_in_global = True
80 |
81 | def can_search_on_home_lens(self):
82 | return bool(int(provider.get_settings_value('search-on-home') or 1))
83 |
84 | pin_notes = ListViewCategory(_("Pin Notes"), 'everpad-lens')
85 | all_notes = ListViewCategory(_("All Notes"), 'everpad-lens')
86 |
87 | def search(self, search, results):
88 | try:
89 | version = provider.get_api_version()
90 | except ( # dbus raise some magic
91 | dbus.exceptions.UnknownMethodException,
92 | dbus.exceptions.DBusException,
93 | ):
94 | version = -1
95 | if version < API_VERSION:
96 | dim = datetime.now() - getattr(self, 'last_api_notify', datetime.now())
97 | if dim.seconds > 600:
98 | Notify.init("everpad")
99 | Notify.Notification.new(
100 | 'everpad',
101 | _('Please restart everpad via indicator'),
102 | '').show()
103 | self.last_api_notify = datetime.now()
104 | return
105 | elif version > API_VERSION:
106 | sys.exit(0)
107 | if self.notebook_filter_id:
108 | notebooks = [self.notebook_filter_id]
109 | else:
110 | notebooks = dbus.Array([], signature='i')
111 | if self.place_filter_id:
112 | place = self.place_filter_id
113 | else:
114 | place = 0
115 | tags = dbus.Array(self.tag_filter_ids, signature='i')
116 | for note_struct in provider.find_notes(
117 | search, notebooks, tags, place,
118 | 1000, Note.ORDER_TITLE, -1,
119 | ):
120 | note = Note.from_tuple(note_struct)
121 | results.append(json.dumps({'id': note.id, 'search': search}),
122 | 'everpad-note', self.pin_notes if note.pinnded else self.all_notes,
123 | "text/html", note.title, html2text(note.content),
124 | '')
125 |
126 | def global_search(self, phrase, results):
127 | if self.can_search_on_home_lens():
128 | return super(EverpadLens, self).global_search(phrase, results)
129 | else:
130 | results.clear()
131 |
132 |
133 | def preview(self, scope, uri):
134 | obj = json.loads(uri)
135 | note = Note.from_tuple(provider.get_note(obj['id']))
136 | preview = Unity.GenericPreview.new(
137 | note.title, html2text(note.content), None,
138 | )
139 | edit = Unity.PreviewAction.new("edit", "Edit", None)
140 | image = None
141 | for _res in provider.get_note_resources(note.id):
142 | res = Resource.from_tuple(_res)
143 | if 'image' in res.mime:
144 | image = 'file://%s' % res.file_path
145 | if image:
146 | preview.props.image_source_uri = image
147 | edit.connect('activated', self.handle_uri)
148 | preview.add_action(edit)
149 | return preview
150 |
151 | def handle_uri(self, scope, uri):
152 | obj = json.loads(uri)
153 | get_pad().open_with_search_term(int(obj['id']), obj.get('search', ''))
154 | return self.hide_dash_response()
155 |
156 | def on_filtering_changed(self, scope):
157 | tags = scope.get_filter('tags')
158 | self.tag_filter_ids = map(lambda tag: int(tag.props.id),
159 | filter(lambda tag: tag.props.active, tags.options))
160 | notebook = scope.get_filter('notebooks').get_active_option()
161 | if notebook:
162 | self.notebook_filter_id = int(notebook.props.id)
163 | else:
164 | self.notebook_filter_id = None
165 | place = scope.get_filter('places').get_active_option()
166 | if place:
167 | self.place_filter_id = int(place.props.id)
168 | else:
169 | self.place_filter_id = None
170 | SingleScopeLens.on_filtering_changed(self, scope)
171 |
172 |
173 | def main():
174 | run_lens(EverpadLens, sys.argv)
175 |
176 | if __name__ == '__main__':
177 | main()
178 |
--------------------------------------------------------------------------------
/everpad/tools.py:
--------------------------------------------------------------------------------
1 | from functools import wraps, partial
2 | from BeautifulSoup import BeautifulSoup
3 | from HTMLParser import HTMLParser
4 | from everpad.const import API_VERSION, SCHEMA_VERSION, VERSION
5 | import dbus
6 | import re
7 | import sys
8 | import os
9 | import pkg_resources
10 |
11 |
12 | class InterfaceWrapper(object):
13 | def __init__(self, get):
14 | self.__get = get
15 | self.__load()
16 |
17 | def __load(self):
18 | self.__interface = self.__get()
19 |
20 | def __getattr__(self, name):
21 | attr = getattr(self.__interface, name)
22 | if hasattr(attr, '__call__'):
23 | attr = self.__reconnect_on_fail(attr, name)
24 | return attr
25 |
26 | def __reconnect_on_fail(self, fnc, name):
27 | def wrapper(*args, **kwargs):
28 | try:
29 | return fnc(*args, **kwargs)
30 | except dbus.DBusException:
31 | self.__load()
32 | return getattr(self.__interface, name)(*args, **kwargs)
33 | return wrapper
34 |
35 |
36 | def wrapper_functor(fnc):
37 | @wraps(fnc)
38 | def wrapper(*args, **kwrags):
39 | return InterfaceWrapper(partial(fnc, *args, **kwrags))
40 | return wrapper
41 |
42 |
43 | @wrapper_functor
44 | def get_provider(bus=None):
45 | if not bus:
46 | bus = dbus.SessionBus()
47 | provider = bus.get_object("com.everpad.Provider", '/EverpadProvider')
48 | return dbus.Interface(provider, "com.everpad.Provider")
49 |
50 |
51 | @wrapper_functor
52 | def get_pad(bus=None):
53 | if not bus:
54 | bus = dbus.SessionBus()
55 | pad = bus.get_object("com.everpad.App", "/EverpadService")
56 | return dbus.Interface(pad, "com.everpad.App")
57 |
58 |
59 | def clean(text): # from http://stackoverflow.com/questions/1707890/fast-way-to-filter-illegal-xml-unicode-chars-in-python
60 | illegal_unichrs = [
61 | (0x00, 0x08), (0x0B, 0x1F), (0x7F, 0x84), (0x86, 0x9F),
62 | (0xD800, 0xDFFF), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF),
63 | (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF),
64 | (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF),
65 | (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF),
66 | (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF),
67 | (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF),
68 | (0x10FFFE, 0x10FFFF)
69 | ]
70 |
71 | illegal_ranges = [
72 | "%s-%s" % (unichr(low), unichr(high))
73 | for (low, high) in illegal_unichrs
74 | if low < sys.maxunicode
75 | ]
76 | illegal_xml_re = re.compile(u'[%s]' % u''.join(illegal_ranges))
77 | return illegal_xml_re.sub('', text)
78 |
79 |
80 | def sanitize(soup=None, html=None):
81 | _allowed_tags = (
82 | 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'bdo',
83 | 'big', 'blockquote', 'br', 'caption', 'center', 'cite',
84 | 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'div',
85 | 'dl', 'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5',
86 | 'h6', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'map', 'ol',
87 | 'p', 'pre', 'q', 's', 'samp', 'small', 'span', 'strike',
88 | 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot',
89 | 'th', 'thead', 'title', 'tr', 'tt', 'u', 'ul', 'var', 'xmp',
90 | 'en-media', 'en-todo', 'en-crypt',
91 | )
92 | _disallowed_attrs = (
93 | 'id', 'class', 'onclick', 'ondblclick', 'rel',
94 | 'accesskey', 'data', 'dynsrc', 'tabindex', 'typeof',
95 | 'property',
96 | )
97 | _protocols = (
98 | 'http', 'https', 'file', 'evernote',
99 | )
100 | if not soup:
101 | soup = BeautifulSoup(html)
102 | for tag in soup.findAll(True):
103 | if tag.name in _allowed_tags:
104 | for attr in _disallowed_attrs:
105 | try:
106 | del tag[attr]
107 | except KeyError:
108 | pass
109 | try:
110 | if not sum(map(
111 | lambda proto: tag['href'].find(proto + '://') == 0,
112 | _protocols)):
113 | del tag['href']
114 | except KeyError:
115 | pass
116 | else:
117 | tag.hidden = True
118 | return clean(reduce(
119 | lambda txt, cur: txt + unicode(cur), soup.contents,
120 | u''))
121 |
122 |
123 | def html_unescape(html):
124 | return HTMLParser().unescape(html)
125 |
126 |
127 | def print_version():
128 | print 'Everpad version: %s' % VERSION
129 | print 'API version: %d' % API_VERSION
130 | print 'Schema version: %d' % SCHEMA_VERSION
131 | sys.exit(0)
132 |
133 |
134 | def get_proxy_config(scheme):
135 | for fmt in ('%s_proxy', '%s_PROXY'):
136 | proxy = os.environ.get(fmt % scheme)
137 | if proxy is not None:
138 | return proxy
139 | return None
140 |
141 |
142 | def prepare_file_path(dest, file_name):
143 | file_path = os.path.join(dest, file_name)
144 | iteration = 0
145 | while os.path.isfile(file_path):
146 | file_path = os.path.join(dest, '%d_%s' % (
147 | iteration, file_name,
148 | ))
149 | iteration += 1
150 | return file_path
151 |
152 |
153 | def resource_filename(file_name):
154 | paths = map(
155 | lambda path: os.path.join(path, file_name),
156 | (
157 | '/opt/extras.ubuntu.com/',
158 | '/usr/local/',
159 | '/usr/',
160 | ),
161 | )
162 | for path in paths:
163 | if os.path.isfile(path):
164 | return path
165 | return pkg_resources.resource_filename(
166 | pkg_resources.Requirement.parse("everpad"), file_name)
167 |
--------------------------------------------------------------------------------
/i18n/ar/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/ar/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/ar/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the PACKAGE package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2012-11-08 18:19+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: everpad/specific/unity/lens.py:34
21 | msgid "Everpad Lens"
22 | msgstr "عدسة إفَرْباد"
23 |
24 | #: everpad/specific/unity/lens.py:35
25 | msgid "Search Everpad"
26 | msgstr "ابحث في إفَرْباد"
27 |
28 | #: everpad/specific/unity/lens.py:55
29 | msgid "Tags"
30 | msgstr "وسوم"
31 |
32 | #: everpad/specific/unity/lens.py:59
33 | msgid "Notebooks"
34 | msgstr "دفاتر"
35 |
36 | #: everpad/specific/unity/lens.py:63
37 | msgid "Places"
38 | msgstr "أماكن"
39 |
40 | #: everpad/specific/unity/lens.py:69
41 | msgid "Pin Notes"
42 | msgstr "مُذَكِّرَات مثبتة"
43 |
44 | #: everpad/specific/unity/lens.py:70
45 | msgid "All Notes"
46 | msgstr "كل المُذَكِّرَات"
47 |
48 | #: everpad/specific/unity/lens.py:86
49 | msgid "Please restart everpad via indicator"
50 | msgstr "رجاءً أعِدْ تشغيل إفَرْباد من منطقة التنبيهات"
51 |
--------------------------------------------------------------------------------
/i18n/ar_EG.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/ar_EG.qm
--------------------------------------------------------------------------------
/i18n/de/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/de/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/de/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # German translation Everpad (DASH)
2 | # Copyright (C) 2013
3 | # This file is distributed under the same license as the Everpad package.
4 | # Simon Allendörfer , 2013
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: 1.0\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2012-11-08 18:19+0200\n"
12 | "PO-Revision-Date: 2013-03-30 15:30+0100\n"
13 | "Last-Translator: Simon Allendörfer \n"
14 | "Language-Team: \n"
15 | "Language: de\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: everpad/specific/unity/lens.py:34
21 | msgid "Everpad Lens"
22 | msgstr "Everpad-Linse"
23 |
24 | #: everpad/specific/unity/lens.py:35
25 | msgid "Search Everpad"
26 | msgstr "Everpad durchsuchen"
27 |
28 | #: everpad/specific/unity/lens.py:55
29 | msgid "Tags"
30 | msgstr "Schlagwörter"
31 |
32 | #: everpad/specific/unity/lens.py:59
33 | msgid "Notebooks"
34 | msgstr "Notizbücher"
35 |
36 | #: everpad/specific/unity/lens.py:63
37 | msgid "Places"
38 | msgstr "Orte"
39 |
40 | #: everpad/specific/unity/lens.py:69
41 | msgid "Pin Notes"
42 | msgstr "Notizbuch anpinnen"
43 |
44 | #: everpad/specific/unity/lens.py:70
45 | msgid "All Notes"
46 | msgstr "Alle Notizen"
47 |
48 | #: everpad/specific/unity/lens.py:86
49 | msgid "Please restart everpad via indicator"
50 | msgstr "Bitte Everpad mit dem Indikator neustarten"
51 |
--------------------------------------------------------------------------------
/i18n/de_AT.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/de_AT.qm
--------------------------------------------------------------------------------
/i18n/de_CH.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/de_CH.qm
--------------------------------------------------------------------------------
/i18n/de_DE.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/de_DE.qm
--------------------------------------------------------------------------------
/i18n/es.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/es.qm
--------------------------------------------------------------------------------
/i18n/es/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/es/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/es/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # Spanish translation for Everpad (DASH)
2 | # Copyright (C) 2013
3 | # This file is distributed under the same license as the Everpad package.
4 | # Jesus M. Castagnetto , 2013
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: 1.0\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2012-11-08 18:19+0200\n"
12 | "PO-Revision-Date: 2013-03-03 09:54-0500\n"
13 | "Last-Translator: Jesus M. Castagnetto \n"
14 | "Language-Team: \n"
15 | "Language: es\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: everpad/specific/unity/lens.py:34
21 | msgid "Everpad Lens"
22 | msgstr "Lente de Everpad"
23 |
24 | #: everpad/specific/unity/lens.py:35
25 | msgid "Search Everpad"
26 | msgstr "Busca en Everpad"
27 |
28 | #: everpad/specific/unity/lens.py:55
29 | msgid "Tags"
30 | msgstr "Etiquetas"
31 |
32 | #: everpad/specific/unity/lens.py:59
33 | msgid "Notebooks"
34 | msgstr "Cuadernos de notas"
35 |
36 | #: everpad/specific/unity/lens.py:63
37 | msgid "Places"
38 | msgstr "Lugares"
39 |
40 | #: everpad/specific/unity/lens.py:69
41 | msgid "Pin Notes"
42 | msgstr "Fijar Notas"
43 |
44 | #: everpad/specific/unity/lens.py:70
45 | msgid "All Notes"
46 | msgstr "Todas las Notas"
47 |
48 | #: everpad/specific/unity/lens.py:86
49 | msgid "Please restart everpad via indicator"
50 | msgstr "Por favor, reiniciar everpad usando el indicador"
51 |
--------------------------------------------------------------------------------
/i18n/ja.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/ja.qm
--------------------------------------------------------------------------------
/i18n/ja/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/ja/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/ja/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the PACKAGE package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2012-11-08 18:19+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: everpad/specific/unity/lens.py:34
21 | msgid "Everpad Lens"
22 | msgstr "Everpadレンズ"
23 |
24 | #: everpad/specific/unity/lens.py:35
25 | msgid "Search Everpad"
26 | msgstr "Everpadの検索"
27 |
28 | #: everpad/specific/unity/lens.py:55
29 | msgid "Tags"
30 | msgstr "タグ"
31 |
32 | #: everpad/specific/unity/lens.py:59
33 | msgid "Notebooks"
34 | msgstr "ノートブック"
35 |
36 | #: everpad/specific/unity/lens.py:63
37 | msgid "Places"
38 | msgstr "場所"
39 |
40 | #: everpad/specific/unity/lens.py:69
41 | msgid "Pin Notes"
42 | msgstr "ピン留めされたノート"
43 |
44 | #: everpad/specific/unity/lens.py:70
45 | msgid "All Notes"
46 | msgstr "全てのノート"
47 |
48 | #: everpad/specific/unity/lens.py:86
49 | msgid "Please restart everpad via indicator"
50 | msgstr "インジケーターからEverpadを再起動してください"
51 |
--------------------------------------------------------------------------------
/i18n/messages.pot:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the PACKAGE package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2012-11-08 18:19+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: everpad/specific/unity/lens.py:34
21 | msgid "Everpad Lens"
22 | msgstr ""
23 |
24 | #: everpad/specific/unity/lens.py:35
25 | msgid "Search Everpad"
26 | msgstr ""
27 |
28 | #: everpad/specific/unity/lens.py:55
29 | msgid "Tags"
30 | msgstr ""
31 |
32 | #: everpad/specific/unity/lens.py:59
33 | msgid "Notebooks"
34 | msgstr ""
35 |
36 | #: everpad/specific/unity/lens.py:63
37 | msgid "Places"
38 | msgstr ""
39 |
40 | #: everpad/specific/unity/lens.py:69
41 | msgid "Pin Notes"
42 | msgstr ""
43 |
44 | #: everpad/specific/unity/lens.py:70
45 | msgid "All Notes"
46 | msgstr ""
47 |
48 | #: everpad/specific/unity/lens.py:86
49 | msgid "Please restart everpad via indicator"
50 | msgstr ""
51 |
--------------------------------------------------------------------------------
/i18n/nl.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/nl.qm
--------------------------------------------------------------------------------
/i18n/ru/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/ru/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/ru/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # Russian translations for PACKAGE package.
2 | # Copyright (C) 2012 ORGANIZATION
3 | # Владимир Яковлев , 2012.
4 | #
5 | msgid ""
6 | msgstr ""
7 | "Project-Id-Version: PACKAGE VERSION\n"
8 | "POT-Creation-Date: 2012-09-09 19:47+MSK\n"
9 | "PO-Revision-Date: 2012-09-09 19:49+0400\n"
10 | "Last-Translator: \n"
11 | "Language-Team: Russian\n"
12 | "MIME-Version: 1.0\n"
13 | "Content-Type: text/plain; charset=UTF-8\n"
14 | "Content-Transfer-Encoding: 8bit\n"
15 | "Generated-By: pygettext.py 1.5\n"
16 | "Language: ru\n"
17 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 |
20 | #: lens.py:29
21 | msgid "Everpad Lens"
22 | msgstr "Линза Everpad"
23 |
24 | #: lens.py:30
25 | msgid "Search Everpad"
26 | msgstr "Искать заметки"
27 |
28 | #: lens.py:39
29 | msgid "Tags"
30 | msgstr "Тэги"
31 |
32 | #: lens.py:43
33 | msgid "Notebooks"
34 | msgstr "Блокноты"
35 |
36 | #: lens.py:47
37 | msgid "Places"
38 | msgstr "Места"
39 |
40 | #: lens.py:54
41 | msgid "Notes"
42 | msgstr "Заметки"
43 |
44 |
--------------------------------------------------------------------------------
/i18n/ru_RU.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/ru_RU.qm
--------------------------------------------------------------------------------
/i18n/zh_CN.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/zh_CN.qm
--------------------------------------------------------------------------------
/i18n/zh_CN/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/zh_CN/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/zh_CN/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # Simplified Chinese translations for PACKAGE package.
2 | # Copyright (C) 2012 ORGANIZATION
3 | # 玛格丽特 苏 , 2012.
4 | #
5 | msgid ""
6 | msgstr ""
7 | "Project-Id-Version: PACKAGE VERSION\n"
8 | "POT-Creation-Date: 2012-09-09 19:47+MSK\n"
9 | "PO-Revision-Date: 2012-09-09 19:49+0400\n"
10 | "Last-Translator: 玛格丽特苏 \n"
11 | "Language-Team: Simplified Chinese\n"
12 | "MIME-Version: 1.0\n"
13 | "Content-Type: text/plain; charset=UTF-8\n"
14 | "Content-Transfer-Encoding: 8bit\n"
15 | "Generated-By: pygettext.py 1.5\n"
16 | "Language: zh_CN\n"
17 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 |
20 | #: lens.py:29
21 | msgid "Everpad Lens"
22 | msgstr "Everpad 透镜"
23 |
24 | #: lens.py:30
25 | msgid "Search Everpad"
26 | msgstr "搜索 Everpad"
27 |
28 | #: lens.py:39
29 | msgid "Tags"
30 | msgstr "标签"
31 |
32 | #: lens.py:43
33 | msgid "Notebooks"
34 | msgstr "笔记本"
35 |
36 | #: lens.py:47
37 | msgid "Places"
38 | msgstr "位置"
39 |
40 | #: lens.py:54
41 | msgid "Notes"
42 | msgstr "笔记"
43 |
44 |
--------------------------------------------------------------------------------
/i18n/zh_TW.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/zh_TW.qm
--------------------------------------------------------------------------------
/i18n/zh_TW/LC_MESSAGES/everpad.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/i18n/zh_TW/LC_MESSAGES/everpad.mo
--------------------------------------------------------------------------------
/i18n/zh_TW/LC_MESSAGES/everpad.po:
--------------------------------------------------------------------------------
1 | # Traditional Chinese translations for PACKAGE package.
2 | # Copyright (C) 2012 ORGANIZATION
3 | # 瑪格麗特 蘇 , 2012.
4 | #
5 | msgid ""
6 | msgstr ""
7 | "Project-Id-Version: PACKAGE VERSION\n"
8 | "POT-Creation-Date: 2012-09-09 19:47+MSK\n"
9 | "PO-Revision-Date: 2012-09-09 19:49+0400\n"
10 | "Last-Translator: 瑪格麗特蘇 \n"
11 | "Language-Team: Traditional Chinese\n"
12 | "MIME-Version: 1.0\n"
13 | "Content-Type: text/plain; charset=UTF-8\n"
14 | "Content-Transfer-Encoding: 8bit\n"
15 | "Generated-By: pygettext.py 1.5\n"
16 | "Language: zh_TW\n"
17 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 |
20 | #: lens.py:29
21 | msgid "Everpad Lens"
22 | msgstr "Everpad 透鏡"
23 |
24 | #: lens.py:30
25 | msgid "Search Everpad"
26 | msgstr "搜索 Everpad"
27 |
28 | #: lens.py:39
29 | msgid "Tags"
30 | msgstr "標籤"
31 |
32 | #: lens.py:43
33 | msgid "Notebooks"
34 | msgstr "筆記本"
35 |
36 | #: lens.py:47
37 | msgid "Places"
38 | msgstr "位置"
39 |
40 | #: lens.py:54
41 | msgid "Notes"
42 | msgstr "筆記"
43 |
44 |
--------------------------------------------------------------------------------
/scripts/install_dbus_services.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Install dbus service files in a custom prefix.
5 | This is needed when installing in user directory, as the standard search
6 | path is not aware of the virtualenv.
7 | """
8 |
9 | from __future__ import with_statement
10 | import sys
11 | import os
12 |
13 | if len(sys.argv) > 1:
14 | services_dir = sys.argv[1]
15 | else:
16 | services_dir = "~/.local/share/dbus-1/services/"
17 |
18 | services_dir = os.path.expanduser(services_dir)
19 | if not os.path.isdir(services_dir):
20 | os.makedirs(services_dir)
21 |
22 |
23 | service_files = {}
24 |
25 | service_files["everpad-app.service"] = """\
26 | [D-BUS Service]
27 | Name=com.everpad.App
28 | Exec={prefix}/bin/everpad
29 | """
30 |
31 | service_files["everpad-provider.service"] = """\
32 | [D-BUS Service]
33 | Name=com.everpad.Provider
34 | Exec={prefix}/bin/everpad-provider
35 | """
36 |
37 | service_files["unity-lens-everpad.service"] = """\
38 | [D-BUS Service]
39 | Name=net.launchpad.Unity.Lens.EverpadLens
40 | Exec={prefix}/bin/everpad-lens
41 | """
42 |
43 | if __name__ == '__main__':
44 | for filename, filetpl in service_files.iteritems():
45 | print "Installing {} -> {}".format(filename, services_dir)
46 | with open(os.path.join(services_dir, filename), 'w') as f:
47 | f.write(filetpl.format(prefix=sys.prefix))
48 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [egg_info]
2 | tag_build = dev
3 | tag_svn_revision = true
4 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 | import os
3 |
4 | version = '2.5'
5 | requirements = [
6 | "BeautifulSoup",
7 | "html2text",
8 | "httplib2",
9 | "keyring",
10 | "py-oauth2 ",
11 | "pysqlite ",
12 | "regex",
13 | "sqlalchemy",
14 | ]
15 | if not 'TRAVIS_CI' in os.environ:
16 | requirements.append('PySide')
17 |
18 |
19 | setup(
20 | name='everpad',
21 | version=version,
22 | description="Ubuntu integrated evernote client",
23 | long_description=open('README.rst').read(),
24 | classifiers=[
25 | 'Programming Language :: Python',
26 | ],
27 | keywords='ubuntu python evernote',
28 | author='Vladimir Yakovlev',
29 | author_email='nvbn.rm@gmail.com',
30 | url='https://github.com/nvbn/everpad/',
31 | license='X11',
32 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
33 | include_package_data=True,
34 | zip_safe=True,
35 | install_requires=requirements,
36 | entry_points={
37 | 'gui_scripts': [
38 | 'everpad=everpad.pad.indicator:main'
39 | ], 'console_scripts': [
40 | 'everpad-lens=everpad.specific.unity.lens:main',
41 | 'everpad-provider=everpad.provider.daemon:main',
42 | ]
43 | },
44 | data_files=[
45 | ('share/icons/hicolor/24x24/actions', [
46 | 'data/editor-icons/everpad-text-bold.png',
47 | 'data/editor-icons/everpad-list-unordered.png',
48 | 'data/editor-icons/everpad-text-strikethrough.png',
49 | 'data/editor-icons/everpad-text-italic.png',
50 | 'data/editor-icons/everpad-list-ordered.png',
51 | 'data/editor-icons/everpad-justify-center.png',
52 | 'data/editor-icons/everpad-justify-left.png',
53 | 'data/editor-icons/everpad-justify-fill.png',
54 | 'data/editor-icons/everpad-text-underline.png',
55 | 'data/editor-icons/everpad-justify-right.png',
56 | 'data/editor-icons/everpad-checkbox.png',
57 | 'data/editor-icons/everpad-link.png',
58 | 'data/editor-icons/everpad-insert-table.png',
59 | 'data/editor-icons/everpad-insert-image.png',
60 | 'data/editor-icons/everpad-pin.png',
61 | ]),
62 | ('share/icons/hicolor/32x32/apps', [
63 | 'data/everpad-black.png', 'data/everpad-mono.png',
64 | ]),
65 | ('share/icons/hicolor/48x48/actions', [
66 | 'data/everpad-file.png',
67 | ]),
68 | ('share/icons/hicolor/64x64/apps', [
69 | 'data/everpad-note.png',
70 | ]),
71 | ('share/icons/hicolor/128x128/apps', [
72 | 'data/everpad.png', 'data/everpad-lens.png',
73 | ]),
74 | ('share/pixmaps', [
75 | 'data/everpad.png', 'data/everpad-mono.png',
76 | 'data/everpad-lens.png', 'data/everpad-note.png',
77 | 'data/everpad-black.png',
78 | ]),
79 | ('share/applications', ['data/everpad.desktop']),
80 | ('share/everpad/i18n/', [
81 | 'i18n/ru_RU.qm',
82 | 'i18n/ar_EG.qm',
83 | 'i18n/zh_CN.qm',
84 | 'i18n/zh_TW.qm',
85 | 'i18n/ja.qm',
86 | 'i18n/es.qm',
87 | 'i18n/de_DE.qm',
88 | 'i18n/de_AT.qm',
89 | 'i18n/de_CH.qm',
90 | ]),
91 | ('share/everpad/', [
92 | 'everpad/pad/editor/editor.html',
93 | ]),
94 | ('share/locale/ru/LC_MESSAGES', ['i18n/ru/LC_MESSAGES/everpad.mo']),
95 | ('share/locale/ar/LC_MESSAGES', ['i18n/ar/LC_MESSAGES/everpad.mo']),
96 | ('share/locale/zh_CN/LC_MESSAGES', ['i18n/zh_CN/LC_MESSAGES/everpad.mo']),
97 | ('share/locale/zh_TW/LC_MESSAGES', ['i18n/zh_TW/LC_MESSAGES/everpad.mo']),
98 | ('share/locale/ja/LC_MESSAGES', ['i18n/ja/LC_MESSAGES/everpad.mo']),
99 | ('share/locale/es/LC_MESSAGES', ['i18n/es/LC_MESSAGES/everpad.mo']),
100 | ('share/locale/de/LC_MESSAGES', ['i18n/de/LC_MESSAGES/everpad.mo']),
101 | ('share/unity/lenses/everpad', ['data/everpad.lens']),
102 | ('share/dbus-1/services', [
103 | 'data/unity-lens-everpad.service',
104 | 'data/everpad-provider.service',
105 | 'data/everpad-app.service',
106 | ]),
107 | ('share/kde4/services/', [
108 | 'data/plasma-runner-everpad.desktop',
109 | ]),
110 | ('share/kde4/apps/plasma/runners/everpad/', [
111 | 'data/metadata.desktop',
112 | ]),
113 | ('share/kde4/apps/plasma/runners/everpad/contents/code/', [
114 | 'everpad/specific/kde/everpad_runner.py',
115 | ]),
116 | ]
117 | )
118 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/tests/__init__.py
--------------------------------------------------------------------------------
/tests/factories.py:
--------------------------------------------------------------------------------
1 | from everpad.provider import models
2 | from everpad import const
3 | from factory.alchemy import SQLAlchemyModelFactory
4 | import factory
5 |
6 |
7 | class NotebookFactory(SQLAlchemyModelFactory):
8 | """Note factory"""
9 | FACTORY_FOR = models.Notebook
10 |
11 | guid = factory.Sequence(lambda n: 'guid{}'.format(n))
12 | name = factory.Sequence(lambda n: 'name{}'.format(n))
13 | default = False
14 | service_created = factory.Sequence(lambda n: n)
15 | service_updated = factory.Sequence(lambda n: n)
16 | action = const.ACTION_NONE
17 | stack = ''
18 |
19 |
20 | class TagFactory(SQLAlchemyModelFactory):
21 | """Tag factory"""
22 | FACTORY_FOR = models.Tag
23 |
24 | guid = factory.Sequence(lambda n: 'guid{}'.format(n))
25 | name = factory.Sequence(lambda n: 'name{}'.format(n))
26 | action = const.ACTION_NONE
27 |
28 |
29 | class ResourceFactory(SQLAlchemyModelFactory):
30 | """Resource factory"""
31 | FACTORY_FOR = models.Resource
32 |
33 | guid = factory.Sequence(lambda n: 'guid{}'.format(n))
34 | hash = factory.Sequence(lambda n: 'hash{}'.format(n))
35 | mime = 'text/plain'
36 | action = const.ACTION_NONE
37 |
38 |
39 | class NoteFactory(SQLAlchemyModelFactory):
40 | """Note factory"""
41 | FACTORY_FOR = models.Note
42 |
43 | guid = factory.Sequence(lambda n: 'guid{}'.format(n))
44 | title = factory.Sequence(lambda n: 'title{}'.format(n))
45 | content = factory.Sequence(lambda n: 'content{}'.format(n))
46 | created = factory.Sequence(lambda n: n)
47 | updated = factory.Sequence(lambda n: n)
48 | updated_local = factory.Sequence(lambda n: n)
49 |
50 |
51 | class PlaceFactory(SQLAlchemyModelFactory):
52 | """Place factory"""
53 | FACTORY_FOR = models.Place
54 |
55 | name = factory.Sequence(lambda n: 'name{}'.format(n))
56 |
57 |
58 | def invoke_session(session):
59 | """Invoke sqlalchemy sessions"""
60 | for _factory in (
61 | NotebookFactory,
62 | TagFactory,
63 | ResourceFactory,
64 | NoteFactory,
65 | PlaceFactory,
66 | ):
67 | _factory.FACTORY_SESSION = session
68 |
--------------------------------------------------------------------------------
/tests/pad/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/tests/pad/__init__.py
--------------------------------------------------------------------------------
/tests/pad/test_editor.py:
--------------------------------------------------------------------------------
1 | from .. import settings
2 | from mock import MagicMock
3 | from PySide.QtCore import QSettings, Signal, QUrl
4 | from PySide.QtGui import QApplication
5 | from everpad.provider.service import ProviderService
6 | from everpad.provider.tools import get_db_session
7 | from everpad.basetypes import (
8 | Note, Notebook, Tag, Resource, Place,
9 | NONE_ID, NONE_VAL,
10 | )
11 | from everpad.provider import models
12 | from everpad.pad.editor import Editor
13 | from everpad.pad.editor.content import set_links
14 | from datetime import datetime
15 | import unittest
16 | import sys
17 | import os
18 |
19 |
20 | class FakeApp(QApplication):
21 | data_changed = Signal()
22 |
23 | def update(self, service):
24 | self.provider = service
25 | self.settings = QSettings('everpad-test', str(datetime.now()))
26 |
27 |
28 | app = FakeApp(sys.argv)
29 |
30 |
31 | CONTENTS = [
32 | u"",
33 | u"123
\xa0\xa0ok",
34 | u"\xa0\xa0123
\xa0\xa0\xa0\xa0ok
",
35 | u"hello, i'am fat
",
36 | u"",
37 | ]
38 |
39 | CHANGING_CONTENTS = [
40 | (u"< a b cd
", u"< a b cd
"),
41 | (u"> a b cd", u"> a b cd"),
42 | (u"ok
ok
"),
43 | ]
44 |
45 | TITLES = [
46 | u"<<ok ok ok",
47 | ''.join([u"verybigtitle"] * 50),
48 | u"okhttps://github.com/nvbn/'),
54 | (u"https://github.com/nvbn/ http://ya.ru/", u'https://github.com/nvbn/ http://ya.ru/'),
55 | (u"
https://github.com/nvbn/
", u"https://github.com/nvbn/
"),
56 | ]
57 |
58 |
59 | if 'test_editor' in os.environ:
60 | class EditorTestCase(unittest.TestCase):
61 | def setUp(self):
62 | self.service = ProviderService()
63 | self.service._session = get_db_session()
64 | models.Note.session = self.service._session
65 | self.app = app
66 | self.app.update(self.service)
67 | notebook = Notebook.from_tuple(
68 | self.service.create_notebook('test', None),
69 | )
70 | self.note = Note.from_tuple(self.service.create_note(Note(
71 | id=NONE_ID,
72 | title='New note',
73 | content="New note content",
74 | tags=[],
75 | notebook=notebook.id,
76 | created=NONE_VAL,
77 | updated=NONE_VAL,
78 | place='',
79 | ).struct))
80 |
81 | def tearDown(self):
82 | if hasattr(self, 'editor'):
83 | self.app.data_changed.disconnect(
84 | self.editor.init_alternatives,
85 | )
86 | del self.app.provider
87 | del self.app
88 |
89 | def test_content_nochange(self):
90 | """Test content nochange"""
91 | self.editor = Editor(self.note)
92 | self.assertEqual(
93 | self.editor.note_edit.content,
94 | "New note content",
95 | )
96 | for content in CONTENTS:
97 | self.editor.note_edit.content = content
98 | self.assertEqual(
99 | self.editor.note_edit.content,
100 | content,
101 | )
102 |
103 | def test_content_changing(self):
104 | """Test content changing"""
105 | self.editor = Editor(self.note)
106 | for prev, current in CHANGING_CONTENTS:
107 | self.editor.note_edit.content = prev
108 | self.assertEqual(
109 | self.editor.note_edit.content,
110 | current,
111 | )
112 |
113 | def test_title_nochange(self):
114 | """Test title nochange"""
115 | self.editor = Editor(self.note)
116 | self.assertEqual(
117 | self.editor.note_edit.title,
118 | "New note",
119 | )
120 | for title in TITLES:
121 | self.editor.note_edit.title = title
122 | self.assertEqual(
123 | self.editor.note_edit.title,
124 | title,
125 | )
126 |
127 | def test_set_links(self):
128 | """Test set links"""
129 | for orig, result in SET_LINKS:
130 | self.assertEqual(
131 | set_links(orig), result,
132 | )
133 |
134 | def test_not_broken_note_links(self):
135 | """Test content nochange"""
136 | content = 'note link'
137 | self.note.content = content
138 | self.editor = Editor(self.note)
139 | self.assertEqual(
140 | self.editor.note_edit.content,
141 | content,
142 | )
143 |
144 | def test_open_note_links(self):
145 | """Test open note links"""
146 | guid = 'guid'
147 | note = Note(
148 | id=123,
149 | )
150 |
151 | self.app.open = MagicMock()
152 | self.service.get_note_by_guid = MagicMock(
153 | return_value=note.struct,
154 | )
155 |
156 | link = "evernote:///view/123/123/{guid}/123/".format(
157 | guid=guid,
158 | )
159 | self.editor = Editor(self.note)
160 | self.editor.note_edit.link_clicked(QUrl(link))
161 |
162 | self.assertEqual(
163 | self.service.get_note_by_guid.call_args[0][0], guid,
164 | )
165 | self.assertEqual(
166 | self.app.open.call_args[0][0].id, note.id,
167 | )
168 | del self.app.open
169 |
--------------------------------------------------------------------------------
/tests/provider/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/tests/provider/__init__.py
--------------------------------------------------------------------------------
/tests/settings/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | import local
3 | except ImportError:
4 | raise ImportError('Copy dist.py to local.py')
5 |
6 |
7 | from everpad import const
8 |
9 |
10 | const.HOST = local.HOST
11 | const.CONSUMER_KEY = local.CONSUMER_KEY
12 | const.CONSUMER_SECRET = local.CONSUMER_SECRET
13 | const.DB_PATH = local.DB_PATH
14 | TOKEN = local.TOKEN
15 |
--------------------------------------------------------------------------------
/tests/settings/ci_local.py:
--------------------------------------------------------------------------------
1 | HOST = 'sandbox.evernote.com'
2 | CONSUMER_KEY = 'nvbn-1422'
3 | CONSUMER_SECRET = 'c17c0979d0054310'
4 | DB_PATH = ':memory:'
5 | TOKEN = 'S=s1:U=6604d:E=145758f3852:C=13e1dde0c54:P=1cd:A=en-devtoken:V=2:H=d2b720cdb06c99a105f937e669ebfc67'
6 |
--------------------------------------------------------------------------------
/tests/settings/dist.py:
--------------------------------------------------------------------------------
1 | HOST = 'sandbox.evernote.com'
2 | CONSUMER_KEY = ''
3 | CONSUMER_SECRET = ''
4 | DB_PATH = ':memory:'
5 | TOKEN = ''
6 |
--------------------------------------------------------------------------------
/tests/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nvbn/everpad/5db96c0f9b7c30ce4f900274f3826fdfa55cbaac/tests/test.png
--------------------------------------------------------------------------------
/tests/test_basetypes.py:
--------------------------------------------------------------------------------
1 | from everpad.basetypes import Tag, DbusSendable
2 | import unittest
3 |
4 |
5 | class TestBaseTypes(unittest.TestCase):
6 | def test_signature(self):
7 | class Fake(DbusSendable):
8 | fields = (
9 | ('id', 'i'),
10 | ('name', 's'),
11 | )
12 | self.assertEqual(
13 | Fake.signature, '(is)',
14 | 'generate signature',
15 | )
16 |
17 | def test_serialise(self):
18 | class Fake(object):
19 | id = 0
20 | name = '123'
21 | tag = Tag.from_obj(Fake())
22 | self.assertEqual(
23 | tag.struct, (0, '123'),
24 | 'serialise to struct',
25 | )
26 |
27 | def test_load(self):
28 | tag = Tag.from_tuple((0, '123'))
29 | self.assertEqual(
30 | tag.name, '123',
31 | 'load from struct',
32 | )
33 |
34 | def test_give(self):
35 | class Fake(object):
36 | id = 0
37 | @property
38 | def id_dbus(self):
39 | return self.id
40 |
41 | @id_dbus.setter
42 | def id_dbus(self, val):
43 | self.id = val + 12
44 | tag = Tag.from_tuple((0, '123'))
45 | obj = Fake()
46 | tag.give_to_obj(obj)
47 | self.assertEqual(
48 | obj.id, 12,
49 | 'give data to object',
50 | )
51 |
--------------------------------------------------------------------------------
/thrift/TSCons.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | from os import path
21 | from SCons.Builder import Builder
22 |
23 | def scons_env(env, add=''):
24 | opath = path.dirname(path.abspath('$TARGET'))
25 | lstr = 'thrift --gen cpp -o ' + opath + ' ' + add + ' $SOURCE'
26 | cppbuild = Builder(action = lstr)
27 | env.Append(BUILDERS = {'ThriftCpp' : cppbuild})
28 |
29 | def gen_cpp(env, dir, file):
30 | scons_env(env)
31 | suffixes = ['_types.h', '_types.cpp']
32 | targets = map(lambda s: 'gen-cpp/' + file + s, suffixes)
33 | return env.ThriftCpp(targets, dir+file+'.thrift')
34 |
--------------------------------------------------------------------------------
/thrift/TSerialization.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | from protocol import TBinaryProtocol
21 | from transport import TTransport
22 |
23 | def serialize(thrift_object, protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()):
24 | transport = TTransport.TMemoryBuffer()
25 | protocol = protocol_factory.getProtocol(transport)
26 | thrift_object.write(protocol)
27 | return transport.getvalue()
28 |
29 | def deserialize(base, buf, protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()):
30 | transport = TTransport.TMemoryBuffer(buf)
31 | protocol = protocol_factory.getProtocol(transport)
32 | base.read(protocol)
33 | return base
34 |
35 |
--------------------------------------------------------------------------------
/thrift/Thrift.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | import sys
21 |
22 | class TType:
23 | STOP = 0
24 | VOID = 1
25 | BOOL = 2
26 | BYTE = 3
27 | I08 = 3
28 | DOUBLE = 4
29 | I16 = 6
30 | I32 = 8
31 | I64 = 10
32 | STRING = 11
33 | UTF7 = 11
34 | STRUCT = 12
35 | MAP = 13
36 | SET = 14
37 | LIST = 15
38 | UTF8 = 16
39 | UTF16 = 17
40 |
41 | _VALUES_TO_NAMES = ( 'STOP',
42 | 'VOID',
43 | 'BOOL',
44 | 'BYTE',
45 | 'DOUBLE',
46 | None,
47 | 'I16',
48 | None,
49 | 'I32',
50 | None,
51 | 'I64',
52 | 'STRING',
53 | 'STRUCT',
54 | 'MAP',
55 | 'SET',
56 | 'LIST',
57 | 'UTF8',
58 | 'UTF16' )
59 |
60 | class TMessageType:
61 | CALL = 1
62 | REPLY = 2
63 | EXCEPTION = 3
64 | ONEWAY = 4
65 |
66 | class TProcessor:
67 |
68 | """Base class for procsessor, which works on two streams."""
69 |
70 | def process(iprot, oprot):
71 | pass
72 |
73 | class TException(Exception):
74 |
75 | """Base class for all thrift exceptions."""
76 |
77 | # BaseException.message is deprecated in Python v[2.6,3.0)
78 | if (2,6,0) <= sys.version_info < (3,0):
79 | def _get_message(self):
80 | return self._message
81 | def _set_message(self, message):
82 | self._message = message
83 | message = property(_get_message, _set_message)
84 |
85 | def __init__(self, message=None):
86 | Exception.__init__(self, message)
87 | self.message = message
88 |
89 | class TApplicationException(TException):
90 |
91 | """Application level thrift exceptions."""
92 |
93 | UNKNOWN = 0
94 | UNKNOWN_METHOD = 1
95 | INVALID_MESSAGE_TYPE = 2
96 | WRONG_METHOD_NAME = 3
97 | BAD_SEQUENCE_ID = 4
98 | MISSING_RESULT = 5
99 | INTERNAL_ERROR = 6
100 | PROTOCOL_ERROR = 7
101 |
102 | def __init__(self, type=UNKNOWN, message=None):
103 | TException.__init__(self, message)
104 | self.type = type
105 |
106 | def __str__(self):
107 | if self.message:
108 | return self.message
109 | elif self.type == self.UNKNOWN_METHOD:
110 | return 'Unknown method'
111 | elif self.type == self.INVALID_MESSAGE_TYPE:
112 | return 'Invalid message type'
113 | elif self.type == self.WRONG_METHOD_NAME:
114 | return 'Wrong method name'
115 | elif self.type == self.BAD_SEQUENCE_ID:
116 | return 'Bad sequence ID'
117 | elif self.type == self.MISSING_RESULT:
118 | return 'Missing result'
119 | else:
120 | return 'Default (unknown) TApplicationException'
121 |
122 | def read(self, iprot):
123 | iprot.readStructBegin()
124 | while True:
125 | (fname, ftype, fid) = iprot.readFieldBegin()
126 | if ftype == TType.STOP:
127 | break
128 | if fid == 1:
129 | if ftype == TType.STRING:
130 | self.message = iprot.readString();
131 | else:
132 | iprot.skip(ftype)
133 | elif fid == 2:
134 | if ftype == TType.I32:
135 | self.type = iprot.readI32();
136 | else:
137 | iprot.skip(ftype)
138 | else:
139 | iprot.skip(ftype)
140 | iprot.readFieldEnd()
141 | iprot.readStructEnd()
142 |
143 | def write(self, oprot):
144 | oprot.writeStructBegin('TApplicationException')
145 | if self.message != None:
146 | oprot.writeFieldBegin('message', TType.STRING, 1)
147 | oprot.writeString(self.message)
148 | oprot.writeFieldEnd()
149 | if self.type != None:
150 | oprot.writeFieldBegin('type', TType.I32, 2)
151 | oprot.writeI32(self.type)
152 | oprot.writeFieldEnd()
153 | oprot.writeFieldStop()
154 | oprot.writeStructEnd()
155 |
--------------------------------------------------------------------------------
/thrift/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | __all__ = ['Thrift', 'TSCons']
21 |
--------------------------------------------------------------------------------
/thrift/protocol/TBase.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | from thrift.Thrift import *
21 | from thrift.protocol import TBinaryProtocol
22 | from thrift.transport import TTransport
23 |
24 | try:
25 | from thrift.protocol import fastbinary
26 | except:
27 | fastbinary = None
28 |
29 | class TBase(object):
30 | __slots__ = []
31 |
32 | def __repr__(self):
33 | L = ['%s=%r' % (key, getattr(self, key))
34 | for key in self.__slots__ ]
35 | return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
36 |
37 | def __eq__(self, other):
38 | if not isinstance(other, self.__class__):
39 | return False
40 | for attr in self.__slots__:
41 | my_val = getattr(self, attr)
42 | other_val = getattr(other, attr)
43 | if my_val != other_val:
44 | return False
45 | return True
46 |
47 | def __ne__(self, other):
48 | return not (self == other)
49 |
50 | def read(self, iprot):
51 | if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
52 | fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
53 | return
54 | iprot.readStruct(self, self.thrift_spec)
55 |
56 | def write(self, oprot):
57 | if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
58 | oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
59 | return
60 | oprot.writeStruct(self, self.thrift_spec)
61 |
62 | class TExceptionBase(Exception):
63 | # old style class so python2.4 can raise exceptions derived from this
64 | # This can't inherit from TBase because of that limitation.
65 | __slots__ = []
66 |
67 | __repr__ = TBase.__repr__.im_func
68 | __eq__ = TBase.__eq__.im_func
69 | __ne__ = TBase.__ne__.im_func
70 | read = TBase.read.im_func
71 | write = TBase.write.im_func
72 |
73 |
--------------------------------------------------------------------------------
/thrift/protocol/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | __all__ = ['TProtocol', 'TBinaryProtocol', 'fastbinary', 'TBase']
21 |
--------------------------------------------------------------------------------
/thrift/server/THttpServer.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | import BaseHTTPServer
21 |
22 | from thrift.server import TServer
23 | from thrift.transport import TTransport
24 |
25 | class ResponseException(Exception):
26 | """Allows handlers to override the HTTP response
27 |
28 | Normally, THttpServer always sends a 200 response. If a handler wants
29 | to override this behavior (e.g., to simulate a misconfigured or
30 | overloaded web server during testing), it can raise a ResponseException.
31 | The function passed to the constructor will be called with the
32 | RequestHandler as its only argument.
33 | """
34 | def __init__(self, handler):
35 | self.handler = handler
36 |
37 |
38 | class THttpServer(TServer.TServer):
39 | """A simple HTTP-based Thrift server
40 |
41 | This class is not very performant, but it is useful (for example) for
42 | acting as a mock version of an Apache-based PHP Thrift endpoint."""
43 |
44 | def __init__(self, processor, server_address,
45 | inputProtocolFactory, outputProtocolFactory = None,
46 | server_class = BaseHTTPServer.HTTPServer):
47 | """Set up protocol factories and HTTP server.
48 |
49 | See BaseHTTPServer for server_address.
50 | See TServer for protocol factories."""
51 |
52 | if outputProtocolFactory is None:
53 | outputProtocolFactory = inputProtocolFactory
54 |
55 | TServer.TServer.__init__(self, processor, None, None, None,
56 | inputProtocolFactory, outputProtocolFactory)
57 |
58 | thttpserver = self
59 |
60 | class RequestHander(BaseHTTPServer.BaseHTTPRequestHandler):
61 | def do_POST(self):
62 | # Don't care about the request path.
63 | itrans = TTransport.TFileObjectTransport(self.rfile)
64 | otrans = TTransport.TFileObjectTransport(self.wfile)
65 | itrans = TTransport.TBufferedTransport(itrans, int(self.headers['Content-Length']))
66 | otrans = TTransport.TMemoryBuffer()
67 | iprot = thttpserver.inputProtocolFactory.getProtocol(itrans)
68 | oprot = thttpserver.outputProtocolFactory.getProtocol(otrans)
69 | try:
70 | thttpserver.processor.process(iprot, oprot)
71 | except ResponseException, exn:
72 | exn.handler(self)
73 | else:
74 | self.send_response(200)
75 | self.send_header("content-type", "application/x-thrift")
76 | self.end_headers()
77 | self.wfile.write(otrans.getvalue())
78 |
79 | self.httpd = server_class(server_address, RequestHander)
80 |
81 | def serve(self):
82 | self.httpd.serve_forever()
83 |
--------------------------------------------------------------------------------
/thrift/server/TProcessPoolServer.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 |
21 | import logging
22 | from multiprocessing import Process, Value, Condition, reduction
23 |
24 | from TServer import TServer
25 | from thrift.transport.TTransport import TTransportException
26 |
27 | class TProcessPoolServer(TServer):
28 |
29 | """
30 | Server with a fixed size pool of worker subprocesses which service requests.
31 | Note that if you need shared state between the handlers - it's up to you!
32 | Written by Dvir Volk, doat.com
33 | """
34 |
35 | def __init__(self, * args):
36 | TServer.__init__(self, *args)
37 | self.numWorkers = 10
38 | self.workers = []
39 | self.isRunning = Value('b', False)
40 | self.stopCondition = Condition()
41 | self.postForkCallback = None
42 |
43 | def setPostForkCallback(self, callback):
44 | if not callable(callback):
45 | raise TypeError("This is not a callback!")
46 | self.postForkCallback = callback
47 |
48 | def setNumWorkers(self, num):
49 | """Set the number of worker threads that should be created"""
50 | self.numWorkers = num
51 |
52 | def workerProcess(self):
53 | """Loop around getting clients from the shared queue and process them."""
54 |
55 | if self.postForkCallback:
56 | self.postForkCallback()
57 |
58 | while self.isRunning.value == True:
59 | try:
60 | client = self.serverTransport.accept()
61 | self.serveClient(client)
62 | except (KeyboardInterrupt, SystemExit):
63 | return 0
64 | except Exception, x:
65 | logging.exception(x)
66 |
67 | def serveClient(self, client):
68 | """Process input/output from a client for as long as possible"""
69 | itrans = self.inputTransportFactory.getTransport(client)
70 | otrans = self.outputTransportFactory.getTransport(client)
71 | iprot = self.inputProtocolFactory.getProtocol(itrans)
72 | oprot = self.outputProtocolFactory.getProtocol(otrans)
73 |
74 | try:
75 | while True:
76 | self.processor.process(iprot, oprot)
77 | except TTransportException, tx:
78 | pass
79 | except Exception, x:
80 | logging.exception(x)
81 |
82 | itrans.close()
83 | otrans.close()
84 |
85 |
86 | def serve(self):
87 | """Start a fixed number of worker threads and put client into a queue"""
88 |
89 | #this is a shared state that can tell the workers to exit when set as false
90 | self.isRunning.value = True
91 |
92 | #first bind and listen to the port
93 | self.serverTransport.listen()
94 |
95 | #fork the children
96 | for i in range(self.numWorkers):
97 | try:
98 | w = Process(target=self.workerProcess)
99 | w.daemon = True
100 | w.start()
101 | self.workers.append(w)
102 | except Exception, x:
103 | logging.exception(x)
104 |
105 | #wait until the condition is set by stop()
106 |
107 | while True:
108 |
109 | self.stopCondition.acquire()
110 | try:
111 | self.stopCondition.wait()
112 | break
113 | except (SystemExit, KeyboardInterrupt):
114 | break
115 | except Exception, x:
116 | logging.exception(x)
117 |
118 | self.isRunning.value = False
119 |
120 | def stop(self):
121 | self.isRunning.value = False
122 | self.stopCondition.acquire()
123 | self.stopCondition.notify()
124 | self.stopCondition.release()
125 |
126 |
--------------------------------------------------------------------------------
/thrift/server/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | __all__ = ['TServer', 'TNonblockingServer']
21 |
--------------------------------------------------------------------------------
/thrift/transport/THttpClient.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | import httplib
21 | import os
22 | import socket
23 | import sys
24 | import urllib
25 | import urlparse
26 | import warnings
27 | from thrift.transport import httpslib # fix ssl issue
28 | from cStringIO import StringIO
29 |
30 | from TTransport import *
31 |
32 |
33 | class THttpClient(TTransportBase):
34 | """Http implementation of TTransport base."""
35 |
36 | def __init__(self, uri_or_host, port=None, path=None, http_proxy=None):
37 | """THttpClient supports two different types constructor parameters.
38 |
39 | THttpClient(host, port, path) - deprecated
40 | THttpClient(uri)
41 |
42 | Only the second supports https.
43 | """
44 | if port is not None:
45 | warnings.warn(
46 | "Please use the THttpClient('http://host:port/path') syntax",
47 | DeprecationWarning,
48 | stacklevel=2)
49 | self.host = uri_or_host
50 | self.port = port
51 | assert path
52 | self.path = path
53 | self.scheme = 'http'
54 | else:
55 | parsed = urlparse.urlparse(uri_or_host)
56 | self.scheme = parsed.scheme
57 | assert self.scheme in ('http', 'https')
58 | if self.scheme == 'http':
59 | self.port = parsed.port or httplib.HTTP_PORT
60 | elif self.scheme == 'https':
61 | self.port = parsed.port or httplib.HTTPS_PORT
62 | self.host = parsed.hostname
63 | self.path = parsed.path
64 | if parsed.query:
65 | self.path += '?%s' % parsed.query
66 | if http_proxy is not None:
67 | http_proxy = urlparse.urlparse(http_proxy)
68 | if http_proxy.scheme == 'http':
69 | if http_proxy.port is None:
70 | http_proxy.port = 8080
71 | else:
72 | raise ValueError("Unsupported Proxy Scheme, %s" % http_proxy.scheme)
73 | self.http_proxy = http_proxy
74 | self.__wbuf = StringIO()
75 | self.__http = None
76 | self.__timeout = None
77 | self.__custom_headers = None
78 |
79 | def open(self):
80 | http_proxy = getattr(self, 'http_proxy', None)
81 | if self.scheme == 'http':
82 | if http_proxy is not None:
83 | self.__http = httplib.HTTP(self.http_proxy.hostname,
84 | self.http_proxy.port)
85 | else:
86 | self.__http = httplib.HTTP(self.host, self.port)
87 | else:
88 | if http_proxy is not None:
89 | self.__http = httpslib.HTTPS(self.http_proxy.hostname,
90 | self.http_proxy.port)
91 | self.__http._conn.set_tunnel(self.host, self.port)
92 | else:
93 | self.__http = httpslib.HTTPS(self.host, self.port)
94 |
95 | def close(self):
96 | self.__http.close()
97 | self.__http = None
98 |
99 | def isOpen(self):
100 | return self.__http is not None
101 |
102 | def setTimeout(self, ms):
103 | if not hasattr(socket, 'getdefaulttimeout'):
104 | raise NotImplementedError
105 |
106 | if ms is None:
107 | self.__timeout = None
108 | else:
109 | self.__timeout = ms / 1000.0
110 |
111 | def setCustomHeaders(self, headers):
112 | self.__custom_headers = headers
113 |
114 | def read(self, sz):
115 | return self.__http.file.read(sz)
116 |
117 | def write(self, buf):
118 | self.__wbuf.write(buf)
119 |
120 | def __withTimeout(f):
121 | def _f(*args, **kwargs):
122 | orig_timeout = socket.getdefaulttimeout()
123 | socket.setdefaulttimeout(args[0].__timeout)
124 | result = f(*args, **kwargs)
125 | socket.setdefaulttimeout(orig_timeout)
126 | return result
127 | return _f
128 |
129 | def flush(self):
130 | if self.isOpen():
131 | self.close()
132 | self.open()
133 |
134 | # Pull data out of buffer
135 | data = self.__wbuf.getvalue()
136 | self.__wbuf = StringIO()
137 |
138 | # HTTP request
139 | if self.scheme == 'http' and self.http_proxy is not None:
140 | # Instead of using CONNECT semantics for HTTP requests, use standard
141 | # http proxy full url semantics.
142 | self.__http.putrequest('POST', 'http://%s:%d%s' %
143 | (self.host, self.port, self.path))
144 | else:
145 | self.__http.putrequest('POST', self.path)
146 |
147 | # Write headers
148 | self.__http.putheader('Host', self.host)
149 | self.__http.putheader('Content-Type', 'application/x-thrift')
150 | self.__http.putheader('Content-Length', str(len(data)))
151 |
152 | if not self.__custom_headers or 'User-Agent' not in self.__custom_headers:
153 | user_agent = 'Python/THttpClient'
154 | script = os.path.basename(sys.argv[0])
155 | if script:
156 | user_agent = '%s (%s)' % (user_agent, urllib.quote(script))
157 | self.__http.putheader('User-Agent', user_agent)
158 |
159 | if self.__custom_headers:
160 | for key, val in self.__custom_headers.iteritems():
161 | self.__http.putheader(key, val)
162 |
163 | self.__http.endheaders()
164 |
165 | # Write payload
166 | self.__http.send(data)
167 |
168 | # Get reply to flush the request
169 | self.code, self.message, self.headers = self.__http.getreply()
170 |
171 | # Decorate if we know how to timeout
172 | if hasattr(socket, 'getdefaulttimeout'):
173 | flush = __withTimeout(flush)
174 |
--------------------------------------------------------------------------------
/thrift/transport/TSocket.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | from TTransport import *
21 | import os
22 | import errno
23 | import socket
24 | import sys
25 |
26 | class TSocketBase(TTransportBase):
27 | def _resolveAddr(self):
28 | if self._unix_socket is not None:
29 | return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None, self._unix_socket)]
30 | else:
31 | return socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
32 |
33 | def close(self):
34 | if self.handle:
35 | self.handle.close()
36 | self.handle = None
37 |
38 | class TSocket(TSocketBase):
39 | """Socket implementation of TTransport base."""
40 |
41 | def __init__(self, host='localhost', port=9090, unix_socket=None):
42 | """Initialize a TSocket
43 |
44 | @param host(str) The host to connect to.
45 | @param port(int) The (TCP) port to connect to.
46 | @param unix_socket(str) The filename of a unix socket to connect to.
47 | (host and port will be ignored.)
48 | """
49 |
50 | self.host = host
51 | self.port = port
52 | self.handle = None
53 | self._unix_socket = unix_socket
54 | self._timeout = None
55 |
56 | def setHandle(self, h):
57 | self.handle = h
58 |
59 | def isOpen(self):
60 | return self.handle is not None
61 |
62 | def setTimeout(self, ms):
63 | if ms is None:
64 | self._timeout = None
65 | else:
66 | self._timeout = ms/1000.0
67 |
68 | if self.handle is not None:
69 | self.handle.settimeout(self._timeout)
70 |
71 | def open(self):
72 | try:
73 | res0 = self._resolveAddr()
74 | for res in res0:
75 | self.handle = socket.socket(res[0], res[1])
76 | self.handle.settimeout(self._timeout)
77 | try:
78 | self.handle.connect(res[4])
79 | except socket.error, e:
80 | if res is not res0[-1]:
81 | continue
82 | else:
83 | raise e
84 | break
85 | except socket.error, e:
86 | if self._unix_socket:
87 | message = 'Could not connect to socket %s' % self._unix_socket
88 | else:
89 | message = 'Could not connect to %s:%d' % (self.host, self.port)
90 | raise TTransportException(type=TTransportException.NOT_OPEN, message=message)
91 |
92 | def read(self, sz):
93 | try:
94 | buff = self.handle.recv(sz)
95 | except socket.error, e:
96 | if (e.args[0] == errno.ECONNRESET and
97 | (sys.platform == 'darwin' or sys.platform.startswith('freebsd'))):
98 | # freebsd and Mach don't follow POSIX semantic of recv
99 | # and fail with ECONNRESET if peer performed shutdown.
100 | # See corresponding comment and code in TSocket::read()
101 | # in lib/cpp/src/transport/TSocket.cpp.
102 | self.close()
103 | # Trigger the check to raise the END_OF_FILE exception below.
104 | buff = ''
105 | else:
106 | raise
107 | if len(buff) == 0:
108 | raise TTransportException(type=TTransportException.END_OF_FILE, message='TSocket read 0 bytes')
109 | return buff
110 |
111 | def write(self, buff):
112 | if not self.handle:
113 | raise TTransportException(type=TTransportException.NOT_OPEN, message='Transport not open')
114 | sent = 0
115 | have = len(buff)
116 | while sent < have:
117 | plus = self.handle.send(buff)
118 | if plus == 0:
119 | raise TTransportException(type=TTransportException.END_OF_FILE, message='TSocket sent 0 bytes')
120 | sent += plus
121 | buff = buff[plus:]
122 |
123 | def flush(self):
124 | pass
125 |
126 | class TServerSocket(TSocketBase, TServerTransportBase):
127 | """Socket implementation of TServerTransport base."""
128 |
129 | def __init__(self, host=None, port=9090, unix_socket=None):
130 | self.host = host
131 | self.port = port
132 | self._unix_socket = unix_socket
133 | self.handle = None
134 |
135 | def listen(self):
136 | res0 = self._resolveAddr()
137 | for res in res0:
138 | if res[0] is socket.AF_INET6 or res is res0[-1]:
139 | break
140 |
141 | # We need remove the old unix socket if the file exists and
142 | # nobody is listening on it.
143 | if self._unix_socket:
144 | tmp = socket.socket(res[0], res[1])
145 | try:
146 | tmp.connect(res[4])
147 | except socket.error, err:
148 | eno, message = err.args
149 | if eno == errno.ECONNREFUSED:
150 | os.unlink(res[4])
151 |
152 | self.handle = socket.socket(res[0], res[1])
153 | self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
154 | if hasattr(self.handle, 'settimeout'):
155 | self.handle.settimeout(None)
156 | self.handle.bind(res[4])
157 | self.handle.listen(128)
158 |
159 | def accept(self):
160 | client, addr = self.handle.accept()
161 | result = TSocket()
162 | result.setHandle(client)
163 | return result
164 |
--------------------------------------------------------------------------------
/thrift/transport/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing,
13 | # software distributed under the License is distributed on an
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | # KIND, either express or implied. See the License for the
16 | # specific language governing permissions and limitations
17 | # under the License.
18 | #
19 |
20 | __all__ = ['TTransport', 'TSocket', 'THttpClient','TZlibTransport', 'httpslib']
21 |
--------------------------------------------------------------------------------
/thrift/transport/httpslib.py:
--------------------------------------------------------------------------------
1 | '''
2 | Replacement of HTTPS client from standart httplib module
3 |
4 | workaround of ssl bug: https://bugs.launchpad.net/ubuntu/source/openssl/bug/965371
5 | Copyright (C) http://docs.python.org/license.html
6 |
7 | Marat Khayrullin
8 | '''
9 |
10 | import httplib
11 | import socket
12 | try:
13 | import ssl
14 | except ImportError:
15 | pass
16 | else:
17 |
18 | class HTTPSConnection(httplib.HTTPConnection):
19 | "This class allows communication via SSL."
20 |
21 | default_port = httplib.HTTPS_PORT
22 |
23 | def __init__(self, host, port=None, key_file=None, cert_file=None,
24 | strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
25 | source_address=None):
26 | httplib.HTTPConnection.__init__(self, host, port, strict, timeout,
27 | source_address)
28 | self.key_file = key_file
29 | self.cert_file = cert_file
30 |
31 | def connect(self):
32 | "Connect to a host on a given (SSL) port."
33 |
34 | sock = socket.create_connection((self.host, self.port),
35 | self.timeout, self.source_address)
36 | if self._tunnel_host:
37 | self.sock = sock
38 | self._tunnel()
39 | self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1)
40 |
41 | #__all__.append("HTTPSConnection")
42 |
43 | class HTTPS(httplib.HTTP):
44 | """Compatibility with 1.5 httplib interface
45 |
46 | Python 1.5.2 did not have an HTTPS class, but it defined an
47 | interface for sending http requests that is also useful for
48 | https.
49 | """
50 |
51 | _connection_class = HTTPSConnection
52 |
53 | def __init__(self, host='', port=None, key_file=None, cert_file=None,
54 | strict=None):
55 | # provide a default host, pass the X509 cert info
56 |
57 | # urf. compensate for bad input.
58 | if port == 0:
59 | port = None
60 | self._setup(self._connection_class(host, port, key_file,
61 | cert_file, strict))
62 |
63 | # we never actually use these for anything, but we keep them
64 | # here for compatibility with post-1.5.2 CVS.
65 | self.key_file = key_file
66 | self.cert_file = cert_file
67 |
--------------------------------------------------------------------------------