pax_global_header 0000666 0000000 0000000 00000000064 14367477523 0014534 g ustar 00root root 0000000 0000000 52 comment=5584f7fc53de2f7e4140e0b7950edbba422eb714
u1db-qt-0.1.7/ 0000775 0000000 0000000 00000000000 14367477523 0013016 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/.gitignore 0000664 0000000 0000000 00000000525 14367477523 0015010 0 ustar 00root root 0000000 0000000 CMakeCache.txt
CMakeFiles
Makefile
cmake_install.cmake
install_manifest.txt
libu1db-qt5.so*
libQtU1db.so*
moc_*.cpp
*.moc
*_automoc.cpp
*.pc
CTestTestfile.cmake
*Test.log
Testing
*-xunit.xml
libu1db-qt.pc.in
tests/test-database
sql.qrc.depends
qrc_sql.cpp
documentation/output
documentation/u1db-qt.qhcp
documentation/u1db-qt.qhp
aDatabase*
u1db-qt-0.1.7/AUTHORS 0000664 0000000 0000000 00000000337 14367477523 0014071 0 ustar 00root root 0000000 0000000 Albert Astals Cid
Christian Dywan
Dalton Durst
Florian Leeber
Guido Berhoerster
Kevin Wright
Marco Trevisan (Treviño)
Marius Gripsgard
Mike Gabriel
Nekhelesh Ramananthan
Olivier Tilloy
Pete Woods
Rodney Dawes
Timo Jyrinki
u1db-qt-0.1.7/CMakeLists.txt 0000664 0000000 0000000 00000002717 14367477523 0015565 0 ustar 00root root 0000000 0000000 cmake_minimum_required(VERSION 3.5)
project(u1db-qt VERSION 0.1.7 LANGUAGES CXX)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
option(ENABLE_WERROR "Treat all build warnings as errors" ON)
# Dependencies
include(FindPkgConfig)
include(GNUInstallDirs)
find_package(Qt5Core REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Sql REQUIRED)
add_definitions(-DWITHQT5=1)
set(U1DB_QT_LIBNAME u1db-qt5)
set(QT_PKGCONFIG_DEPENDENCIES "Qt5Core Qt5Network Qt5Quick Qt5Sql")
set(QT_U1DB_PKGCONFIG_FILE lib${U1DB_QT_LIBNAME}.pc)
# Build flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wundef -std=c++0x")
if(ENABLE_WERROR)
add_compile_options("-Werror")
endif()
add_definitions(-DQT_NO_KEYWORDS)
# Disable building during install to avoid file permission chaos
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1)
add_subdirectory(src)
enable_testing()
add_subdirectory(tests)
add_subdirectory(modules)
add_subdirectory(examples)
add_subdirectory(gallery)
add_subdirectory(documentation)
add_subdirectory(qtcreator)
# PkgConfig file
set (PREFIX "${CMAKE_INSTALL_PREFIX}")
set (EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}")
set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}")
set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
configure_file (libu1db-qt.pc.in
${CMAKE_CURRENT_BINARY_DIR}/${QT_U1DB_PKGCONFIG_FILE} @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${QT_U1DB_PKGCONFIG_FILE}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
u1db-qt-0.1.7/COPYING 0000664 0000000 0000000 00000016743 14367477523 0014064 0 ustar 00root root 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
u1db-qt-0.1.7/ChangeLog 0000664 0000000 0000000 00000172516 14367477523 0014604 0 ustar 00root root 0000000 0000000 2023-02-04 Mike Gabriel
* Release 0.1.7 (HEAD -> main, tag: 0.1.7)
2023-01-19 Guido Berhoerster
* Merge branch 'personal/sunweaver/prepare-0.1.7-release' into 'main'
(b0563a5)
2023-01-19 Mike Gabriel
* CMake: Add ENABLE_WERROR boolean build option. (4f47947)
* d/changelog: Add 0.1.7 pre-release stanza. (3a03edc)
* CMakeLists.txt: Set (next) upstream version in project() macro.
(73023a3)
* CMake: Bump mininum version requirement to 3.5 (a84f744)
* gallery/u1db-qt-gallery.desktop: Drop deprecated Encoding= key.
(1303a8f)
2021-07-30 Dalton Durst
* Merge branch 'ubports/focal_-_build' into 'main' (507a5bf)
2021-06-03 Rodney Dawes
* Rename the qml module package to modern convention. (983b152)
* Remove the licensecheck script and test. (246339a)
* Update build dependency for Lomiri renaming. (bf5fe68)
* Migrate obsolete bzr config to git. (9ae3a74)
* Move Jenkinsfile to debian directory. (9777fd8)
2020-12-17 Florian Leeber
* Merge pull request #3 from ubports/xenial_-_qt-5-12 (b9f6d9e)
2020-12-17 Rodney Dawes
* Update Jenkinsfile (e764bc1)
2020-08-26 Rodney Dawes
* Skip bad tests and set XDG_DATA_HOME for qml tests (bcd0e4f)
* Don't fail on qdoc.err existing (527bfce)
2020-08-25 Rodney Dawes
* Clean up QML module dependencies (869d825)
2020-10-08 Marius Gripsgard
* Fix deprecated use of QByteArray::append(const QString &str) (#1)
(feb494e)
2018-04-16 Marius Gripsgard
* Imported to UBports (8dd87b9)
2015-08-26 CI Train Bot
* Releasing 0.1.5+15.10.20150826.1-0ubuntu1 (2a665f3)
2015-08-26 Marco Trevisan (Treviño)
* Query: allow adding more than one result for each doc, allowing
indexing subfields of objects in a list (73601f1)
* Document: ensure defaults and contents are set when database path
changes
Fixes: #1426178 Approved by: PS Jenkins bot,
Christian Dywan (4a86ed7)
* Database: support parsing of URI paths using something such as
"file://"+ path
Fixes: #1426180 Approved by: PS Jenkins
bot, Christian Dywan (cf28770)
2015-08-26 Christian Dywan
* Mention BUILD_DOC flag in HACKING file Approved by: Nekhelesh
Ramananthan, PS Jenkins bot (9910d64)
* Add new advanced-game example Approved by: PS Jenkins bot,
Christian Dywan (46367df)
2015-03-27 CI Train Bot
* Releasing 0.1.5+15.04.20150327-0ubuntu1 (58c5918)
2015-03-27 Christian Dywan
* Port qdoc syntax to QML annotations
Fixes: #1277601 Approved by: PS
Jenkins bot, Marco Trevisan (Treviño) (b956350)
2015-03-24 Christian Dywan
* Clarify path behavior documentation (bf91710)
2015-03-06 Marco Trevisan (Treviño)
* Index: ensure we've the index set on db when path changes (c30ade7)
* Example7: fix indentation (8f56fc9)
* Query: allow adding more than one result for each doc, allowing
indexing subfields of objects in a list (a55f68f)
* TestDatabase: verify indexing subfields of objects in a list
(9bad27a)
* examples: add example for indexing subfields of objects in a list
(bfacc85)
2015-03-05 Marco Trevisan (Treviño)
* Database: make sure that setting an empty path, moves the db to
memory (1a03297)
* Database: keep the ":memory:" special path saved in
Database::MEMORY_PATH (3469694)
* TestDatabase: open temporary files, to actually create paths
(4fd39b9)
* Database: don't change the internal m_path value when sanitizing,
just keep the user value (81e8778)
2015-03-02 Marco Trevisan (Treviño)
* Fix tests (69c9676)
* Examples: use Qt.resolvedUrl to open databases (4b2315d)
* Document: put current contents on database when path changes and
new one is empty (8b79277)
* Document: ensure defaults are set when database path changes
(61fd82c)
2015-02-28 Marco Trevisan (Treviño)
* Database: support parsing of URI paths using something such as
"file://"+ path (2af9f37)
2015-02-20 CI Train Bot
* Releasing 0.1.5+15.04.20150220-0ubuntu1 (547b8b3)
2015-02-20 Albert Astals Cid
* Make tests pass with Qt 5.4
Fixes: #1423473 Approved by: PS Jenkins
bot, Christian Dywan (4ed66de)
2015-02-19 Albert Astals Cid
* Make it work with Qt 5.4 (5f12594)
2014-11-14 Christian Dywan
* C++ documentation for everyone (59a9110)
* Drop unnecessary include statements (bf990bf)
* C++ documentation for Database (7ab1e20)
2014-11-13 Christian Dywan
* Merge lp:u1db-qt (955abf1)
2014-11-11 CI bot
* Releasing 0.1.5+15.04.20141111~rtm-0ubuntu1 (61a1bf1)
2014-11-11 Christian Dywan
* Create parent folder for full database path
Fixes: 1390166 Approved
by: PS Jenkins bot, Michał Karnicki (e9a62cc)
2014-11-07 Christian Dywan
* Create parent folder for full database path (69c8853)
* Split up C++ Database test cases (5f29bdd)
* Enable stdout for test-database in addition to XML (0f14e45)
2014-08-25 Nekhelesh Ramananthan
* some small fixes (e2b2559)
* Updated game to use latest sdk version (074974e)
2014-07-16 CI bot
* Releasing 0.1.5+14.10.20140716-0ubuntu1 (f6daaee)
2014-07-16 Pete Woods
* Improve database init performance by adding transactions Approved
by: PS Jenkins bot, Christian Dywan (32d41f1)
2014-07-16 Timo Jyrinki
* (sync with archive) No-change rebuild for shlib changes in qtbase
and qtdeclarative. (ac60a38)
2014-07-09 Pete Woods
* Formatting (e5deb3c)
* Manage transactions with ScopedTransaction class, batch inserts
(7f3a3de)
* Add transaction inside putDoc (6b5bb56)
* Add transaction around schema initialization (d1fbd80)
2014-03-14 Timo Jyrinki
* Sync changelog for this special case that got manually uploaded
after the CI Train build. (22ce0b8)
2014-03-14 Christian Dywan
* Revert r113 and update unit test to verify previous behavior
(01a4911)
2014-03-13 Christian Dywan
* Revert r113 and update unit test to verify previous behavior
(eb0bc98)
2014-03-10 Christian Dywan
* Mention apt-get build-dep for installing dependencies (ff3f5b4)
* Reverse query logic to check non-matching and internally convert
between query syntaxes.
Fixes:
https://bugs.launchpad.net/bugs/1214538,
https://bugs.launchpad.net/bugs/1215898,
https://bugs.launchpad.net/bugs/1284194. (43900ef)
2014-03-07 Christian Dywan
* Convert between query syntaxes in generateQueryResults (04e9ed1)
* Add copyright headers to advanced game files (da00d72)
* Add new advanced-game example (154c31c)
2014-03-05 Christian Dywan
* Explicitly verify different query syntaxes and log expected
failures (14a6ac3)
2014-03-03 Christian Dywan
* Add document to fully reproduce the one/two fields issue (d09d3b2)
* Reverse query logic to check for non-matching (a1bc601)
* Merge lp:~kalikiana/u1db-qt/ordering (71c412d)
* Merge lp:u1db-qt (29cb6c7)
* Store whole document contents in the results and unit test that.
Fixes: https://bugs.launchpad.net/bugs/1271973. (9343c15)
2014-02-28 Christian Dywan
* Port qdoc syntax to QML annotations (48d25b7)
2014-02-24 Christian Dywan
* Add wonderious fields test case that ignores the query (3d5ee88)
* Merge lp:u1db-qt (fb660f9)
* Increase consistency in the whole file (03e8a62)
2014-02-19 Christian Dywan
* Merge lp:u1db-qt (b136a6a)
2014-02-18 Christian Dywan
* Query improvements and more advanced example.
Fixes:
https://bugs.launchpad.net/bugs/1266478,
https://bugs.launchpad.net/bugs/1271972,
https://bugs.launchpad.net/bugs/1271977. (5ddf898)
2014-02-17 Christian Dywan
* Use new-style qmlrunner log option to enable stdout. (d42cd47)
* Use deleteDoc to delete document from the bookmarks example
(02e1807)
* Merge lp:u1db-qt (fda6b03)
* Fix glob for installing all examples (80fed24)
* Implement Database.removeDoc method and use it in unit test
(4537c05)
* Sort out build warnings and make them always fatal. (158a4f8)
* Mention declarative test plugin package in HACKING (e23510f)
* Change cmake stanza to a better one (9559eb3)
* Mention branch and dependencies in HACKING (dfdaa1c)
2014-02-07 Christian Dywan
* Mention BUILD_DOC flag in HACKING file (38afc73)
2014-02-06 Christian Dywan
* Add unit tests for top level fields and list in hash (587fc11)
* Override built-in compare to resolve matching and JSON output
(8297863)
2014-01-31 Christian Dywan
* Replace example 4 with a bookmarks sample with several query styles
(156c6df)
* Handle string list in index and query (631099f)
* Check for original field to avoid ".foo" as the field (bc261eb)
2014-01-24 Christian Dywan
* Merge lp:u1db-qt (476f4dc)
* Store whole document contents in the results and unit test that
(1839422)
* Rename removeDoc to deleteDoc (40f1ddc)
* Merge lp:u1db-qt (f649f45)
* Merge lp:u1db-qt (f0da1d9)
2014-01-23 Christian Dywan
* Adopt xvfb.sh script from ui toolkit to run tests (a22446a)
2014-01-22 Christian Dywan
* Invoke xvfb.sh via sh (4bf3b40)
* Add xvfb and libgl1-mesa-dri build deps (cca7fa5)
* Adopt xvfb.sh script from ui toolkit to run tests (399d666)
2013-11-25 Christian Dywan
* Fallback targetDb to NULL to ensure it's always initialized
(95b3f90)
2013-11-22 Christian Dywan
* Make build warnings always fatal (d962bba)
* Swap private variables in Synchronizer to match constructor
(b7566f6)
* Drop unused increaseVectorClockRev (c6dc229)
* Implement Database.removeDoc method and use it in unit test
(e57aa9c)
2013-09-16 Automatic PS uploader
* Releasing 0.1.5+13.10.20130916-0ubuntu1 (revision 106 from
lp:u1db-qt). (08f5ad6)
* Releasing 0.1.5+13.10.20130916-0ubuntu1, based on r106 (b72d079)
2013-09-06 Christian Dywan
* Update developer website URL.
Fixes:
https://bugs.launchpad.net/bugs/1209372. (1c51de1)
* Add devel to developer website URL (a00b87e)
2013-09-04 Christian Dywan
* Unit test query bugs related to the ordering of fields (7b4f07d)
* Use new-style qmlrunner log option to enable stdout (5fa2b67)
2013-08-27 Automatic PS uploader
* Releasing 0.1.5+13.10.20130827-0ubuntu1 (revision 104 from
lp:u1db-qt). (77bc257)
* Releasing 0.1.5+13.10.20130827-0ubuntu1, based on r104 (4edd93d)
2013-08-27 Christian Dywan
* Always omit deleted/ empty Query results and update tests.
Fixes:
https://bugs.launchpad.net/bugs/1213013. (1fcfa92)
* Always omit deleted/ empty Query results and update tests (2352fad)
* Update developer website URL (28de61d)
2013-08-21 Automatic PS uploader
* Releasing 0.1.5+13.10.20130821.1-0ubuntu1 (revision 102 from
lp:u1db-qt). (63752df)
* Releasing 0.1.5+13.10.20130821.1-0ubuntu1, based on r102 (6daed93)
2013-08-21 Christian Dywan
* Use QStandardPaths to find a good path for relative filenames.
Fixes: https://bugs.launchpad.net/bugs/1206935. (9b70a65)
2013-08-14 Automatic PS uploader
* Releasing 0.1.5+13.10.20130814.1-0ubuntu1 (revision 100 from
lp:u1db-qt). (d49e363)
* Releasing 0.1.5+13.10.20130814.1-0ubuntu1, based on r100 (b3e7862)
2013-08-14 Christian Dywan
* Use QStandardPaths to find a good path for relative filenames
(7e1547e)
2013-08-14 Kevin Wright
* This branch merges the latest trunk with the code for
synchronization of databases.
Fixes:
https://bugs.launchpad.net/bugs/1184628. (c3bdca0)
2013-08-12 Kevin Wright
* Fixed one test to remove a warning. (efe7d58)
* Modified tests. In one instance a query property was missing from a
Query element (in tst_query.qml), and in another occurance
the test needed to be updated to reflect a different
return value (in test_database.qml). (298fd7e)
* Fixed qdoc warnings. (14cd7e1)
2013-08-09 Kevin Wright
* Changed qdoc markup class to qmlclass in synchronizer.cpp.
(30e6d18)
* Modified database.cpp to fix a small bug re: setError. (1446a59)
* Modified database.cpp so that all query.exec() statements are
covered by setError. Unfortunately setSerror cannot be the
return value in some places, because the method is void or
something other than a string. (7fed594)
* Modified database.cpp so that all query.exec() statements have
either qDebug output of the error message, or are covered
by setError. Eventually error handling should be more
consistant, and perhaps utilize the same mechanism as
sync_output in the Synchronizer class. Some functions in
Database are used side by side with other functions in
Synchronizer, so perhaps this is a wise idea where
applicable. (2e9c454)
* Modified several source files to fix warnings from qdoc. (6f5188b)
* Modified 'errors'. Changed to 'sync_output' (since not everything
was an error); changed from QString to QVariantMap that
includes more meta-data; and created more generic output
descriptions (i.e. removed most hard data and placed into
meta-data instead). This approach is still primarily
intented as a mechanism for application developers to
troubleshoot (or simply keep themselves/users informed of
background activity), but can be utilized within the
plugin itself as well (e.g. log files, console output). It
does not presently include error codes (where appropriate)
but should, and additionally it needs to be documented so
people can take advantage of it and use it properly. The
example u1db-qt-example-6.qml uses it as of this commit,
but is only applying the output message and not any of the
meta-data. (19a3b3f)
2013-08-08 Kevin Wright
* Added 'U1Db-Qt v1.0' to the raw header information sent to the
server. (d67e417)
* Updated code comments in src/synchronizer.cpp to be more
descriptive with respect to the instructions for how to
use the plugin with the python implementation (the server
part to be specific). (56a0af1)
* Removed an unecessary code from src/synchronizer.cpp, and updated
putDoc in src/database.cpp to return QString instead of
int. (790c15c)
* Removed an unecessary function call and code comment from
src/database.cpp. (19e7149)
* Removed some additional unecessary code comments. (9ed3ea9)
* Removed some unecessary code comments. (16dfdcd)
* Fixed an error in src/synchronizer.cpp where the plugin would not
build because Synchronizer::source was not initialized.
(edcb887)
* Removed some debug output from src/synchronizer.cpp. (ea3a591)
* More edits to merge synchronization changes with trunk. (87310f8)
* Merged synchronization changes with trunk. (fe96b68)
2013-08-07 Kevin Wright
* Fixed u1db-qt-example-6.qml to better refelect the latest sync
related code. The example works with the python server of
u1db itself. Some basic instructions were added to the
code comments of synchronizer.cpp. (c9e389d)
* As of this commit the basic two way synchronization between a local
source database and a remote target database is working,
to a minimal, but less than perfect degree. Some of the
meta data that would normally be used in a sync
transaction is not yet being utilized properly, or updated
properly at the end of the transaction. However, the
post/get functionality is now doing more or less as it
should, and the function of updating the document contents
on either end of the transation is working (but work
remains to ensure it is being done accurately -- probably
partly tied into the meta-data issue mentioned earlier).
Some good effort has been made to add appropriate code
commenting / qdoc markup that explains things in detail,
but has not been run through qdoc or proof read to ensure
it is up to date or follows a logical flow in any way.
Most changes are in the code for Synchronizer itself, but
some modification to Database is also included in this
commit. (455e69a)
2013-08-07 Automatic PS uploader
* Releasing 0.1.5+13.10.20130807-0ubuntu1 (revision 98 from
lp:u1db-qt). (b399b8d)
* Releasing 0.1.5+13.10.20130807-0ubuntu1, based on r98 (efe153f)
2013-08-01 Timo Jyrinki
* Rename the QML plugin to qtdeclarative5-u1db1.0 according to the
new convention. Tweak short descriptions a bit. (b6ff6ba)
* Rename the QML plugin to qtdeclarative5-u1db1.0 according to the
new convention. Tweak short descriptions a bit. (2b78656)
2013-07-31 Timo Jyrinki
* Split QML plugin, install into multi-arch directories. (715c0c8)
* Split QML plugin, install into multi-arch directories. (1fbd364)
* Fix license (non-"later"), remove redundant debian/* section,
remove non-needed rules lines, add blank lines to the
changelog. (cb45bea)
* Fix license (non-"later"), remove redundant debian/* section,
remove non-needed rules lines, add blank lines to the
changelog. (077773f)
2013-07-30 Timo Jyrinki
* Bootstrap, fix debian/copyright, run wrap-and-sort -a -t. (e918cc5)
* Bootstrap, fix debian/copyright, run wrap-and-sort -a -t (c582717)
2013-07-30 Christian Dywan
* Resolve missing copyright and license details.
Fixes:
https://bugs.launchpad.net/bugs/1195299. (c9b2727)
2013-07-29 Christian Dywan
* Don't check licenses of generated files in CMakeFiles (b12ca65)
* Check licenses of sh files and add license to qmltestrunner wrapper
(35f87bb)
* Add checklicense.sh test and add licenses to CSS files and python
wrapper (10903e5)
* Debian packaging tweaks according to
https://wiki.ubuntu.com/DailyRelease/InlinePackaging.
Fixes: https://bugs.launchpad.net/bugs/1195299. (242e458)
* Drop debian/source/format file (644026a)
* Change to downstream version, quilt and "split" package (dd91159)
* Make debian/copyright not look like a template (943bccf)
* Resolve lintian complaints about debian/control (a4b0788)
* Don't exceed 80 columns in debian/changelog (15d4263)
2013-07-18 Christian Dywan
* Empty commit (60d01fe)
2013-07-17 Christian Dywan
* Empty commit (714bfc8)
* Empty commit (5fb53f8)
2013-07-16 Christian Dywan
* Empty commit (42aec1a)
* Uncomment unreliable unicode warning test (7c45e29)
2013-07-04 Kevin Wright
* This commit continues the work to support the second stage of a
local to remote sync transaction, where the client (aka
source) begins sharing information about new data since
the previous sync between the two databases (if any
previous transaction occured). The post is sending
complete data as of this commit, but the server is still
replying with a bad request error. On the surface
everything appears to comply with the high level
architecture documentation, but something is obviously
still incorrect. (bf9109e)
* This commit continues the work to support the second stage of a
local to remote sync transaction, where the client (aka
source) begins sharing information about new data since
the previous sync between the two databases (if any
previous transaction occured). The code now is up to the
point of initiating the post to the remote server, but at
this time is showing bad request errors. The post is not
sending complete data at this time, which may be the
reason for the bad request error. (a4a63e7)
* Added the initial steps for sync with a remote database. There are
several steps in the archtitecure for remote sync, whereby
the server and client communicate information between each
other (e.g. previous sync transations, new data). This
commit consists of the first step, where the client
initiates the sync transaction and the server responds
with known information about previous syncs if any. Also
in this commit is the first roughed in code for the second
stage of a sync transaction, where the client (aka source)
begins sharing information about new data since the
previous sync between the two databases (if any previous
transaction occured). (e68160e)
2013-07-01 Christian Dywan
* Debian packaging tweaks according to
https://wiki.ubuntu.com/DailyRelease/InlinePackaging
(93287b4)
2013-06-27 Kevin Wright
* Fixed a regression relating to the active source Database for
Synchronizer. In the function syncLocalToLocal is the
ability to overide the main source database (the 'source'
property) with another database when a query is defined
within an individual 'target' definition (with the key
'source_query'). (7845a89)
2013-06-26 Kevin Wright
* Migrated getSyncLogInfoFromLocalDb function from Synchronizer class
to Database class, and renamed getSyncLogInfo. Previously
this class used the path of a database file rather than an
instance of an active Database class' database connection.
With the function now hosted by the Database class itself
the path of the file and opening of the database
connection within the scope of the function is no longer
required (i.e. the class' active database connection is
used instead). This function is used by the Synchronizer
class' getLastSyncInformation function to retrieve data
from the source and target databases. The data represents
information that one database has about the other the last
time they synced (if ever). (d10023d)
* Migrated listTransactionsSince function from Syncrhonizer class to
Database class. Previously this class used the path of a
database file rather than an instance of an active
Database class' database connection. With the function now
hosted by the Database class itself the path of the file
and opening of the database connection within the scope of
the function is no longer required (i.e. the class' active
database connection is used instead). (437564d)
2013-06-19 Kevin Wright
* Modified Query class so that it updates its model properly. Added
support for passing Query types to Synchronizer (the Index
and Database types are also supported and can be extracted
from the Query object). (57531e6)
2013-06-18 Kevin Wright
* A few light modifiactions only... (5fbffc0)
* Synchronizer will now sync two databases that have never been
synced before. (c75f11e)
* With this commit the Synchronization class will sync two previously
synced local databases. Still missing is the ability to
sync two databases that have not been synced before, but
this should be fixed in the next commit. Also missing is
the functionality to update the sync log information in
each database. That should be added to the next commit's
features as well. (40af19b)
* More modifications towards completing the functionality for local
to local database synchronization. This commit adds the
first ability to sync between two databases. The two
databases are compared and new documents, or new
modifications to existing documents, are added to one or
the other of the target/source database. Missing from this
commit is the updating of the doc_rev field in the
document table. (69556c4)
* Added functionality to generate a list of known transactions from a
specific generation number, for a particular database.
This is necessary for comparing new documents, updates to
documents etc. since the last time two databases synched,
or the first sync between the two. As of this commit the
query is done directly on the database files rather than
using an instance of the Database class. Since it is a
read only activity it is not necessary to have a live
instance of the Database class, and therefore it would be
possible to work on databases that are not currently
active in the application. (8ab2415)
* Cleaned up some of the code and comments related to the changes for
transactions within the Database class, as well as added
some additional descriptive comments to ensure clarity.
Those comments may be used with qdoc, but are not heavily
marked up or optimised for that purpose. (fe6e02c)
* Further modifications to Database class to ensure properly working
transactions. With this commit it appears transaction_log
table and sqlite_sequence table are updated as expected
when a new transaction is commited. Transactions are
created whenever a document is inserted or updated in the
database. (3e2ff88)
* Fixed Document class so that it more properly handles transactions
and generation. (5cf3d60)
2013-06-17 Kevin Wright
* More big changes for Synchronizer. Added a logging mechanism that
allows the developer to have access to errors and other
log messages accumulated during the sync procedure. Fixed
a problem in Database where the document revision
(doc_rev) was incorrect (it was hard coded to always be
7???). The core local to local synchronization
functionality is at the point where the target database is
queried for the sync history with the source database. The
next functionality to be added is to compare the known
information from each database (sync history, new
transactions) to determine what updates need to go into
the source database as well as new documents. Following
that conflict resolution and final re-sync (if needed). A
great attempt has been made to try and match the logic of
local to remote sync as best possible, so that when it
comes time to add that functionality the delta will be
minimal (and more code can be shared between the two
approaches). Example 6 has been updated to include the
logging functionality. (3a8d6dd)
2013-06-07 Kevin Wright
* Heavily modified Synchronizer to use a list to define the database
to sync (aka targets property). Each element in the list
is a map, representing a database to sync -- on other
words one source database can sync with multiple target
databases in one sync session (one by one). Each map
contains key and value pairs for various properties.
Because the developer is free to create any key and value
pair, and add any type for the value, checks are done to
ensure that the minimal mandatory keys are present and
that each value is the correct type. As of this commit no
actual synchronizing is done for either local or remote
targets. However, the functionality towards synchronizing
with a local target has begun -- current up to the point
of checking the existance of the local database file,
attempting to open it and retrieve its uid. Manual testing
of current functionality during development was
accomplished using u1db-qt-example-6.qml under the
examples folder. (3a1ef3d)
2013-05-16 Kevin Wright
* Modified Synchronizer to support batch sync of remote and local
targets. Split identification of local targets as Database
elements (via each one's id property), and remote targets
as QStrings representing their respective url -- both
remote and local targets will be contained within QLists
(remote_targets and local_targets), which can be set via
the QML interface. (2c0ac7f)
2013-05-13 Christian Dywan
* Add .index file for cross-linking to -doc package and set URL.
(3e04993)
* Follow up on ui-toolkit doc index rename (be3f7ac)
* Depend on ubuntu-ui-toolkit-doc at build-time for cross-linking
(5fa7d82)
* Merge lp:u1db-qt (9496e8b)
* Shuffle Index::setExpression to ensure Index is defined.
Fixes:
https://bugs.launchpad.net/bugs/1177357. (3780b30)
2013-05-10 Christian Dywan
* Run query unit tests against a local filename (818757d)
* Shuffle Index::setExpression to ensure Index is defined (cbfe8ee)
2013-05-10 Kevin Wright
* Changed a few lines in Index::setExpression to fix a bug where an
Index was not being pointed to as expected, and missed
having itself defined properly. (5ff6a2b)
2013-05-03 Christian Dywan
* Add qch file for QtCreator to -dev package. (09b637c)
2013-05-02 Christian Dywan
* Configure 3 content pages shown in QtCreator (4454d0f)
2013-05-02 Kevin Wright
* Modified u1db-qt-example-6 to better reflect the Schronizer element
functionality. Added an extra ListView that is aligned
with a second database. Included a button that modifies
the Synchronizer's synchronize property to true when
pressed. The Synchronizer's source is the first database,
the target is the second and the resolver is the first,
which means the target database will be updated with the
content from the first after sync is initiated. (232ba65)
2013-05-02 Christian Dywan
* Add qch file for QtCreator to -dev package (1dc7e5d)
* Install qch documentation for QtCreator (d938ae1)
2013-05-02 Kevin Wright
* Added u1db-qt-example-6 to reflect the Schronizer element. There is
a qml example files and qdoc tutorial file. The latter
still needs to be updated with the specific details of how
to work with the Synchronizer element. (e182e9f)
* Fixed some small errors in defining properties for Synchronizer as
well as one error in the plugin file to support
Synchronizer itself. (6a31872)
2013-05-02 Christian Dywan
* Use MainView as root item in all examples. (0981a86)
* Drop unused id and objectName uses in examples (cf8c79a)
* Use MainView as root item in all examples (434cdc0)
2013-05-02 Kevin Wright
* Committing skeleton of Synchronizer element's code. Synchronizer is
intended to sync two databases -- a 'source' data base and
a local or remote 'target' database. The initial aim is to
design the Synchronizer element so that it supports
synchronizing through changes in a small set of
properties, rather than relying on the developer using the
API to need to rely heavily on any procedural code.
(2efb92a)
2013-05-01 Christian Dywan
* Cross-link to Ubuntu Components in overview and tutorial (a297dc4)
* Add .index file for cross-linking to -doc package and set URL
(1f5de66)
2013-05-02 Christian Dywan
* Warn only once on wrong query type and test cases. (ec913da)
2013-05-01 Christian Dywan
* Add QtCreator Application templates and plugins.qmltypes to -dev
package. (4b1b13f)
* Warn only once on wrong query type and test cases (c7a36b8)
* Split up custom commands and disable build during install (6a0d958)
* Install generated plugins.qmltypes for QtCreator (e66a454)
* Enable and fix number and defaults behavior. (451daff)
2013-04-30 Christian Dywan
* Add QtCreator Application templates to -dev package (6583fb6)
2013-04-29 Christian Dywan
* Emit warnings on unexpected types in query (d9ac73d)
* Correct keyword query test definitions (cca4509)
* Wrap qmltestrunner instead of a separate warning test case
(cd4dd50)
* Ensure connection isn't re-used and test expected warnings
(dd9fc5b)
* Numeric queries are fine (92efcc7)
* The query default is equal to '*' (3d6b3a7)
2013-04-25 Christian Dywan
* Introduce Query.documents property and add test cases. (33d999d)
* Add missing qdoc comment for Query.documents (be3f12d)
* Introduce Query.documents property and add test cases (f6f37b9)
* Hide private Index and Query methods from the outside (61f5c82)
2013-04-24 Christian Dywan
* Move enable_testing back to toplevel, otherwise it quietly does
nothing. (e124900)
* Move enable_testing back to toplevel, otherwise it quietly does
nothing (cf07e93)
2013-04-23 Christian Dywan
* Remove range property for now, it's not implemented. (b91b878)
* Work-around to make build fail if qdoc warns (c5aeab5)
* Mark up Javascript-only snippets as \code not \qml (0e50ddb)
* Document Query::results property (a20bb6e)
* Merge 'Initial ground work splitting off query tests' (1c22668)
* Sort out documentation of signals and properties (83f4021)
* Remove dataIndexed and documentsAvailable signals (f800580)
* Don't bother calling 'assistant', leave it to install (e1678cb)
* Remove redundant documentCount variable (0ee1780)
* Fix un-closed comment in concepts.qdoc (25d676b)
* Rename the overview - qdoc expects a page titled All Modules
(2db78ae)
* Fill in documentation for remaining C++ class methods (a29b74f)
* Initial ground work splitting off query tests. (6f9dab0)
* Remove range property for now, it's not implemented' (7053260)
2013-04-23 Kevin Wright
* Modified example qml files to reduce number of warnings from qdoc.
Changed each example's tutorial file from \example to
\page and modified all \qml tags to \code tags. (2c01ed8)
* Modified example qml files to reduce number of warnings from qdoc.
Changed each example's tutorial file from \example to
\page and modified all \qml tags to \code tags. (42e863b)
2013-04-23 Christian Dywan
* Packaging refactoring. (e82b5e4)
* Don't hide qdoc errors from default output (8b4c9aa)
* Enable building the Python module via BUILD_PYTHON (3258663)
* Bump changelog for -doc and -examples addition (1046e02)
* Split off CMakeLists rules for src into src (181a32b)
* Move documentation generation to CMakeLists.txt (f8ce664)
2013-04-22 Christian Dywan
* Stricter approach to installing HTML docs. (af451ae)
* Stricter approach to installing HTML docs (71ef790)
* Add Index and Query to barebones C++ test (747afed)
* Split off query tests, add Query.results property (3c3fd4e)
* Mark internal methods, mention model feature and document
parameters. (bc83bd9)
* Mark internal methods, mention model feature and document
parameters (575cafa)
* Ignore token Q_INVOKABLE in qdoc (6ff8d6f)
* Add Design Concepts to the overview. (8b069b4)
* Add Design Concepts to the overview (bf2a6f5)
* Replaces classes page with a real overview. (d49a93d)
* Replace classes page with a proper overview (812b8e2)
* Implement tabbed example gallery and install to example package.
(71c1f1c)
* Install HTML docs to doc/html (07ea7ff)
2013-04-19 Kevin Wright
* Added support for 'Query' to use string, list or map. Removed
'queries' property. (165cbd3)
* Fixed u1db-qt-example-5.qml -- an incorrect modification was
accidently pushed, where a query was designed to not
return anything (which is fine for testing but not
desireable for the example suite). (3397470)
* Added support for 'Query' to use string, list or map. Removed
'queries' property. (816184e)
2013-04-19 Christian Dywan
* Rename u1db{,-qt}-gallery.desktop (8aa4c74)
2013-04-18 Christian Dywan
* Install U1Db example gallery and add to example package (01f462e)
2013-04-18 Kevin Wright
* Modified Query to split up the querying functionality across more
reasonable and intuitive methods. Additionally changed
some method names and variable names to be more intuitive
(e.g. checkMapMatch to queryField) (3da0020)
* Modified Query to update the proposed new querying functionality.
The new modification fixes a bug where an else clause was
returning incorrect results. The clause was changed to an
if else to check for the existance of the wildcard first
and then the proper boolean value determined after that.
Additionally changed the surrounding function to default
to return false if none of the checks are true (previously
it was set to true). (bc290b5)
* Modified Query to support the querying functionality. In order to
support proper querying on QVariantMaps a property
'queries' was added to Query. The property is a list that
includes key value pairs matching a field/sub-field with a
query statement. Example: queries:
[{id:*},{message:Hel*}]. Query supports exact match and
wild cards (i.e. *). Additionaly added a queries
definition to the Query element in
examples/u1db-qt-example-5/u1db-qt-example-5.qml, but
includes a not that the property is proposed. The
'queries' property would replace the 'query' property
(which does not support query on QVariantMaps). (06e683d)
2013-04-17 Christian Dywan
* Implement a tabbed example gallery (a48b70d)
2013-04-12 Christian Dywan
* Add qttools5-dev-tools to build dependencies (e3abab7)
* Add -doc.install needed for -doc package (185f693)
* Add -examples package containing the QML examples. (f73bbf5)
* Build docs in binary dir, BUILD_DOCS option, add -doc package
(68ef781)
* Add -examples package containing the QML examples (3366fc2)
* Install QML sources for all examples (f0c619f)
* Moves sources to src folder. (8dbff73)
* Move sources from root into src folder (98f93f5)
* Bail out of dataInvalidated if index is unset.
Fixes:
https://bugs.launchpad.net/bugs/1168034. (b3d403e)
* Bail out of dataInvalidated if index is unset (3a2e944)
2013-04-12 Kevin Wright
* Added in additional information to
examples/u1db-qt-example-5/u1db-qt-example-5.qdoc
concerning Index and Query elements. Additionally, updated
some of the other text in the same file, fixed formatting
issues, and ensured there was consistancy between all the
files and example code for u1db-qt-example-5. (0090d2c)
* Added qdoc sections to
examples/u1db-qt-example-5/u1db-qt-example-5.qdoc.
(72ab748)
* Fixed some formatting problems in the qdoc markup and qml within
all files under examples/u1db-qt-example-5. (699ef87)
* Fixed a small ending tag error in the qdoc markup within
examples/u1db-qt-example-5/u1db-qt-example-5.qdoc.
(46b7036)
* Added in additional information to
examples/u1db-qt-example-5/u1db-qt-example-5.qdoc
concerning Index and Query elements. Additionally, updated
some of the other text in the same file, fixed formatting
issues, and ensured there was consistancy between all the
files and example code for u1db-qt-example-5. (4547831)
2013-04-10 Olivier Tilloy
* Install missing header for the -dev package.
Fixes:
https://bugs.launchpad.net/bugs/1167395. (0a2ef31)
* Install missing header for the -dev package. (bbc2b76)
* Fix pkg-config requirements.
Fixes:
https://bugs.launchpad.net/bugs/1167247. (0068c2a)
* Remove a useless addition to the list of pkg-config requirements.
(914941e)
* Fix pkg-config requirements. (66d19f3)
2013-04-09 Christian Dywan
* Enable unit tests during Debian package build. (1ab7b19)
* Add libqt5sql5-sqlite to build dependencies (83af943)
2013-04-09 Kevin Wright
* Moved qdoc markup from qml example files into .qdoc files. Provided
a sub-directory under 'examples' for each existing example
that includes both the example qml and corresponding qdoc
file. Modified u1db.qdocconf to account for these changes.
Additionally modified u1db.qdocconf to automatically add
the correct styles to each html output file (required some
additional modifications to postheader, footer etc. to
support the style sheets). (be56b7b)
2013-04-09 Christian Dywan
* Add dependencies providing QtQuickTest and QtQuick2 (42e2da4)
* Add qt5-default build dependency (ae93327)
* Add qtdeclarative5-dev-tools build dep for qmltestrunner (f0a6107)
* Enable unit tests during Debian package build (75d11da)
2013-04-09 Kevin Wright
* Modified examples/u1db-qt-example-5.qml so that it is
representative of a tutorial demonstrating Index and other
U1Db-Qt functionality. Additionally added appropriate qdoc
markup for the tutorial to the file. (35cba5c)
2013-04-08 Kevin Wright
* Moved qdoc markup from qml example files into .qdoc files. Provided
a sub-directory under 'examples' for each existing example
that includes both the example qml and corresponding qdoc
file. Modified u1db.qdocconf to account for these changes.
Additionally modified u1db.qdocconf to automatically add
the correct styles to each html output file (required some
additional modifications to postheader, footer etc. to
support the style sheets). (e592495)
* Created initial example to demonstrate index functionality.
(8d3706a)
* Created initial index functionality. Modified source for both Index
and Query. Within the Index source, QVariantMaps are
generated (based on the index expressions), using
appropriate data, and put into a QList, which is used by
Query::data as its return value. Some known issues:
currently will match on any index expression criteria
(rather than on all criteria), and will not recognize new
databases / documents (but has no problems with existing
ones). (67651d3)
2013-04-07 Kevin Wright
* Modified examples/u1db-qt-example-5.qml, with additional edits to
the section of the tutorial qdoc markup regarding ListView
and delegates. (bb4b8a2)
* Modified examples/u1db-qt-example-5.qml to edit a small portion of
the tutorial qdoc markup (regarding ListView and
delegates). (43800ef)
* Modified examples/u1db-qt-example-5.qml to add more tutorial qdoc
markup, up to the end of describing the variations of the
Document instances used in the example. (a321328)
* Modified examples/u1db-qt-example-5.qml. Made mostly minor
modifications to the tutorial qdoc markup. (b3a6810)
* Modified examples/u1db-qt-example-5.qml to include additional
tutorial qdoc markup, focussed on describing support for
embedded lists within the Document element's 'default'
property definition. (0e611d4)
* Modified examples/u1db-qt-example-5.qml to include code markup in
the qdoc sections, surrounding appropriate example
snippets. (fd0bc19)
* Modified examples/u1db-qt-example-5.qml so that it is
representative of a tutorial demonstrating Index and other
U1Db-Qt functionality. Additionally added appropriate qdoc
markup for the tutorial to the file. (93029c7)
2013-04-06 Kevin Wright
* Fixed a critical issue with Index and Query where newly created
databases / documents were not being realized in the
model. (143fa29)
* Created initial example to demonstrate index functionality.
(c7c9967)
* Fixed index.h and query.h by adding back in some important ifdef
Q_DOC conditions that were accidently overwritten.
Additionally added back in one qdoc 'inmodule' markup line
that was accidently erased in query.cpp. (5d0d945)
2013-04-05 Kevin Wright
* Created initial index functionality. Modified source for both Index
and Query. Within the Index source, QVariantMaps are
generated (based on the index expressions), using
appropriate data, and put into a QList, which is used by
Query::data as its return value. Some known issues:
currently will match on any index expression criteria
(rather than on all criteria), and will not recognize new
databases / documents (but has no problems with existing
ones). (1dafd70)
* Added documentation/u1db.tutorial.qdoc file. This document
initially represents an all-in-one cheatsheet for U1Db-Qt,
which includes reference, tutorial, examples, best
practice etc. (9dd3b30)
2013-04-05 Christian Dywan
* Install docs into QtAssistant, add Ubuntu style and fix Concepts.
(5f31086)
2013-04-05 Kevin Wright
* Added documentation/u1db.tutorial.qdoc file. This document
initially represents an all-in-one cheatsheet for U1Db-Qt,
which includes reference, tutorial, examples, best
practice etc. (f62176f)
2013-04-04 Christian Dywan
* Revamp concepts page markup to parse correctly (a34495c)
* Use Ubuntu style orange base.css stylesheet (d9f887a)
* Install docs into QtAssistant when running make doc (3b3a8b0)
2013-04-03 Christian Dywan
* Implement 'make doc'; fix C++ classes to be parsed by qdoc
(9006cce)
* qdoc for Database, Document, Index and Query. (b7fad06)
* Add qdoc comments to Query class (24b3559)
* Add qdoc comments to Index class (51466ee)
* Add introduction to Document class (4382fe0)
2013-04-02 Christian Dywan
* Add qtdoc comments to Document class (abe5f74)
* Add qtdoc comments for all methods and summary of Database
(70481e5)
* Document Variant/ JSON conversion behavior (45c97af)
2013-03-28 Christian Dywan
* Use consistent test database naming and disable getIndexKeys test.
(5120383)
* Fix libu1db-qt5-1.install, erroneous install target and Python
module (c1392e1)
* Comment out getIndexKeys tests for now until it's fixed (137d07b)
* Consistently name databases 'aDatabase*' to easily bzr ignore them
(bdc9ea2)
2013-03-27 Christian Dywan
* Add upstream test runner and Python C++ wrapper module (2c35dbd)
* Add .install files, corrected dependencies, drop obsolete
-DWITHQT5=1 (ae25dc1)
2013-03-20 Christian Dywan
* Add example 2b using sub-fields for a model (3cae86d)
* Add qdocconf for generating HTML docs (4497215)
* Modify test delegates to avoid binding loop errors (a83ddc1)
* Implement docLoaded and fillDocument test case (5ddbdc8)
* Implement Database::getIndexKeys (work-in-progress) (1142393)
2013-03-19 Kevin Wright
* Added examples/u1db-qt-example-2b.qml to demonstrate the creation
and querying of sub-fields in a Document. Discovered a bug
where the database, document contents do not appear to
update properly if a change has been made and the contents
contain sub-fields. (6c881e4)
2013-03-18 Kevin Wright
* Created qdocconf file for generating html documentation. Ran qdoc
using the qdocconf file. Created QtHelpProject and
QtHelpCollectionProject files to create documentation
files for QtCreator. Ran qhelpgenerator and
qcollectiongenerator using appropriate files. Some work
still needs to be done here to get the proper
documentation builds for QtCreator and fine tune the html
docs. Additionally some of the examples need to have the
qdoc markup edited, as the tags are not correct. (c11679a)
2013-03-14 Christian Dywan
* Fill in concept docs based on tutorial in example 4 (f9246c1)
* Placeholders for documentation pages (56ef559)
* Add example 4 based on example 3 and using a ListView (16c66bd)
2013-03-14 Kevin Wright
* Modified the proposed topic list in documentation/concepts.qdoc,
and reordered existing topics so they are in some logical
order. (5ef1f70)
* Added start of overiew content to documentation/concepts.qdoc that
describes U1DB, and the differences between the standard
U1DB implementations and U1Db-Qt implementation. (80a5779)
* Added concept content to documentation/concepts.qdoc. Most of the
content was copied from the tutorial text in
examples/u1db-qt-exmaple-4.qml as a starting point. Also
roughed in a table of suggested topics. (d7d63d9)
2013-03-13 Kevin Wright
* Added placeholder docs in documentation for architecture, best
practices, concepts, overview and troubleshooting. These
should be started ASAP, even if the amount of information
at this time is minimal. (def9967)
* Added a document to u1db-qt-example4.qml to represent bookmarks. A
ListView will be added to the second tab in the
application and docId vlues from the database will be
stored there. The user can select one of those docIds and
the main tab will be updated accordingly. (9bef281)
* Added the start of u1db-qt-example-4.qml. This example will begin
to use more MainView tabs and introduce a bookmark feature
in a ListView. (8e3bf4a)
2013-03-13 Christian Dywan
* Updated debian rules, changelog, and control for initial package
(3241dfa)
2013-03-13 Kevin Wright
* Updated debian rules, changelog, and control files to create
initial package. (62c3fac)
2013-03-12 Christian Dywan
* Add moc files to list of files for 'make clean' (a020f0e)
* Store dbschema.sql in a resource (dfe5066)
* example 3: Implement next/ previous and describe getting docId's
(5856bb7)
* example 3: Implement 'Home' and add an opening summary (fc1a13b)
2013-03-12 Kevin Wright
* Put dbschema.sql into a qrc file and made it available as a
resource. Also modified database.cpp to make use of it as
a resource rather than a local file. (2623159)
* Resolved https://bugs.launchpad.net/u1db-qt/+bug/1153938 by
removing clear button from address bar in
u1db-qt-example-3.qml (TextField component's
hasClearButton : bool property set to false). (8a2bd0d)
* Fixed a small code comment error so that the section will be picked
up by qdoc. (3416704)
* Improved u1db-qt-example-3.qml by adding the functionality for
retrieving the next and previous documents in the
database. Additionally some tutorial text was added to
describe the retireving of docId values from the database,
which this new functionality makes use of. (f676a3a)
2013-03-11 Kevin Wright
* Improved u1db-qt-example-3.qml by adding in the ability to return
to 'home', added more tutorial text (including an opening
summmary and learning outcomes), and removed some console
output calls. (8f3becb)
2013-03-11 Christian Dywan
* example 3: Save content for current id key represented in the
address bar (0002fe2)
2013-03-11 Kevin Wright
* Improved u1db-qt-example-3.qml by adding in the functionality to
save content to the database for the current id key
represented in the address bar. (2536548)
2013-03-11 Christian Dywan
* example3: Update database based on the key the user types (95f4a08)
2013-03-11 Kevin Wright
* Improved u1db-qt-example-3.qml by adding in the functionality to
update the content text area with data from the database,
based on the key the user types into the address bar.
Additionally more tutorial content was added to the code
comments. (5ef8898)
2013-03-08 Kevin Wright
* Added more tutorial text to u1db-qt-example-3, modified some of the
existing text to reflect recent code changes, and fixed
some typos. (e0d486c)
* Continued to add more markup for the tutorial content that goes
with u1db-qt-example-3. Also modified some properties of
the TextArea representing the document content so that it
is more visually pleasing. (7374b64)
2013-03-08 Christian Dywan
* Split off getIndexExpressions from putIndex (567731a)
* Removed unecessary ListView elements example 3 and reworded
tutorial text (e4b811b)
2013-03-08 Kevin Wright
* Modified u1db-qt-example-3 to generate a new document entry in the
database with a key / name / address that corresponds to
user input in the address bar, but without changing the
application's global document ('aDocument'). (59d46e7)
* Modified u1db-qt-example-3 so that the address bar will display the
object's key (aka the search string or name/address of a
document in the database) rather than the return value of
the search. (c6a2b6b)
* Removed unecessary ListView elements from u1db-qt-example-3 and
reworded some of the tutorial text. Removing those
elements has also removed part of the tutorial markup, and
new text will need to be added. (7910158)
2013-03-07 Christian Dywan
* Add a basic HACKING file about building and testing (d737f1e)
* Save changes to document in example 3 (0d5ef4e)
* Bring example 3 closer to needs of a web browser (0dc29cd)
2013-03-07 Kevin Wright
* Added bidirectional change functionality between Document and
address bar. (a000d45)
* Fixed some corruption in one of the example files. (ef7ab20)
* More modifications to u1db-qt-example-3.qml to better reflect more
real world use cases. (ef11cf6)
* Added more functionality to u1db-qt-example-3, began to change
application behaviour so that it evolves into a
demonstration of how to store and navigate documents in a
database. This would be mildly similar to functionality
required for a basic web browser. (fcb0818)
2013-03-06 Christian Dywan
* Changed interval in example 2 to 5000 (e94aed9)
* Adding 2 more examples and inline documentation (c6026cb)
* Fix updating Document whenever contents changes (9129189)
2013-03-06 Kevin Wright
* Increased the interval value in example 2 to from 5 to 5000
(611312d)
* Fixed some more formatting issues in example code, changed some
code comments in the example code, reduced the interval
value in example 2 to 5 from 500, and ensured every
delegate in each example is using 'text: contents.hello'
(891c9ec)
2013-03-06 Christian Dywan
* listDocs should return docId's not contents (be0a5f5)
2013-03-06 Kevin Wright
* Added more to the layout of example 3, to begin representing the
desired functionality. Added navigation buttons and an
area to enter text that will be saved (and to display text
when navigating the document history). Also cleaned up
tabs in the qml file and replaced with spaces (1d00c87)
2013-03-05 Kevin Wright
* Added a third example to demonstrate use with TextInput elements,
modified other examples, and continued to add doc markup
for tutorials for each example. (139dcad)
* Added a third example to demonstrate use with TextInput elements,
modified other examples, and continued to add doc markup
for tutorials for each example. (6f9c8a8)
2013-03-04 Christian Dywan
* Documentation comments for the first example (7254e92)
2013-03-04 Kevin Wright
* Added a new example that dynamically creates documents, modified
the original example slightly, and added some
documentation markup (61fff54)
2013-03-04 Christian Dywan
* Work-around new rows not appearing in the view (d3e732b)
2013-03-01 Christian Dywan
* Use getDocUnchecked in Document to avoid false errors (2d385fe)
* Replace Database hash table with OFFSET lookup (de83c46)
* Make getDocUnchecked return variant map like getDoc (ac94ddb)
* Fix off by one inserting into hash and fix example delegate
(60bc8d9)
2013-03-01 Kevin Wright
* Fixed off by one problem when inserting records into hash table,
and modified the example to display retrieved contents of
the document from the database into the ListView. This
unfortunately only works for updates to the database or
inserts into the database, and not existing, unmodified
records. (4fd2d49)
2013-02-28 Christian Dywan
* Remove spurious log calls from QML test (990230d)
* Index.dataInvalidated and Query.QAbstractListModel (e024e54)
* Drop Query.database property; Index is enough (be273e1)
* First example using Ubuntu components (ae9770b)
* Implement 'create' to create documents with defaults (f852c31)
* Don't start exclusive transaction - to be revisited (d814677)
2013-02-28 Kevin Wright
* Added first example to demonstrate basic usage. This initial commit
does not do much on the surface. (7a4c9ab)
2013-02-27 Christian Dywan
* Have Document reflect changes via docChanged (3f352d8)
2013-02-26 Christian Dywan
* Add contents property to Document, analogous to delegate (dbc8dc9)
* Make Index put indexes on demand, merge putIndex functions
(4037889)
* Rename s/create/put/Index(List) to avoid conflict with
QAbstractListModel (1fcd8aa)
* Database::createIndexList/ createIndex implementations (b8bf76f)
* Always check if QVariant/ QJsonDocument converted (5712d04)
* Expose 'docId' and 'contents' to delegate (d2a9d01)
2013-02-26 Kevin Wright
* Modified comment: int Database::createIndex(QString index_name,
QStringList expressions), which corresponds to the u1db.c
function: int u1db_create_index(u1database *db, const char
*index_name, int n_expressions, ...). It is being marked
as INCOMPLETE (1b169f3)
* Added the function int Database::createIndex(u1database *db, const
char *index_name, QStringList expressions). It is
currently marked INCOMPLETE. (05463f0)
* Added the function int Database::createIndexList(QString
index_name, QStringList expressions), which corresponds to
the u1db.c function: int u1db_create_index_list(u1database
*db, const char *index_name, int n_expressions, const char
**expressions). It is currently marked INCOMPLETE.
(cc4cf13)
2013-02-26 Christian Dywan
* Install to QT_INSTALL_QML, qmlscene/ testrunner doesn't see
QT_INSTALL_IMPORTS (fd639b8)
2013-02-25 Christian Dywan
* Fix QT_BEGIN_NAMESPACE_U1DB, use QT_PREPEND_NAMESPACE_U1DB
(883684d)
2013-02-22 Christian Dywan
* QAbstractListModel support in Database + model test fixes (312470b)
2013-02-19 Christian Dywan
* Put without docId, suppressing false errors (d01d260)
2013-02-18 Christian Dywan
* Introduce setError/ errorChanged/ lastError (600e212)
* Verify docId against regex before storing (eab6d10)
* Init db when changing name and "bind" correctly (45be6be)
2013-02-15 Christian Dywan
* Split off global macro boilerplate into global.h (4cae982)
* Add Query and Index classes based on proposed API (48b9756)
2013-02-14 Christian Dywan
* Add empty U1Db.Document class (83b8ad9)
* Methods for get/ put/ list docs, schema, json (12b2721)
2013-01-31 Christian Dywan
* QML plugin boilerplate, one C++ class, empty unit tests (45c4e8a)
u1db-qt-0.1.7/HACKING 0000664 0000000 0000000 00000002061 14367477523 0014004 0 ustar 00root root 0000000 0000000 *** Building and installing ***
Get the source:
bzr branch lp:u1db-qt
Build dependencies to have:
ubuntu-sdk-libs-dev, dbus-test-runner, qtdeclarative5-test-plugin
All of these can also be installed with one command:
sudo apt-get build-dep u1db-qt
Build it:
mkdir _build; cd _build; cmake ..
make
sudo make install
Build docs:
make doc
Unit tests:
make check
Note: both docs and tests must pass for branches proposed for merging.
*** Further debugging and testing ***
By hand:
qmlscene -I ./modules examples/u1db-qt-example-1.qml
qmltestrunner -import ./modules
Partial upstream test case support:
make
env PYTHONPATH=/path/to/u1db ./tests/test-upstream.py
Use Python U1Db for testing:
python -c "import u1db;db=u1db.open('pDb',create=False);print(db.get_all_docs());print(db.list_indexes())"
python -c "import u1db;db=u1db.open('pDb',create=True);db.create_index('by-phone', 'gents.phone');doc3 = db.create_doc({'gents': [ {'name': 'Mary', 'phone': '12345'}, {'name': 'Peter', 'phone': '54321'} ]})"
u1db-qt-0.1.7/debian/ 0000775 0000000 0000000 00000000000 14367477523 0014240 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/debian/Jenkinsfile 0000664 0000000 0000000 00000000101 14367477523 0016414 0 ustar 00root root 0000000 0000000 @Library('ubports-build-tools') _
buildAndProvideDebianPackage()
u1db-qt-0.1.7/debian/changelog 0000664 0000000 0000000 00000017345 14367477523 0016124 0 ustar 00root root 0000000 0000000 u1db-qt (0.1.7) unstable; urgency=medium
* Upstream-provided Debian package for u1db-qt. See upstream
ChangeLog for recent changes.
-- UBports developers Sat, 04 Feb 2023 16:51:50 +0100
u1db-qt (0.1.6+ubports) xenial; urgency=medium
* Imported to UBports
-- UBports auto importer Mon, 16 Apr 2018 13:33:42 +0200
u1db-qt (0.1.5+15.10.20150826.1-0ubuntu1) wily; urgency=medium
[ CI Train Bot ]
* New rebuild forced.
[ Christian Dywan ]
* Add new advanced-game example
* Mention BUILD_DOC flag in HACKING file
[ Marco Trevisan (Treviño) ]
* Database: support parsing of URI paths using something such as
"file://"+ path (LP: #1426180)
* Document: ensure defaults and contents are set when database path
changes (LP: #1426178)
* Query: allow adding more than one result for each doc, allowing
indexing subfields of objects in a list (LP: #1322156)
[ Nekhelesh Ramananthan ]
* Add new advanced-game example
-- CI Train Bot Wed, 26 Aug 2015 16:34:30 +0000
u1db-qt (0.1.5+15.04.20150327-0ubuntu1) vivid; urgency=medium
[ Christian Dywan ]
* Port qdoc syntax to QML annotations (LP: #1277601)
* Port qdoc syntax to QML annotations (LP: #1277601)
-- CI Train Bot Fri, 27 Mar 2015 08:22:26 +0000
u1db-qt (0.1.5+15.04.20150220-0ubuntu1) vivid; urgency=medium
[ Albert Astals Cid ]
* Make tests pass with Qt 5.4 (LP: #1423473)
-- CI Train Bot Fri, 20 Feb 2015 10:26:14 +0000
u1db-qt (0.1.5+15.04.20141111~rtm-0ubuntu1) 14.09; urgency=low
[ Christian Dywan ]
* Create parent folder for full database path (LP: #1390166)
-- Ubuntu daily release Tue, 11 Nov 2014 15:27:42 +0000
u1db-qt (0.1.5+14.10.20140716-0ubuntu1) utopic; urgency=low
[ Pete Woods ]
* Improve database init performance by adding transactions
[ Christian Dywan ]
* Adopt xvfb.sh script from ui toolkit to run tests
* Sort out build warnings and make them always fatal.
* Implement Database.removeDoc method and use it in unit test
Functionally this is equivalent to replacing the doc with an empty
one. (LP: #1243395)
* Use new-style qmlrunner log option to enable stdout.
* Query improvements and more advanced example. (LP: #1271977,
#1271972, #1266478)
* Store whole document contents in the results and unit test that.
(LP: #1271973)
* Reverse query logic to check non-matching and internally convert
between query syntaxes. (LP: #1284194, #1214538, #1215898)
* Revert r113 and update unit test to verify previous behavior
-- Ubuntu daily release Wed, 16 Jul 2014 07:52:34 +0000
u1db-qt (0.1.5+14.04.20140313-0ubuntu2) trusty; urgency=medium
* No-change rebuild for shlib changes in qtbase and qtdeclarative.
-- Ricardo Salveti de Araujo Mon, 14 Apr 2014 13:45:06 -0300
u1db-qt (0.1.5+14.04.20140313-0ubuntu1) trusty; urgency=low
[ CI bot ]
* No change rebuild against Qt 5.2.1.
[ Christian Dywan ]
* Adopt xvfb.sh script from ui toolkit to run tests
* Sort out build warnings and make them always fatal.
* Implement Database.removeDoc method and use it in unit test
Functionally this is equivalent to replacing the doc with an empty
one. (LP: #1243395)
* Use new-style qmlrunner log option to enable stdout.
* Query improvements and more advanced example. (LP: #1271977,
#1271972, #1266478)
* Store whole document contents in the results and unit test that.
(LP: #1271973)
* Reverse query logic to check non-matching and internally convert
between query syntaxes. (LP: #1284194, #1214538, #1215898)
* Revert r113 and update unit test to verify previous behavior
-- Ubuntu daily release Thu, 13 Mar 2014 23:12:40 +0000
u1db-qt (0.1.5+14.04.20140306-0ubuntu1) trusty; urgency=low
[ CI bot ]
* No change rebuild against Qt 5.2.1.
[ Ubuntu daily release ]
* New rebuild forced
[ Christian Dywan ]
* Adopt xvfb.sh script from ui toolkit to run tests
* Sort out build warnings and make them always fatal.
* Implement Database.removeDoc method and use it in unit test
Functionally this is equivalent to replacing the doc with an empty
one. (LP: #1243395)
* Use new-style qmlrunner log option to enable stdout.
* Query improvements and more advanced example. (LP: #1271977,
#1271972, #1266478)
* Store whole document contents in the results and unit test that.
(LP: #1271973)
-- Ubuntu daily release Thu, 06 Mar 2014 08:25:22 +0000
u1db-qt (0.1.5+13.10.20130916-0ubuntu1) saucy; urgency=low
[ Christian Dywan ]
* Update developer website URL. (LP: #1209372)
[ Ubuntu daily release ]
* Automatic snapshot from revision 106
-- Ubuntu daily release Mon, 16 Sep 2013 11:34:54 +0000
u1db-qt (0.1.5+13.10.20130827-0ubuntu1) saucy; urgency=low
[ Christian Dywan ]
* Always omit deleted/ empty Query results and update tests. (LP:
#1213013)
[ Ubuntu daily release ]
* Automatic snapshot from revision 104
-- Ubuntu daily release Tue, 27 Aug 2013 19:11:29 +0000
u1db-qt (0.1.5+13.10.20130821.1-0ubuntu1) saucy; urgency=low
[ Christian Dywan ]
* Use QStandardPaths to find a good path for relative filenames. (LP:
#1206935)
[ Ubuntu daily release ]
* Automatic snapshot from revision 102
-- Ubuntu daily release Wed, 21 Aug 2013 16:18:56 +0000
u1db-qt (0.1.5+13.10.20130814.1-0ubuntu1) saucy; urgency=low
[ Kevin Wright ]
* This branch merges the latest trunk with the code for
synchronization of databases. (LP: #1184628)
[ Ubuntu daily release ]
* Automatic snapshot from revision 100
-- Ubuntu daily release Wed, 14 Aug 2013 14:30:45 +0000
u1db-qt (0.1.5+13.10.20130807-0ubuntu1) saucy; urgency=low
[ Christian Dywan ]
* Debian packaging tweaks according to
https://wiki.ubuntu.com/DailyRelease/InlinePackaging
[ Timo Jyrinki ]
* Automatic snapshot from revision 96 (bootstrap)
* Rename the QML plugin to qtdeclarative5-u1db1.0 according to the new
convention. Tweak short descriptions a bit.
[ Ubuntu daily release ]
* Automatic snapshot from revision 98
-- Ubuntu daily release Wed, 07 Aug 2013 10:28:13 +0000
u1db-qt (0.1.5) quantal; urgency=low
* Add .index file for cross-linking to -doc package and set URL
-- Christian Dywan Mon, 13 May 2013 10:58:01 +0200
u1db-qt (0.1.4) quantal; urgency=low
* Add qch file for QtCreator to -dev package
-- Christian Dywan Wed, 02 May 2013 14:21:33 -0700
u1db-qt (0.1.3) quantal; urgency=low
* Add QtCreator Application templates and plugins.qmltypes to -dev package
-- Christian Dywan Wed, 01 May 2013 10:40:08 -0700
u1db-qt (0.1.2) quantal; urgency=low
* Documentation packages -doc and -examples
-- Christian Dywan Tue, 23 Apr 2013 12:58:11 +0100
u1db-qt (0.1.1-0ubuntu1) quantal; urgency=low
* Added .install files
* Corrected dependencies
* Drop obsolete -DWITHQT5=1 flag
-- Christian Dywan Wed, 27 Mar 2013 12:37:06 +0100
u1db-qt (0.1.1-0ubuntu0) quantal; urgency=low
* Fixed a packaging issue. The following still apply from 0.1:
* Initial Alpha (Unstable) Release
* API subject to change
* API not feature complete
* Basic functionality is available, but does not yet meet the API specification and may still contain bugs
-- Kevin Wright Tue, 12 Mar 2013 12:15:00 +0100
u1db-qt-0.1.7/debian/compat 0000664 0000000 0000000 00000000002 14367477523 0015436 0 ustar 00root root 0000000 0000000 9
u1db-qt-0.1.7/debian/control 0000664 0000000 0000000 00000005341 14367477523 0015646 0 ustar 00root root 0000000 0000000 Source: u1db-qt
Section: libs
Priority: optional
Maintainer: Ubuntu Developers
Build-Depends: cmake (>= 2.8.6),
dbus-test-runner,
debhelper (>= 9),
devscripts,
libqt5sql5-sqlite,
qml-module-qtquick2,
qml-module-qttest,
qt5-default,
qtbase5-dev,
qtdeclarative5-dev,
qtdeclarative5-dev-tools,
qttools5-dev-tools,
lomiri-ui-toolkit-doc,
xvfb,
libgl1-mesa-dri,
Standards-Version: 3.9.4
Homepage: https://launchpad.net/u1db-qt
Vcs-Bzr: https://code.launchpad.net/u1db-qt/trunk
Package: libu1db-qt5-3
Architecture: any
Multi-Arch: same
Pre-Depends: dpkg (>= 1.15.6~),
${misc:Pre-Depends},
Depends: libqt5sql5-sqlite,
qml-module-qtquick2,
${misc:Depends},
${shlibs:Depends},
Description: Qt5 binding for U1DB - shared library
Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).
.
This package contains the shared library.
Package: qml-module-u1db
Architecture: any
Multi-Arch: same
Breaks: qtdeclarative5-u1db1.0
Replaces: qtdeclarative5-u1db1.0
Pre-Depends: dpkg (>= 1.15.6~),
${misc:Pre-Depends},
Depends: libqt5sql5-sqlite,
qml-module-qtquick2,
${misc:Depends},
${shlibs:Depends},
Description: Qt5 binding for U1DB - QtQuick2 QML plugin
Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).
.
This package contains the QML plugin.
Package: libu1db-qt5-dev
Section: libdevel
Architecture: any
Depends: libu1db-qt5-3 (= ${binary:Version}),
qtbase5-dev,
qtdeclarative5-dev,
${misc:Depends},
Description: Qt5 binding and QtQuick2 plugin for U1DB - development files
Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).
.
This package contains the developer headers for the Qt binding for U1DB
Package: libu1db-qt5-examples
Section: doc
Architecture: all
Depends: libu1db-qt5-3 (>= ${source:Version}),
${misc:Depends},
Description: Qt5 binding and QtQuick2 plugin for U1DB - examples
Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).
.
This package contains examples showcasing the use of the Qt binding for U1DB
Package: libu1db-qt5-doc
Section: doc
Architecture: all
Depends: libu1db-qt5-3 (>= ${source:Version}),
qttools5-dev-tools,
${misc:Depends},
Description: Qt5 binding and QtQuick2 plugin for U1DB - offline documentation
Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).
.
This package contains the offline documentation for the Qt binding for U1DB
u1db-qt-0.1.7/debian/copyright 0000664 0000000 0000000 00000004717 14367477523 0016204 0 ustar 00root root 0000000 0000000 Format: http://dep.debian.net/deps/dep5
Upstream-Name: u1db-qt
Source: https://code.launchpad.net/~uonedb-qt/u1db-qt/trunk
Files: *
Copyright: (C) 2011-2013 Canonical Ltd.
License: LGPL-3
License: LGPL-3
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; version 3.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
.
On Debian systems, the complete text of the GNU Lesser General
Public License can be found in "/usr/share/common-licenses/LGPL-3".
Files: documentation/style/reset.css
Copyright: 2010, Yahoo! Inc.
License: BSD-3-clause
License: BSD-3-clause
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
.
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
Neither the name of Yahoo! Inc. nor the names of YUI's contributors may
be used to endorse or promote products derived from this software
without specific prior written permission of Yahoo! Inc.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
u1db-qt-0.1.7/debian/libu1db-qt5-3.install 0000664 0000000 0000000 00000000024 14367477523 0020015 0 ustar 00root root 0000000 0000000 usr/lib/*/lib*.so.*
u1db-qt-0.1.7/debian/libu1db-qt5-dev.install 0000664 0000000 0000000 00000000244 14367477523 0020435 0 ustar 00root root 0000000 0000000 usr/include/lib*/*.h
usr/lib/*/qt5/qml/*/plugins.qmltypes
usr/lib/*/lib*.so
usr/lib/*/pkgconfig/lib*.pc
usr/share/qt5/doc/qch/*
usr/share/qtcreator/templates/qml/*
u1db-qt-0.1.7/debian/libu1db-qt5-doc.install 0000664 0000000 0000000 00000000210 14367477523 0020415 0 ustar 00root root 0000000 0000000 usr/share/qt5/phrasebooks/*
usr/share/u1db-qt/doc/html/*.html
usr/share/u1db-qt/doc/html/*.index
usr/share/u1db-qt/doc/html/style/*.css
u1db-qt-0.1.7/debian/libu1db-qt5-examples.install 0000664 0000000 0000000 00000000160 14367477523 0021472 0 ustar 00root root 0000000 0000000 usr/share/applications/u1db-qt-gallery.desktop
usr/share/u1db-qt/examples/*.qml
usr/share/u1db-qt/gallery/*.qml
u1db-qt-0.1.7/debian/qml-module-u1db.install 0000664 0000000 0000000 00000000027 14367477523 0020534 0 ustar 00root root 0000000 0000000 usr/lib/*/qt5/qml/U1db
u1db-qt-0.1.7/debian/rules 0000775 0000000 0000000 00000000467 14367477523 0015327 0 ustar 00root root 0000000 0000000 #!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export DPKG_GENSYMBOLS_CHECK_LEVEL=4
%:
dh $@ --fail-missing --parallel
override_dh_auto_configure:
dh_auto_configure -- -DBUILD_DOCS=ON
override_dh_auto_test:
sh tests/xvfb.sh dh_auto_test || exit $?
u1db-qt-0.1.7/documentation/ 0000775 0000000 0000000 00000000000 14367477523 0015667 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/documentation/CMakeLists.txt 0000664 0000000 0000000 00000003530 14367477523 0020430 0 ustar 00root root 0000000 0000000 option(BUILD_DOCS "Build documentation" OFF)
if (BUILD_DOCS)
set(ALL "ALL")
endif ()
set(U1DB_DOCS "${CMAKE_CURRENT_BINARY_DIR}/output")
add_custom_command(OUTPUT overview.html
COMMAND "mkdir" "-p" "${U1DB_DOCS}"
COMMAND "qdoc" "-outputdir" "${U1DB_DOCS}" "${CMAKE_CURRENT_SOURCE_DIR}/u1db.qdocconf" "2>" "${CMAKE_CURRENT_BINARY_DIR}/qdoc.err"
COMMAND "cat" "${CMAKE_CURRENT_BINARY_DIR}/qdoc.err"
# FIXME: Should not fail on warnings
# COMMAND "test" "!" "-s" "${CMAKE_CURRENT_BINARY_DIR}/qdoc.err"
COMMAND "sed" "-r" "-i" "'s@()@\\1@'" "${U1DB_DOCS}/*.html"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS U1DBPlugin
)
add_custom_command(OUTPUT u1dbqt.qhp
COMMAND "qhelpgenerator" "${U1DB_DOCS}/u1dbqt.qhp"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS overview.html
)
add_custom_target(doc ${ALL} DEPENDS u1dbqt.qhp overview.html)
if (BUILD_DOCS)
install(FILES "${U1DB_DOCS}/u1dbqt.qch"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/qt5/phrasebooks/"
)
install(FILES "${U1DB_DOCS}/u1dbqt.qch"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/qt5/doc/qch/"
)
install(DIRECTORY "${U1DB_DOCS}/"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/u1db-qt/doc/html"
FILES_MATCHING PATTERN "*.html"
)
install(DIRECTORY "${U1DB_DOCS}/"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/u1db-qt/doc/html"
FILES_MATCHING PATTERN "*.index"
)
install(DIRECTORY "${U1DB_DOCS}/style/"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/u1db-qt/doc/html/style"
FILES_MATCHING PATTERN "*.css"
)
install(DIRECTORY
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/u1db-qt/examples
FILES_MATCHING PATTERN "*example-*.html"
)
endif ()
u1db-qt-0.1.7/documentation/architecture.qdoc 0000664 0000000 0000000 00000000000 14367477523 0021207 0 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/documentation/bestpractices.qdoc 0000664 0000000 0000000 00000000000 14367477523 0021360 0 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/documentation/concepts.qdoc 0000664 0000000 0000000 00000021232 14367477523 0020355 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
/*!
\page concepts.html
\title Design Concepts
This concept guide will describe a wide variety of U1Db-Qt functionality and usage. It will cover:
\list 1
\li Overview of U1Db Documents and Databases
\li Creating Documents and Databases
\li Database keys and Document contents
\li Listing docId values in a Database
\li Retrieving Documents
\li Searching and retrieving Documents by docId
\li Modifying Existing Documents
\li Document Functions
\li Index expressions
\li Querying an index
\li Index functions
\li Blending the U1Db-Qt plugin with QML and Javascript
\li U1Db-Qt with QML Elements and Components
\li Using U1Db-Qt with elements and components that support models
\li Using U1Db-Qt with elements and components that do not utilize models
\li Using a Document without a Database
\endlist
\section1 Brief Description of U1DB
U1DB is a database API for synchronised databases of JSON documents. It’s simple to use in applications, and allows apps to store documents and synchronise them between machines and devices. U1DB is the database designed to work everywhere, backed by the platform’s native data storage capabilities. This means that you can use u1db on different platforms, from different languages, and backed on to different databases, and sync between all of them.
\section1 What is the difference between U1DB and U1Db-Qt
U1Db-Qt is the QML implementation of U1DB. It is a QML plugin written in C++ and allows for creating and manipulating U1DB databases via a more declarative approach within a QML application.
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
\qml
U1db.Database {
id: aDatabase
path: "aU1DbDSatabase2"
}
\endqml
A Document can be declared at runtime. It requires at the very least a unique 'docId', but that alone won't do anything special. The snipet below snippet demonstrates the basic requirements.
In addition to this, this example displays text from the database for a specific docId and id key in a text area called 'documentContent. To update the text area at startup with either the default value or a value from the database the onCompleted function is utilized, which is also demonstrated below.
\qml
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "helloworld":"Hello World" }
Component.onCompleted: {
documentContent.text = aDocument.contents.helloworld
}
}
\endqml
It should be possible to use a document without a database, as demonstrated in this snippet. Additionally this document will use the concept of sub-keys, as exemplified by the "bookmarks" id key + contents. This example will attempt to use the bookmark document to store docId values from the database, which will be displayed in a ListView on the second tab of the application. The user will be able to select a value from the ListView and the first tab will be modified accordingly.
\qml
U1db.Document {
id: aBookmarkDocument
docId: 'bookmarks'
create: true
defaults: { "bookmarks": [{}] }
}
\endqml
The listDocs method retrieves all the docId values from the current database. In this demonstration the values are put into an array, which is then checked to locate the docId for the current and previous documents within the database.
\code
var documentIds = documentObject.database.listDocs()
for(var i = 0; i < documentIds.length; i++){
if(documentIds[i]===documentObject.docId && i > 0){
return documentIds[i-1]
}
else if(documentIds[i]===documentObject.docId && i==0){
return documentIds[documentIds.length-1]
}
}
\endcode
These steps demonstrate the creation of a temporary document, based on a copy of the global document. This will then be used to determine if there is already a document in the database with the same docId as the address bar, and additionally with a key id with the same name.
\code
var tempFieldName = addressBarText;
var tempDocument = aDocument
tempDocument.docId = addressBarText;
var tempContents = tempDocument.contents
\endcode
\b{Note: For simplicity sake this example sometimes uses the same value for both the docId and the key id, as seen here. Real life implimentations can and will differ, and this will be demonstrated elsewhere in the example code.}
Here the contents of the temporary document are modified, which then replaces the global document.
\code
documentContent.text = 'More Hello World...';
var tempContents = {}
tempContents[tempFieldName] = documentContent.text
tempDocument.contents = tempContents
aDocument = tempDocument
\endcode
In this instance the current document's content is updated from the text view. The unique key and docId are not modified because the database already contains a record with those properties.
\code
var tempContents = {}
tempFieldName = getCurrentDocumentKey(aDocument.contents)
tempContents[tempFieldName] = documentContent.text
aDocument.contents = tempContents
\endcode
Here a rectangle is defined that represents the lower portion of our application. It will contain all the main parts of the application.
\qml
Rectangle {
width: units.gu(45)
height: units.gu(70)
anchors.bottom: parent.bottom
color: "#00FFFFFF"
// The remainder of the main part of the application goes here ...
}
\endqml
The following TextArea is for displaying contents for the current state of the global document, as defined by the key / name in the address bar.
\qml
TextArea{
id: documentContent
selectByMouse : false
x: units.gu(1)
y: units.gu(1)
width: units.gu(43)
height: units.gu(58)
color: "#000000"
}
\endqml
There is an object within in the 'aDocument' model defined earlier called 'contents', which contains a key called 'hello', which represents a search string. In this example the key will represent the name of a document in the database, which will be displayed in the address bar. Displaying the key is demonstrated here:
\qml
TextArea{
text: displayKey(aDocument.contents)
function displayKey(documentObject){
var keys = Object.keys(documentObject);
return keys[0]
}
}
\endqml
*/
u1db-qt-0.1.7/documentation/overview.qdoc 0000664 0000000 0000000 00000002404 14367477523 0020405 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
/*!
\page overview.html overview
\title All Modules
\contentspage {All Modules} {Contents}
\part General Topics
\list
\li \l {Tutorial} gives a quick start guide from storing a document
to querying a database and displaying it in \l {Ubuntu User Interface Toolkit}{Ubuntu Components}.
\li \l {Design Concepts} provides an overview of the design and
terminology.
\endlist
\part Document Storage
Available through:
\code
import U1db 1.0 as U1db
\endcode
\annotatedlist modules
*/
u1db-qt-0.1.7/documentation/style/ 0000775 0000000 0000000 00000000000 14367477523 0017027 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/documentation/style/base.css 0000664 0000000 0000000 00000027067 14367477523 0020467 0 ustar 00root root 0000000 0000000 /**
* Ubuntu Developer base stylesheet
*
* A base stylesheet containing site-wide styles
*
* @project Ubuntu Developer
* @version 1.0
* @author Canonical Web Team: Steve Edwards
* @copyright 2011 Canonical Ltd.
*/
/**
* @section Global
*/
body {
font-family: 'Ubuntu', 'Ubuntu Beta', UbuntuBeta, Ubuntu, 'Bitstream Vera Sans', 'DejaVu Sans', Tahoma, sans-serif;
font-size: 13px;
line-height: 1.4;
color: #333;
}
a {
color: #dd4814;
text-decoration: none;
outline: 0;
}
p, dl {
margin-bottom: 10px;
}
strong {
font-weight: bold;
}
em {
font-style: italic;
}
code{
padding: 10px;
font-family: 'Ubuntu Mono', 'Consolas', 'Monaco', 'DejaVu Sans Mono', Courier, monospace;
background-color: #fdf6f2;
display: block;
margin-bottom: 10px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
h1 {
font-size: 36px;
line-height: 1.1;
margin-bottom: 20px;
}
article h1,
h2 {
font-size: 24px;
line-height: 1.2;
margin-bottom: 14px;
}
h3 {
font-size: 16px;
line-height: 1.3;
margin-bottom: 8px;
}
h4 {
font-weight: bold;
}
time {
color:#999;
}
/**
* @section Structure
*/
.header-login,
.header-navigation div,
.header-content div {
margin: 0 auto;
width: 940px;
}
.header-content h1{
background-color:#ffffff;
display:inline-block;
}
.header-content h2{
background-color:#ffffff;
display:table;
}
.header-login ul {
margin: 4px 0;
float: right;
}
.header-login li {
margin-right: 10px;
float: left;
}
.header-login a {
color: #333;
}
.header-navigation {
border-top: 2px solid #dd4814;
border-bottom: 2px solid #dd4814;
background-color: #fff;
height: 54px;
clear: right;
overflow: hidden;
}
.header-navigation nav ul {
border-right: 1px solid #dd4814;
float: right;
}
.header-navigation nav li {
border-left: 1px solid #dd4814;
float: left;
height: 54px;
}
.header-navigation nav a {
padding: 18px 14px 0;
font-size: 14px;
display: block;
height: 36px;
}
.header-navigation nav a:hover {
background-color: #fcece7;
}
.header-navigation nav .current_page_item a,
.header-navigation nav .current_page_parent a,
.header-navigation nav .current_page_ancestor a {
background-color: #dd4814;
color: #fff;
}
.header-navigation input {
margin: 12px 10px 0 10px;
padding: 5px;
border-top: 1px solid #a1a1a1;
border-right: 1px solid #e0e0e0;
border-bottom: 1px solid #fff;
border-left: 1px solid #e0e0e0;
width: 90px;
font-style: italic;
color: #ccc;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: inset 0 1px 1px #e0e0e0;
-webkit-box-shadow: inset 0 1px 1px #e0e0e0;
box-shadow: inset 0 1px 1px #e0e0e0;
}
.header-navigation h2 {
margin: 18px 0 0 6px;
text-transform: lowercase;
font-size: 22px;
color: #dd4814;
float: left;
}
.header-navigation .logo-ubuntu {
margin-top: 12px;
float: left;
}
.header-content .header-navigation-secondary {
margin-bottom: 40px;
padding: 0;
position: relative;
z-index: 2;
}
.header-navigation-secondary div {
padding: 0;
border: 2px solid #dd4814;
-moz-border-radius: 0px 0px 4px 4px;
-webkit-border-radius: 0px 0px 4px 4px;
border-radius: 0px 0px 4px 4px;
background: #fff;
border-top: 0px;
width: 936px;
}
.header-navigation-secondary nav li {
float: left;
}
.header-navigation-secondary nav li a {
color: #333;
display: block;
height: 25px;
padding: 8px 8px 0;
}
.header-navigation-secondary nav li:hover,
.header-navigation-secondary nav .current_page_item a {
background: url("../img/sec-nav-hover.gif");
}
.header-content {
padding-bottom: 30px;
border-bottom: 1px solid #e0e0e0;
-moz-box-shadow: 0 1px 3px #e0e0e0;
-webkit-box-shadow: 0 1px 3px #e0e0e0;
box-shadow: 0 1px 3px #e0e0e0;
margin-bottom: 3px;
position: relative;
overflow: hidden;
}
footer {
padding: 10px 10px 40px 10px;
position: relative;
-moz-border-radius: 0 0 4px 4px;
-webkit-border-radius: 0 0 4px 4px;
border-radius: 0 0 4px 4px;
font-size: 12px;
background: url("../img/background-footer.png") repeat scroll 0 0 #f7f6f5;
}
footer div {
margin: 0 auto;
padding: 0 10px;
width: 940px;
}
footer a {
color: #000;
}
footer nav ul {
margin: 10px 17px 30px 0;
width: 172px;
display: inline-block;
vertical-align: top;
height: auto;
zoom: 1;
*display: inline;
}
footer nav ul.last {
margin-right: 0;
}
footer nav li {
margin-bottom: 8px;
}
footer nav li:first-child {
font-weight: bold;
}
footer p {
margin-bottom: 0;
}
#content {
padding-top: 35px;
}
.arrow-nav {
display: none;
position: absolute;
top: -1px;
z-index: 3;
}
.shadow {
margin: 30px 0 3px 0;
border-bottom: 1px solid #e0e0e0;
-moz-box-shadow: 0 2px 3px #e0e0e0;
-webkit-box-shadow: 0 2px 3px #e0e0e0;
box-shadow: 0 2px 3px #e0e0e0;
height: 3px;
}
/**
* @section Site-wide
*/
#content h2{
font-size:24px;
}
.box-orange {
padding: 10px;
border: 3px solid #dd4814;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.box-orange .link-action-small {
float: right;
margin: 0 0 0 20px;
}
.link-bug {
margin-left: 10px;
color: #999;
}
.link-action {
float: left;
margin-bottom: 20px;
padding: 8px 12px;
display: block;
background-color: #dd4814;
color: #fff;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
font-size: 16px;
line-height: 1.3;
border-top: 3px solid #e6633a;
border-bottom: 3px solid #c03d14;
}
.link-action2 {
float: left;
display: block;
color: #fff;
font-size: 16px;
line-height: 1.3;
}
.link-action2 span{
display:block;
float:left;
}
.link-action2 .cta-left{
background:url(../img/button-cta-left.png) no-repeat;
width:22px;
height:48px;
}
.link-action2 .cta-center{
background:url(../img/button-cta-slice.png) repeat-x;
line-height:45px;
height:48px;
}
.link-action2 .cta-right{
background:url(../img/button-cta-right.png) no-repeat;
width:22px;
height:48px;
}
.link-action-small {
float: left;
display: block;
color: #fff;
font-size: 16px;
}
.link-action-small span{
display:block;
float:left;
height:42px;
}
.link-action-small .cta-left{
background:url(../img/button-cta-left-small.png) no-repeat;
width:19px;
}
.link-action-small .cta-center{
background:url(../img/button-cta-slice-small.png) repeat-x;
line-height:42px;
}
.link-action-small .cta-right{
background:url(../img/button-cta-right-small.png) no-repeat;
width:19px;
}
.link-action:active {
position: relative;
top: 1px;
}
.link-action2:active {
position: relative;
top: 1px;
}
.link-action-small:active {
position: relative;
top: 1px;
}
.list-bullets li {
margin-bottom: 10px;
list-style: disc;
list-style-position: inside;
}
.box {
margin-bottom: 30px;
padding: 15px;
border: 1px solid #aea79f;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.box-padded {
margin-bottom: 30px;
padding: 5px;
border: 2px solid #aea79f;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background: url("../img/pattern-featured.gif") repeat scroll 0 0 #ebe9e7;
overflow: hidden;
}
.box-padded h3 {
margin: 5px 0 10px 5px;
}
.box-padded div {
padding: 10px;
border: 1px solid #aea79f;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background-color: #fff;
overflow: hidden;
}
.box-padded li {
padding: 0 10px;
float: left;
width: 211px;
border-right: 1px dotted #aea79f;
}
.box-padded li.first {
padding: 0;
margin-bottom: 0;
}
.box-padded li.last {
border: 0;
width: 217px;
}
.box-padded img {
margin: 0 10px 50px 0;
float: left;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
border-radius: 8px;
}
.box-clear {
margin-bottom: 40px;
}
.box-clear .grid-4.first {
margin-right: 15px;
padding-right: 15px;
}
.box-clear .grid-4 {
margin-left: 0;
margin-right: 10px;
padding-right: 10px;
width: 298px;
}
.box-clear time {
display: block;
border-bottom: 1px dotted #aea79f;
padding-bottom: 10px;
margin-bottom: 10px;
}
.box-clear div.first {
border-right: 1px dotted #aea79f;
}
.box-clear a {
display: block;
}
.box-clear .rss {
background: url("../img/rss.jpg") no-repeat scroll 0 center;
padding-left: 20px;
}
.box-clear .location {
display: block;
margin-bottom: 1px;
}
.box-clear .last {
margin: 0;
padding-right: 0;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
width: 293px;
}
/* Widgets */
.ui-state-focus {
outline: none;
}
.ui-accordion {
border-bottom: 1px dotted #aea79f;
}
.ui-accordion a {
display: block;
}
.ui-accordion h3 {
margin-bottom: 0;
border-top: 1px dotted #aea79f;
position: relative;
font-size: 13px;
font-weight: bold;
}
.ui-accordion h3 a {
padding: 10px 0;
color: #333;
}
.ui-accordion h4 {
margin-bottom: 5px;
}
.ui-accordion div fieldset {
padding-bottom: 5px;
}
.ui-accordion div li,
.ui-accordion div input {
margin-bottom: 10px;
}
.ui-accordion .ui-icon {
position: absolute;
top: 15px;
right: 0;
display: block;
width: 8px;
height: 8px;
background: url("../img/icon-accordion-inactive.png") 0 0 no-repeat transparent;
}
.ui-accordion .ui-state-active .ui-icon {
background-image: url("../img/icon-accordion-active.png");
}
.ui-accordion .current_page_item a {
color: #333;
}
.container-tweet {
-moz-border-radius: 4px 4px 4px 4px;
-webkit-border-radius: 4px 4px 4px 4px;
border-radius: 4px 4px 4px 4px;
padding: 10px 10px 10px;
background-color: #f7f7f7;
}
.container-tweet .tweet-follow {
margin-top: 10px;
margin-bottom: -10px;
padding-left: 55px;
padding-bottom: 6px;
background: url("../img/tweet-follow.png") 0 5px no-repeat;
display: block;
}
.container-tweet .tweet-follow span {
font-size: 16px;
font-weight: bold;
line-height: 1.2;
display: block;
}
.tweet a {
display: inline;
}
.tweet .tweet_text {
padding: 10px;
background-color: #fff;
-moz-border-radius: 4px 4px 4px 4px;
-webkit-border-radius: 4px 4px 4px 4px;
border-radius: 4px 4px 4px 4px;
border: 1px solid #dd4814;
font-size: 16px;
display: block;
clear: both;
}
.tweet.tweet-small .tweet_text {
font-size: inherit;
}
.tweet .tweet_text a {
color: #333;
}
.tweet .tweet_time,
.tweet .tweet_user_and_time {
padding: 15px 0 10px 0;
position: relative;
top: -2px;
background: url("../img/tweet-arrow.png") no-repeat;
display: block;
}
.tweet .tweet_odd .tweet_time,
.tweet .tweet_odd .tweet_user_and_time {
background-position: right 0;
float: right;
}
.tweet .tweet_even .tweet_time,
.tweet .tweet_even .tweet_user_and_time {
background-position: left 0;
float: left;
}
/* Search */
#content .list-search li {
list-style-type:none;
border:0px;
margin-bottom: 15px;
padding-top: 15px;
}
/* Blog */
.blog-article #nav-single {
margin-top: 30px;
margin-bottom: 30px;
}
.blog-article #nav-single .nav-next {
float: right;
}
.blog-article article header .entry-meta {
margin-bottom: 20px;
}
.blog-article article .entry-meta {
color: #999;
}
.blog-article #respond form input[type="submit"] {
float: left;
cursor: pointer;
margin-bottom: 20px;
padding: 8px 12px;
display: block;
background-color: #dd4814;
color: #fff;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
font-size: 16px;
line-height: 1.3;
border-top: 3px solid #e6633a;
border-left: 3px solid #e6633a;
border-right: 3px solid #e6633a;
border-bottom: 3px solid #c03d14;
}
.blog-article #respond form input[type="submit"]:active {
position: relative;
top: 1px;
}
.alignnone{
float:left;
margin:10px 20px 10px 0;
}
.alignleft{
float:left;
margin:10px 20px 10px 0;
}
.alignright{
float:right;
margin:10px 0 10px 20px;
}
.aligncenter{
float:left;
margin:10px 20px 10px 0;
}
.entry-content h2, .entry-content h3{
margin-top:20px;
}
.entry-content ul li{
list-style-type: circle;
margin-left:16px;
}
.entry-content hr{
border:none;
border-top: 1px dotted #AEA79F;
}
u1db-qt-0.1.7/documentation/style/css.css 0000664 0000000 0000000 00000002154 14367477523 0020333 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu'), url(http://themes.googleusercontent.com/static/fonts/ubuntu/v4/_xyN3apAT_yRRDeqB3sPRg.woff) format('woff');
}
@font-face {
font-family: 'Ubuntu';
font-style: italic;
font-weight: 400;
src: local('Ubuntu Italic'), local('Ubuntu-Italic'), url(http://themes.googleusercontent.com/static/fonts/ubuntu/v4/kbP_6ONYVgE-bLa9ZRbvvvesZW2xOQ-xsNqO47m55DA.woff) format('woff');
}
u1db-qt-0.1.7/documentation/style/css_002.css 0000664 0000000 0000000 00000001642 14367477523 0020715 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'), url(http://themes.googleusercontent.com/static/fonts/ubuntumono/v3/ViZhet7Ak-LRXZMXzuAfkYbN6UDyHWBl620a-IRfuBk.woff) format('woff');
}
u1db-qt-0.1.7/documentation/style/qtquick.css 0000664 0000000 0000000 00000033165 14367477523 0021232 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
@media screen
{
/* basic elements */
html
{
color: #000000;
background: #FFFFFF;
}
table
{
border-collapse: collapse;
border-spacing: 0;
}
fieldset, img
{
border: 0;
max-width:100%;
}
address, caption, cite, code, dfn, em, strong, th, var, optgroup
{
font-style: inherit;
font-weight: inherit;
}
del, ins
{
text-decoration: none;
}
ol li
{
list-style: decimal;
}
ul li
{
list-style: none;
}
caption, th
{
text-align: left;
}
h1.title
{
font-weight: bold;
font-size: 150%;
}
h0
{
font-weight: bold;
font-size: 130%;
}
h1, h2, h3, h4, h5, h6
{
font-size: 100%;
}
q:before, q:after
{
content: '';
}
abbr, acronym
{
border: 0;
font-variant: normal;
}
sup, sub
{
vertical-align: baseline;
}
tt, .qmlreadonly span, .qmldefault span
{
word-spacing:0.5em;
}
legend
{
color: #000000;
}
strong
{
font-weight: bold;
}
em
{
font-style: italic;
}
body
{
margin: 0 1.5em 0 1.5em;
font-family: ubuntu;
line-height: normal
}
a
{
color: #00732F;
text-decoration: none;
}
hr
{
background-color: #E6E6E6;
border: 1px solid #E6E6E6;
height: 1px;
width: 100%;
text-align: left;
margin: 1.5em 0 1.5em 0;
}
pre
{
border: 1px solid #DDDDDD;
-moz-border-radius: 0.7em 0.7em 0.7em 0.7em;
-webkit-border-radius: 0.7em 0.7em 0.7em 0.7em;
border-radius: 0.7em 0.7em 0.7em 0.7em;
padding: 1em 1em 1em 1em;
overflow-x: auto;
}
table, pre
{
-moz-border-radius: 0.7em 0.7em 0.7em 0.7em;
-webkit-border-radius: 0.7em 0.7em 0.7em 0.7em;
border-radius: 0.7em 0.7em 0.7em 0.7em;
background-color: #F6F6F6;
border: 1px solid #E6E6E6;
border-collapse: separate;
margin-bottom: 2.5em;
}
pre {
font-size: 90%;
display: block;
overflow:hidden;
}
thead
{
margin-top: 0.5em;
font-weight: bold
}
th
{
padding: 0.5em 1.5em 0.5em 1em;
background-color: #E1E1E1;
border-left: 1px solid #E6E6E6;
}
td
{
padding: 0.25em 1.5em 0.25em 1em;
}
td.rightAlign
{
padding: 0.25em 0.5em 0.25em 1em;
}
table tr.odd
{
border-left: 1px solid #E6E6E6;
background-color: #F6F6F6;
color: black;
}
table tr.even
{
border-left: 1px solid #E6E6E6;
background-color: #ffffff;
color: #202020;
}
div.float-left
{
float: left; margin-right: 2em
}
div.float-right
{
float: right; margin-left: 2em
}
span.comment
{
color: #008B00;
}
span.string, span.char
{
color: #000084;
}
span.number
{
color: #a46200;
}
span.operator
{
color: #202020;
}
span.keyword
{
color: #840000;
}
span.name
{
color: black
}
span.type
{
font-weight: bold
}
span.type a:visited
{
color: #0F5300;
}
span.preprocessor
{
color: #404040
}
/* end basic elements */
/* font style elements */
.heading
{
font-weight: bold;
font-size: 125%;
}
.subtitle
{
font-size: 110%
}
.small-subtitle
{
font-size: 100%
}
.red
{
color:red;
}
/* end font style elements */
/* global settings*/
.header, .footer
{
display: block;
clear: both;
overflow: hidden;
}
/* end global settings*/
/* header elements */
.header .qtref
{
color: #00732F;
font-weight: bold;
font-size: 130%;
}
.header .content
{
margin-left: 5px;
margin-top: 5px;
margin-bottom: 0.5em;
}
.header .breadcrumb
{
font-size: 90%;
padding: 0.5em 0 0.5em 1em;
margin: 0;
background-color: #fafafa;
height: 1.35em;
border-bottom: 1px solid #d1d1d1;
}
.header .breadcrumb ul
{
margin: 0;
padding: 0;
}
.header .content
{
word-wrap: break-word;
}
.header .breadcrumb ul li
{
float: left;
background: url(../images/breadcrumb.png) no-repeat 0 3px;
padding-left: 1.5em;
margin-left: 1.5em;
}
.header .breadcrumb ul li.last
{
font-weight: normal;
}
.header .breadcrumb ul li a
{
color: #00732F;
}
.header .breadcrumb ul li.first
{
background-image: none;
padding-left: 0;
margin-left: 0;
}
.header .content ol li {
background: none;
margin-bottom: 1.0em;
margin-left: 1.2em;
padding-left: 0
}
.header .content li
{
background: url(../images/bullet_sq.png) no-repeat 0 5px;
margin-bottom: 1em;
padding-left: 1.2em;
}
/* end header elements */
/* content elements */
.content h1
{
font-weight: bold;
font-size: 130%
}
.content h2
{
font-weight: bold;
font-size: 120%;
width: 100%;
}
.content h3
{
font-weight: bold;
font-size: 110%;
width: 100%;
}
.content table p
{
margin: 0
}
.content ul
{
padding-left: 2.5em;
}
.content li
{
padding-top: 0.25em;
padding-bottom: 0.25em;
}
.content ul img {
vertical-align: middle;
}
.content a:visited
{
color: #4c0033;
text-decoration: none;
}
.content a:visited:hover
{
color: #4c0033;
text-decoration: underline;
}
a:hover
{
color: #4c0033;
text-decoration: underline;
}
descr p a
{
text-decoration: underline;
}
.descr p a:visited
{
text-decoration: underline;
}
.alphaChar{
width:95%;
background-color:#F6F6F6;
border:1px solid #E6E6E6;
-moz-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
font-size:12pt;
padding-left:10px;
margin-top:10px;
margin-bottom:10px;
}
.flowList{
/*vertical-align:top;*/
/*margin:20px auto;*/
column-count:3;
-webkit-column-count:3;
-moz-column-count:3;
/*
column-width:100%;
-webkit-column-width:200px;
-col-column-width:200px;
*/
column-gap:41px;
-webkit-column-gap:41px;
-moz-column-gap:41px;
column-rule: 1px dashed #ccc;
-webkit-column-rule: 1px dashed #ccc;
-moz-column-rule: 1px dashed #ccc;
}
.flowList dl{
}
.flowList dd{
/*display:inline-block;*/
margin-left:10px;
min-width:250px;
line-height: 1.5;
min-width:100%;
min-height:15px;
}
.flowList dd a{
}
.mainContent
{
padding-left:5px;
}
.content .flowList p{
padding:0px;
}
.content .alignedsummary
{
margin: 15px;
}
.qmltype
{
text-align: center;
font-size: 120%;
}
.qmlreadonly
{
padding-left: 5px;
float: right;
color: #254117;
}
.qmldefault
{
padding-left: 5px;
float: right;
color: red;
}
.qmldoc
{
}
.generic .alphaChar{
margin-top:5px;
}
.generic .odd .alphaChar{
background-color: #F6F6F6;
}
.generic .even .alphaChar{
background-color: #FFFFFF;
}
.memItemRight{
padding: 0.25em 1.5em 0.25em 0;
}
.highlightedCode
{
margin: 1.0em;
}
.annotated td {
padding: 0.25em 0.5em 0.25em 0.5em;
}
.toc
{
font-size: 80%
}
.header .content .toc ul
{
padding-left: 0px;
}
.content .toc h3 {
border-bottom: 0px;
margin-top: 0px;
}
.content .toc h3 a:hover {
color: #00732F;
text-decoration: none;
}
.content .toc .level2
{
margin-left: 1.5em;
}
.content .toc .level3
{
margin-left: 3.0em;
}
.content ul li
{
background: url(../images/bullet_sq.png) no-repeat 0 0.7em;
padding-left: 1em
}
.content .toc li
{
background: url(../images/bullet_dn.png) no-repeat 0 5px;
padding-left: 1em
}
.relpage
{
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
border: 1px solid #DDDDDD;
padding: 25px 25px;
clear: both;
}
.relpage ul
{
float: none;
padding: 1.5em;
}
h3.fn, span.fn
{
-moz-border-radius:7px 7px 7px 7px;
-webkit-border-radius:7px 7px 7px 7px;
border-radius:7px 7px 7px 7px;
background-color: #F6F6F6;
border-width: 1px;
border-style: solid;
border-color: #E6E6E6;
font-weight: bold;
word-spacing:3px;
padding:3px 5px;
}
.functionIndex {
font-size:12pt;
word-spacing:10px;
margin-bottom:10px;
background-color: #F6F6F6;
border-width: 1px;
border-style: solid;
border-color: #E6E6E6;
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
width:100%;
}
.centerAlign
{
text-align:center;
}
.rightAlign
{
text-align:right;
}
.leftAlign
{
text-align:left;
}
.topAlign{
vertical-align:top
}
.functionIndex a{
display:inline-block;
}
/* end content elements */
/* footer elements */
.footer
{
color: #393735;
font-size: 0.75em;
text-align: center;
padding-top: 1.5em;
padding-bottom: 1em;
background-color: #E6E7E8;
margin: 0;
}
.footer p
{
margin: 0.25em
}
.small
{
font-size: 0.5em;
}
/* end footer elements */
.item {
float: left;
position: relative;
width: 100%;
overflow: hidden;
}
.item .primary {
margin-right: 220px;
position: relative;
}
.item hr {
margin-left: -220px;
}
.item .secondary {
float: right;
width: 200px;
position: relative;
}
.item .cols {
clear: both;
display: block;
}
.item .cols .col {
float: left;
margin-left: 1.5%;
}
.item .cols .col.first {
margin-left: 0;
}
.item .cols.two .col {
width: 45%;
}
.item .box {
margin: 0 0 10px 0;
}
.item .box h3 {
margin: 0 0 10px 0;
}
.cols.unclear {
clear:none;
}
}
/* end of screen media */
/* start of print media */
@media print
{
input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult
{
display: none;
background: none;
}
.content
{
background: none;
display: block;
width: 100%; margin: 0; float: none;
}
}
/* end of print media */
/* modify the TOC layouts */
div.toc ul {
padding-left: 20px;
}
div.toc li {
padding-left: 4px;
}
/* Remove the border around images*/
a img
{
border:none;
}
/*Add styling to the front pages*/
.threecolumn_area
{
padding-top: 20px;
padding-bottom: 20px;
}
.threecolumn_piece
{
display: inline-block;
margin-left: 78px;
margin-top: 8px;
padding: 0;
vertical-align: top;
width: 25.5%;
}
div.threecolumn_piece ul {
list-style-type: none;
padding-left: 0px;
margin-top: 2px;
}
div.threecolumn_piece p {
margin-bottom: 7px;
color: #5C626E;
text-decoration: none;
font-weight: bold;
}
div.threecolumn_piece li {
padding-left: 0px;
margin-bottom: 5px;
}
div.threecolumn_piece a {
font-weight: normal;
}
/* Add style to guide page*/
.fourcolumn_area
{
padding-top: 20px;
padding-bottom: 20px;
}
.fourcolumn_piece
{
display: inline-block;
margin-left: 35px;
margin-top: 8px;
padding: 0;
vertical-align: top;
width: 21.3%;
}
div.fourcolumn_piece ul {
list-style-type: none;
padding-left: 0px;
margin-top: 2px;
}
div.fourcolumn_piece p {
margin-bottom: 7px;
color: #40444D;
text-decoration: none;
font-weight: bold;
}
div.fourcolumn_piece li {
padding-left: 0px;
margin-bottom: 5px;
}
div.fourcolumn_piece a {
font-weight: normal;
}
u1db-qt-0.1.7/documentation/style/reset.css 0000664 0000000 0000000 00000001533 14367477523 0020665 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 3.3.0
build: 3167
*/
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;} u1db-qt-0.1.7/documentation/style/scratch.css 0000664 0000000 0000000 00000002610 14367477523 0021167 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
body {
margin: 0;
}
div.toc ul {
padding: 0;
}
div.toc li {
margin-bottom: 3px;
}
h1.title {
font-size: 36px;
line-height: 1.1;
font-weight: normal;
}
h0, h2 {
font-size: 24px;
line-height: 1.2;
margin: 14px 0;
font-weight: normal;
display: block;
}
a:hover {
color: #dd4814;
text-decoration: underline;
outline: 0;
}
table, pre {
border-radius: 0;
}
.annotated td {
padding: 0.8em 1em 0.3em;
}
.wrapper {
width: 940px;
margin: 0 auto;
}
.main-content {
width: 668px;
position: relative;
left: 270px;
}
.title {
margin-left: -270px;
margin-top: 30px;
margin-bottom: 50px;
}
.toc {
margin-left: -270px;
font-size: 100%;
margin-bottom: 40px;
padding: 0;
z-index: 2;
position: absolute;
top: 100px;
width: 250px;
}
u1db-qt-0.1.7/documentation/troubleshooting.qdoc 0000664 0000000 0000000 00000000000 14367477523 0021754 0 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/documentation/u1db.qdocconf 0000664 0000000 0000000 00000005325 14367477523 0020245 0 ustar 00root root 0000000 0000000 project = U1Db-Qt
description = U1Db-Qt plugin documentation
url = http://developer.ubuntu.com/api/devel/ubuntu-13.10/qml/u1db-qt5/
indexes = /usr/share/ubuntu-ui-toolkit/doc/html/ubuntuuserinterfacetoolkit.index
sourcedirs = ../src \
../documentation
headerdirs = ../src/
Cpp.ignoretokens = Q_DECL_EXPORT \
Q_PROPERTY \
QT_BEGIN_NAMESPACE_U1DB \
Q_INVOKABLE \
defines = Q_QDOC
Cpp.ignoredirectives = Q_ENUMS \
Q_FLAGS \
QT_PREPEND_NAMESPACE_U1DB \
Q_DISABLE_COPY
exampledirs = ../examples/u1db-qt-example-1 \
../examples/u1db-qt-example-2 \
../examples/u1db-qt-example-2b \
../examples/u1db-qt-example-3 \
../examples/u1db-qt-example-4 \
../examples/u1db-qt-example-5 \
../examples/u1db-qt-example-6
imagedirs = images
sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp"
examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
outputdir = output/html
outputformats = HTML
syntaxhighlighting = true
HTML.postheader = "
\n" \
"
\n"
HTML.footer = "
\n" \
"
\n"
HTML.headerstyles = "\n" \
"\n" \
"\n" \
"\n" \
"\n" \
"\n"
HTML.stylesheets = style/base.css \
style/css.css \
style/css_002.css \
style/reset.css \
style/qtquick.css \
style/base.css \
style/scratch.css \
qhp.projects = U1DbQt
qhp.U1DbQt.file = u1dbqt.qhp
qhp.U1DbQt.namespace = net.launchpad.u1db-qt
qhp.U1DbQt.virtualFolder = u1dbqt
qhp.U1DbQt.indexTitle = U1DbQt Reference Documentation
qhp.U1DbQt.indexRoot =
qhp.U1DbQt.subprojects = overview tutorial concepts
qhp.U1DbQt.subprojects.overview.title = U1DbQt Overview
qhp.U1DbQt.subprojects.overview.indexTitle = All Modules
qhp.U1DbQt.subprojects.overview.selectors = class
qhp.U1DbQt.subprojects.tutorial.title = U1DbQt Tutorial
qhp.U1DbQt.subprojects.tutorial.indexTitle = Tutorial
qhp.U1DbQt.subprojects.tutorial.selectors = fake:page,group,module
qhp.U1DbQt.subprojects.concepts.title = U1DbQt Design Concepts
qhp.U1DbQt.subprojects.concepts.indexTitle = Design Concepts
qhp.U1DbQt.subprojects.concepts.selectors = fake:example
u1db-qt-0.1.7/documentation/u1db.tutorial.qdoc 0000664 0000000 0000000 00000017502 14367477523 0021241 0 ustar 00root root 0000000 0000000 /*!
\page tutorial.html
\title Tutorial
\chapter 1.0.0 Overview of U1Db-Qt
U1Db-Qt is a QML plugin written in Qt C++. It provides declarative, easy to use, local data storage for QML applications, and in the future will also include remote sync capabilities.
U1Db-Qt is based on a procedural implementation in Python, but has been designed and developed from the start with declarative programming in mind.
While U1Db-Qt makes use of SQLite in the back end, and relies heavily on JSON, these are largely invisible to a QML developer who makes use of the plugin. However, because U1Db-Qt does rely on both technologies it is possible to easily debug applications using existing programs. For example, a developer could make use of SQLiteBrowser to read U1Db database files, which contain human readable JSON objects representing content derived from a QML application.
\section1 1.0.1 How to Make U1Db-Qt Available to a QML Application
Here is an example import statement:
\code
import U1db 1.0 as U1db
\endcode
\chapter 2.0.0 Database Element
In U1Db-Qt, the Database element is the the central figure that works in conjunction with Document elements, and in the future indexing (currently under development), and querying (currently under development) elements. It is the Database element that defines the location of the data repository.
A Database element is also a valuable tool for cases where specific data from a repository needs to be retrieved quickly, without indexing or querying ahead of time. The 'contents' object associated with the Database element can be used together with base items such as TextField or TextArea and model-based items like ListView and \l {Standard}{ListItems.Standard}.
\section1 2.0.1 Database Properties
\code
QString path
QString error
\endcode
\section1 2.1.0 Creating a Database
A Database is very simple to create. It requires nothing more than an id and a path where the file will be created.
\section2 2.1.1 Example of Creating a Database
\code
import QtQuick 2.0
import U1db 1.0 as U1db
Item{
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
}
}
\endcode
\chapter 3.0.0 Document Element
The Document element is the primary vehicle for entering data into a repository, and can be helpful in some cases for getting data out as well. Indexing and querying would normally provide more robust functionality for extracting data from a repository, but in the case of U1Db-Qt both are still under development at the time of writing (and therefore not available for developers to use).
However, the Document element together with Database can still help developers in many common situations, and will continue to be very useful even when the indexing and querying functionality becomes available. When a developer wants unfiltered results from a database, or the cost of working with unfiltered results is reasonable, the Document+Database combination is fast and easy to use. In quite a number of use cases this may be exactly what a developer needs.
\section1 3.0.1 Document Properties
\code
U1db.Database database
QString docId
bool create
QVariant defaults
QVariant contents
\endcode
\section1 3.1.0 Creating a Basic Document
A Document declaration should contain at least a unique 'docId' and 'database', but these alone won't do anything by themselves. Additionally, although the 'id' property is not mandatory, this property will need to be set in order to more easily reference it from elsewhere in the program (e.g. within a function call).
\section2 3.1.0.1 Example of Creating a Basic Document
\code
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item{
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
}
}
\endcode
\section1 3.1.1 Creating a Document At Runtime
A Document can be declared at runtime, and default data entered into the repository. This requires the same properties to be set as in the basic example ('id', 'database' and 'docId'), plus setting 'create' (to true) and a 'default' string.
\section2 3.1.1.1 Example of Creating a Document At Runtime
\code
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item{
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
}
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "hello": "Hello World!" }
}
}
\endcode
\section1 3.1.2 Creating a Document Dynamically
Creating a Document in a dynamic fashion is the most common way of putting data into a data repository based on UI activity (e.g. when a user presses a button).
\section2 3.1.2.1 Example 1 of Creating a Document Dynamically
Another way of creating a new Document is to copy an existing Document:
\code
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item{
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
}
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
}
function someFunction() {
var tempDocument = {}
tempDocument = aDocument
}
}
\endcode
\section2 3.1.2.2 Example 2 of Creating a Document Dynamically
One way of creating a new Document dynamically is to make use of Qt.createQmlObject:
\code
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item{
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
Component.onCompleted: { newDocumentObject() }
function newDocumentObject() {
var qmlString = "import QtQuick 2.0; import U1db 1.0 as U1db; U1db.Document {id: aDcoument; database: aDatabase; docId: 'helloworld'; create: true; defaults: { 'hello': 'Hello New Document!' }}"
Qt.createQmlObject(qmlString, aDatabase);
}
}
}
\endcode
\chapter 4.0.0 U1Db-Qt and QML Elements and Models
\section1 4.1.0 U1Db-Qt and Standard Elements
\section2 4.1.1 U1Db-Qt and TextField & TextArea
\section3 4.1.2 Example of Using U1Db-Qt with Standard Elements
\code
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item{
width: units.gu(45)
height: units.gu(80)
function getContent(fieldName){
var tempContents = {};
tempContents = aDocument.contents
return tempContents[fieldName]
}
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
}
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "hello": "Hello World 1!" }
}
TextField {
id: addressBar
width: units.gu(45)
text: getContent('hello')
}
}
\endcode
\section1 4.2.0 U1Db-Qt and Model-Based Elements
\section2 4.2.1 U1Db-Qt and ListView
\section3 4.2.2 Example of Using U1Db-Qt with Model-Based Elements
\code
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item{
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: "aU1DbDatabase"
}
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "hello": "Hello World 1!" }
}
U1db.Document {
id: aDocument2
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "hello": "Hello World 2!" }
}
ListView {
model: aDatabase
width: units.gu(45)
height: units.gu(80)
delegate: Text {
x: 66; y: 77
text: contents.hello
}
}
}
\endcode
\chapter 5.0.0 Resources
\section1 5.0.1 Examples
One can find several examples in the bzr branch of U1Db-Qt (bzr branch lp:u1db-qt) either in the subdirectory "examples" or from the following url:
http://bazaar.launchpad.net/~uonedb-qt/u1db-qt/trunk/files/head:/examples/
These examples are currently under development (as is U1Db-Qt in general), but should still be able to demonstrate the fundamentals discussed within this document.
*/
u1db-qt-0.1.7/examples/ 0000775 0000000 0000000 00000000000 14367477523 0014634 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/CMakeLists.txt 0000664 0000000 0000000 00000000204 14367477523 0017370 0 ustar 00root root 0000000 0000000 file(GLOB ALL_EXAMPLES */*.qml)
install(FILES ${ALL_EXAMPLES}
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/u1db-qt/examples
)
u1db-qt-0.1.7/examples/advanced-game/ 0000775 0000000 0000000 00000000000 14367477523 0017310 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/advanced-game/AdvancedGame.desktop 0000664 0000000 0000000 00000000247 14367477523 0023205 0 ustar 00root root 0000000 0000000 [Desktop Entry]
Name=AdvancedGame
Exec=/usr/bin/qmlscene $@ /usr/share/AdvancedGame/AdvancedGame.qml
Icon=qmlscene
Terminal=false
Type=Application
X-Ubuntu-Touch=true
u1db-qt-0.1.7/examples/advanced-game/AdvancedGame.json 0000664 0000000 0000000 00000000120 14367477523 0022473 0 ustar 00root root 0000000 0000000 {
"policy_groups": [
"networking"
],
"policy_version": 1.2
} u1db-qt-0.1.7/examples/advanced-game/AdvancedGame.qml 0000664 0000000 0000000 00000004266 14367477523 0022332 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Nekhelesh Ramananthan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.2
import Ubuntu.Components 1.1
// Import U1db to access its functions
import U1db 1.0 as U1db
MainView {
id: mainView
objectName: "mainView"
applicationName: "com.ubuntu.developer.nik90.AdvancedGame"
width: units.gu(50)
height: units.gu(75)
useDeprecatedToolbar: false
// U1db database to store player profiles
U1db.Database {
id: appDb
path: "playerDatabase"
}
// Common Action available to all pages
Action {
id: addPlayerAction
text: i18n.tr("Add Player")
iconName: "add"
onTriggered: pagestack.push(Qt.resolvedUrl("CreatePlayerPage.qml"))
}
PageStack {
id: pagestack
Component.onCompleted: push(homePage)
Page {
id: homePage
title: i18n.tr("Advanced Game")
head.actions: [
addPlayerAction
]
Column {
anchors.fill: parent
anchors.margins: units.gu(5)
spacing: units.gu(2)
Button {
width: parent.width
text: i18n.tr("List Players")
onClicked: pagestack.push(Qt.resolvedUrl("ListPlayers.qml"))
}
Button {
width: parent.width
text: i18n.tr("Filter Players")
onClicked: pagestack.push(Qt.resolvedUrl("FilterPlayers.qml"))
}
}
}
}
}
u1db-qt-0.1.7/examples/advanced-game/AdvancedGame.qmlproject 0000664 0000000 0000000 00000002015 14367477523 0023707 0 ustar 00root root 0000000 0000000 /* File generated by Qt Creator (with Ubuntu Plugin), version 2.8.1 */
import QmlProject 1.1
Project {
mainFile: "AdvancedGame.qml"
/* Include .qml, .js, and image files from current directory and subdirectories */
QmlFiles {
directory: "."
}
JavaScriptFiles {
directory: "."
}
ImageFiles {
directory: "."
}
Files {
filter: "*.desktop"
}
Files {
filter: "www/*.html"
}
Files {
filter: "Makefile"
}
Files {
directory: "www"
filter: "*"
}
Files {
directory: "www/img/"
filter: "*"
}
Files {
directory: "www/css/"
filter: "*"
}
Files {
directory: "www/js/"
filter: "*"
}
Files {
directory: "tests/"
filter: "*"
}
Files {
directory: "debian"
filter: "*"
}
/* List of plugin directories passed to QML runtime */
importPaths: [ "." ,"/usr/bin","/usr/lib/x86_64-linux-gnu/qt5/qml" ]
}
u1db-qt-0.1.7/examples/advanced-game/CreatePlayerPage.qml 0000664 0000000 0000000 00000004022 14367477523 0023176 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Nekhelesh Ramananthan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.2
import Ubuntu.Components 1.1
import U1db 1.0 as U1db
Page {
id: createUserPage
visible: false
title: i18n.tr("Create Player")
head.actions: [
Action {
id: savePlayerAction
text: i18n.tr("Save Player")
iconName: "save"
onTriggered: {
appDb.putDoc({ "username": userName.text, "userlevel": userlevel.text, "userclass": userClass.selectedIndex})
pageStack.pop()
}
}
]
Column {
spacing: units.gu(3)
anchors.fill: parent
anchors.margins: units.gu(2)
Column {
width: parent.width
spacing: units.gu(1)
Label { text: i18n.tr("Username") }
TextField {
id: userName
placeholderText: "Username"
width: parent.width
}
}
Column {
width: parent.width
spacing: units.gu(1)
Label { text: i18n.tr("User Level") }
TextField {
id: userlevel
placeholderText: "User Level"
width: parent.width
}
}
OptionSelector {
id: userClass
model: ["Foot Soldier", "Archer", "Giant", "Wizard", "Demolisher"]
}
}
}
u1db-qt-0.1.7/examples/advanced-game/FilterPlayers.qml 0000664 0000000 0000000 00000003771 14367477523 0022620 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Nekhelesh Ramananthan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.2
import Ubuntu.Components 1.1
import Ubuntu.Components.ListItems 1.0 as ListItem
import U1db 1.0 as U1db
Page {
id: filterPlayers
visible: false
title: "Filter Players"
U1db.Index {
database: appDb
id: by_player
expression: ["username", "userlevel", "userclass"]
}
U1db.Query {
id: playerQuery
index: by_player
query: [{username:'*'}, {userlevel:'*'},{userclass:userClass.selectedIndex.toString()}]
}
Column {
spacing: units.gu(3)
anchors.fill: parent
anchors.margins: units.gu(2)
Label { text: "Filter by user class" }
OptionSelector {
id: userClass
model: ["Foot Soldier", "Archer", "Giant", "Wizard", "Demolisher"]
}
ListView {
id: players
width: parent.width
height: units.gu(20)
clip: true
model: playerQuery
delegate: ListItem.Subtitled {
text: '%1 Lvl %2'.arg(model.contents.username).arg(model.contents.userlevel)
subText: userClass.model[model.contents.userclass]
removable: true
confirmRemoval: true
onItemRemoved: appDb.deleteDoc(model.docId)
}
}
}
}
u1db-qt-0.1.7/examples/advanced-game/ListPlayers.qml 0000664 0000000 0000000 00000003305 14367477523 0022277 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Nekhelesh Ramananthan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.2
import Ubuntu.Components 1.1
import Ubuntu.Components.ListItems 1.0 as ListItem
import U1db 1.0 as U1db
Page {
id: homePage
visible: false
title: i18n.tr("List Players")
head.actions: [
addPlayerAction
]
U1db.Index {
database: appDb
id: by_player
expression: ["username", "userlevel", "userclass"]
}
U1db.Query {
id: playerQuery
index: by_player
query: ["*", "*", "*"]
}
Label {
anchors.centerIn: parent
visible: players.count === 0
text: "No players? Add some!"
}
ListView {
id: players
anchors.fill: parent
clip: true
model: playerQuery
delegate: ListItem.Subtitled {
text: model.contents.username
subText: "User Level: " + model.contents.userlevel
removable: true
confirmRemoval: true
onItemRemoved: appDb.deleteDoc(model.docId)
}
}
}
u1db-qt-0.1.7/examples/advanced-game/manifest.json 0000664 0000000 0000000 00000000700 14367477523 0022006 0 ustar 00root root 0000000 0000000 {
"architecture": "all",
"description": "description of AdvancedGame",
"framework": "ubuntu-sdk-14.10-qml-dev3",
"hooks": {
"AdvancedGame": {
"apparmor": "AdvancedGame.json",
"desktop": "AdvancedGame.desktop"
}
},
"maintainer": "Nekhelesh Ramananthan ",
"name": "com.ubuntu.developer.nik90.advancedgame",
"title": "AdvancedGame",
"version": "0.1"
}
u1db-qt-0.1.7/examples/bookmarks/ 0000775 0000000 0000000 00000000000 14367477523 0016624 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/bookmarks/bookmarks.qml 0000664 0000000 0000000 00000012415 14367477523 0021332 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
import Ubuntu.Components.ListItems 0.1 as ListItem
import Ubuntu.Components.Popups 0.1
/*!
This example and tutorial is designed to show a wide variety of U1Db-Qt functionality and usage. The example demonstrates:
\list 1
\li Combining U1Db-Qt with elements and components that do not utilize models
\li Blending the U1Db-Qt plugin with QML and Javascript
\endlist
*/
MainView {
id: root
applicationName: "com.ubuntu.developer.foobar.bookmarks"
width: units.gu(45)
height: units.gu(80)
/*
Bookmarks database
*/
U1db.Database {
id: db
// path: "bookmarks.db"
}
U1db.Document {
database: db
docId: 'defaultsDuckDuckGo'
create: true
defaults: { "uri": "https://www.duckduckgo.com", visited: false, "meta": { "title": "Search DuckDuckGo", visits: 0, tags: [ 'search', 'engine' ] } }
}
U1db.Document {
database: db
docId: 'defaultsUbuntu'
create: true
defaults: { "uri": "http://www.ubuntu.com", visited: true, "meta": { "title": "The world's most popular free OS", visits: 1001 } }
}
U1db.Query {
id: allBookmarks
index: U1db.Index {
database: db
}
}
/*
UI: details
*/
Component {
id: detailsPopCom
Popover {
id: detailsPop
Column {
anchors.centerIn: parent
spacing: units.gu(1)
Label {
text: i18n.tr('JSON')
}
TextField {
text: bookmarksList.detailsDocId
}
TextArea {
text: bookmarksList.detailsContents.replace(',',',\n')+'\n\n'
readOnly: true
autoSize: true
}
Button {
text: i18n.tr('Delete')
onClicked: {
PopupUtils.close(detailsPop)
db.deleteDoc(bookmarksList.detailsDocId)
}
}
}
}
}
/*
UI: list view, filters
*/
Page {
id: page
title: i18n.tr("Bookmarks")
Item {
id: container
anchors.margins: units.gu(1)
anchors.fill: parent
ListView {
id: bookmarksList
anchors.fill: parent
model: allBookmarks
property string detailsDocId: ""
property string detailsContents: ""
delegate: ListItem.Subtitled {
text: contents.title || '[title:%1]'.arg(docId)
subText: contents.uri || '[uri:%1]'.arg(docId)
// iconSource: contents.uri + "/favicon.ico"
fallbackIconName: "favorite-unselected,text-html"
iconFrame: false
onClicked: {
bookmarksList.detailsDocId = docId
bookmarksList.detailsContents = JSON.stringify(contents)
PopupUtils.open(detailsPopCom, bookmarksList)
}
}
}
OptionSelector {
id: filterSelector
StateSaver.properties: 'selectedIndex'
anchors.bottom: parent.bottom
text: i18n.tr('N/A')
expanded: true
model: ListModel {
ListElement { label: 'Newly Added'; expression: "[ 'meta.visits' ]"; query: "[ { 'visits': 0 } ]" }
ListElement { label: 'Ubuntu'; expression: "[ 'uri' ]"; query: "[ 'http://www.ubuntu*' ]" }
ListElement { label: 'Search'; expression: "[ 'meta.title' ]"; query: "[ 'Search*' ]" }
ListElement { label: 'Engine'; expression: "[ 'meta.tags' ]"; query: "[ 'engine' ]" }
ListElement { label: 'All'; expression: "[ 'meta.visits', 'meta.title' ]"; query: "[ '*', '*' ]" }
}
delegate: OptionSelectorDelegate {
text: i18n.tr(label)
}
selectedIndex: model.count - 1
onSelectedIndexChanged: {
var d = model.get(selectedIndex)
text = '%1 - %2'.arg(d.expression).arg(d.query)
allBookmarks.index.expression = eval(d.expression)
allBookmarks.query = eval(d.query)
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-1/ 0000775 0000000 0000000 00000000000 14367477523 0017700 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-1/u1db-qt-example-1.qdoc 0000664 0000000 0000000 00000001361 14367477523 0023615 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
/*!
\page u1db-qt-tutorial-1.html
*/
u1db-qt-0.1.7/examples/u1db-qt-example-1/u1db-qt-example-1.qml 0000664 0000000 0000000 00000005420 14367477523 0023460 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
MainView {
id: u1dbView
width: units.gu(45)
height: units.gu(80)
/*!
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
*/
U1db.Database {
id: aDatabase
path: Qt.resolvedUrl("aDatabase1");
}
/*!
A Document can be declared at runtime. It requires at the very least a unique 'docId', but that alone won't do anything special. In order for a document to be entered into the database the below snippet demonstrates the basic requirements. The id might be optional.
*/
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "hello": "Hello World!" }
}
Tabs {
id: tabs
anchors.fill: parent
Tab {
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
ListView {
width: units.gu(45)
height: units.gu(80)
/*
Here is the reference to the Database model mentioned earlier.
*/
model: aDatabase
/* A delegate will be created for each Document retrieved from the Database */
delegate: Text {
x: 66; y: 77
text: {
/*!
The object called 'contents' contains a string as demonstrated here. In this example 'hello' is our search string.
text: contents.hello
*/
text: contents.hello
}
}
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-2/ 0000775 0000000 0000000 00000000000 14367477523 0017701 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-2/u1db-qt-example-2.qdoc 0000664 0000000 0000000 00000001361 14367477523 0023617 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
/*!
\page u1db-qt-tutorial-2.html
*/
u1db-qt-0.1.7/examples/u1db-qt-example-2/u1db-qt-example-2.qml 0000664 0000000 0000000 00000005471 14367477523 0023470 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
MainView {
id: u1dbView
width: units.gu(45)
height: units.gu(80)
/*!
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
*/
U1db.Database {
id: aDatabase
path: Qt.resolvedUrl("aDatabase2")
}
Timer {
property int i: 0; interval: 5000; running: true; repeat: true
onTriggered: newDocumentObject()
function newDocumentObject() {
var qmlString = "import QtQuick 2.0; import U1db 1.0 as U1db; U1db.Document {id: aDcoument"+i+";database: aDatabase;docId: 'helloworld"+i+"';create: true; defaults: { 'hello': 'Hello New Document "+i+"!' }}"
Qt.createQmlObject(qmlString, u1dbView, "dynamicNewDocument"+i);
i = i+1
}
}
Tabs {
id: tabs
anchors.fill: parent
Tab {
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
ListView {
width: units.gu(45)
height: units.gu(80)
/*
Here is the reference to the Database model mentioned earlier.
*/
model: aDatabase
/* A delegate will be created for each Document retrieved from the Database */
delegate: Text {
x: 66; y: 77
text: {
/*!
The object called 'contents' contains a string as demonstrated here. In this example 'hello' is our search string.
text: contents.hello
*/
text: contents.hello
}
}
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-2b/ 0000775 0000000 0000000 00000000000 14367477523 0020043 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-2b/u1db-qt-example-2b.qdoc 0000664 0000000 0000000 00000001362 14367477523 0024124 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
/*!
\page u1db-qt-tutorial-2b.html
*/
u1db-qt-0.1.7/examples/u1db-qt-example-2b/u1db-qt-example-2b.qml 0000664 0000000 0000000 00000006557 14367477523 0024002 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
/*!
This example demonstrates how to create and query one level of sub-fields in a document.
*/
MainView {
id: u1dbView
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: Qt.resolvedUrl("aDatabase2b")
}
/*!
This snippet demonstrates how to create content that includes nested fields. The main field is 'hello', while the sub-field for each entry is 'value'. Later in the example it will be shown how to access each of these in the delegate of a ListView.
U1db.Document {
id: aDocument
database: aDatabase
docId: 'hello'
create: true
defaults: { "hello": [{"value":"99 Hello Worlds on the wall...!"},{"value":"98 Hello Worlds on the wall...!"},{"value":"97 Hello Worlds on the wall...!"},{"value":"...and so on..."}] }
}
*/
U1db.Document {
id: aDocument
database: aDatabase
docId: 'hello'
create: true
defaults: { "hello": [{"value":"99 Hello Worlds on the wall...!"},{"value":"98 Hello Worlds on the wall...!"},{"value":"97 Hello Worlds on the wall...!"},{"value":"...and so on..."}] }
}
Tabs {
id: tabs
anchors.fill: parent
Tab {
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
ListView {
width: units.gu(45)
height: units.gu(80)
anchors.fill: parent
model: aDocument.contents.hello
/*!
Determining the current record is easy. All that is required is to access it using the delegate's own 'index' value, as shown here:
delegate: Text {
height: 30
text: aDocument.contents.hello[index].value
}
Remember that when the entries were created the sub-field was 'value'. So where index = 0, 'aDocument.contents.hello[0].value' will produce '99 Hello Worlds on the wall...!'. Each entry in the document will in turn create its own delegate with a new index number, which can then be used to extract the 'value' (or whatever other sub-field has been created).
*/
delegate: Text {
height: 30
text: aDocument.contents.hello[index].value
}
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-3/ 0000775 0000000 0000000 00000000000 14367477523 0017702 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-3/u1db-qt-example-3.qdoc 0000664 0000000 0000000 00000001361 14367477523 0023621 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
/*!
\page u1db-qt-tutorial-3.html
*/
u1db-qt-0.1.7/examples/u1db-qt-example-3/u1db-qt-example-3.qml 0000664 0000000 0000000 00000034172 14367477523 0023472 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
/*!
This example and tutorial is designed to show a wide variety of U1Db-Qt functionality and usage. The example demonstrates:
\list 1
\li Combining U1Db-Qt with elements and components that do not utilize models
\li Blending the U1Db-Qt plugin with QML and Javascript
\endlist
*/
MainView {
width: units.gu(45)
height: units.gu(80)
/*!
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
U1db.Database {
id: aDatabase
path: "aDatabase3"
}
*/
U1db.Database {
id: aDatabase
path: Qt.resolvedUrl("aDatabase3")
}
/*!
A Document can be declared at runtime. It requires at the very least a unique 'docId', but that alone won't do anything special. The snipet below snippet demonstrates the basic requirements.
In addition to this, this example displays text from the database for a specific docId and id key in a text area called 'documentContent. To update the text area at startup with either the default value or a value from the database the onCompleted function is utilized, which is also demonstrated below.
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "helloworld":"Hello World" }
Component.onCompleted: {
documentContent.text = aDocument.contents.helloworld
}
}
*/
U1db.Document {
id: aDocument
database: aDatabase
docId: 'helloworld'
create: true
defaults: { "helloworld":"Hello World" }
Component.onCompleted: {
documentContent.text = aDocument.contents.helloworld
}
}
function switchToPreviousDocument(documentObject){
aDocument.docId = getPreviousDocumentId(documentObject)
}
function switchToNextDocument(){
aDocument.docId = getNextDocumentId(aDocument)
}
function getPreviousDocumentId(documentObject){
if(typeof documentObject!='undefined'){
/*!
The listDocs method retrieves all the docId values from the current database. In this demonstration the values are put into an array, which is then checked to locate the docId for the current and previous documents within the database.
var documentIds = {}
documentIds = documentObject.database.listDocs()
for(var i = 0; i < documentIds.length; i++){
if(documentIds[i]===documentObject.docId && i > 0){
return documentIds[i-1]
}
else if(documentIds[i]===documentObject.docId && i==0){
return documentIds[documentIds.length-1]
}
}
*/
var documentIds = {}
documentIds = documentObject.database.listDocs()
for(var i = 0; i < documentIds.length; i++){
if(documentIds[i]===documentObject.docId && i > 0){
return documentIds[i-1]
}
else if(documentIds[i]===documentObject.docId && i==0){
return documentIds[documentIds.length-1]
}
}
return documentIds[0]
}
else{
print("Error!")
return ''
}
}
function getNextDocumentId(documentObject){
if(typeof documentObject!='undefined'){
var documentIds = documentObject.database.listDocs()
for(var i = 0; i < documentIds.length; i++){
if(documentIds[i]===documentObject.docId && i < (documentIds.length-1)){
return documentIds[i+1]
}
else if(documentIds[i]===documentObject.docId && i==(documentIds.length-1)){
return documentIds[0]
}
}
return documentIds[0]
}
else{
print("Error!")
return ''
}
}
function getCurrentDocumentKey(contentsObject){
if(typeof contentsObject!='undefined'){
var keys = Object.keys(contentsObject);
return keys[0]
}
else{
return ''
}
}
function updateContentWindow(documentText, addressBarText) {
// Somewhere below need to check for things like invalid docId
if(documentText!==addressBarText) {
/*!
These steps demonstrate the creation of a temporary document, based on a copy of the global document. This will then be used to determine if there is already a document in the database with the same docId as the address bar, and additionally with a key id with the same name.
var tempDocument = {}
var tempFieldName = addressBarText;
var tempContents = {};
tempDocument = aDocument
tempDocument.docId = addressBarText;
tempContents = tempDocument.contents
NOTE: For simplicity sake this example sometimes uses the same value for both the docId and the key id, as seen here. Real life implimentations can and will differ, and this will be demonstrated elsewhere in the example code.
*/
var tempDocument = {}
var tempFieldName = addressBarText;
var tempContents = {};
tempDocument = aDocument
tempDocument.docId = addressBarText;
tempContents = tempDocument.contents
if(typeof tempContents !='undefined' && typeof tempContents[tempFieldName]!='undefined') {
aDocument = tempDocument
documentContent.text = tempContents[tempFieldName]
}
else {
/*!
Here the contents of the temporary document are modified, which then replaces the global document.
documentContent.text = 'More Hello World...';
tempContents = {}
tempContents[tempFieldName] = documentContent.text
tempDocument.contents = tempContents
aDocument = tempDocument
*/
documentContent.text = 'More Hello World...';
tempContents = {}
tempContents[tempFieldName] = documentContent.text
tempDocument.contents = tempContents
aDocument = tempDocument
}
}
else {
/*!
In this instance the current document's content is updated from the text view. The unique key and docId are not modified because the database already contains a record with those properties.
tempContents = {}
tempFieldName = getCurrentDocumentKey(aDocument.contents)
tempContents[tempFieldName] = documentContent.text
aDocument.contents = tempContents
*/
tempContents = {}
tempFieldName = getCurrentDocumentKey(aDocument.contents)
tempContents[tempFieldName] = documentContent.text
aDocument.contents = tempContents
}
}
Tabs {
id: tabs
Tab {
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
/*! Here a rectangle is defined that represents the lower portion of our application. It will contain all the main parts of the application.
Rectangle {
width: units.gu(45)
height: units.gu(70)
anchors.bottom: parent.bottom
color: "#00FFFFFF"
// The remainder of the main part of the application goes here ...
}
*/
Rectangle {
width: units.gu(45)
height: units.gu(70)
anchors.bottom: parent.bottom
color: "#00FFFFFF"
Rectangle {
width: units.gu(45)
height: units.gu(60)
anchors.bottom: parent.bottom
/*!
The following TextArea is for displaying contents for the current state of the global document, as defined by the key / name in the address bar.
TextArea{
id: documentContent
selectByMouse : false
x: units.gu(1)
y: units.gu(1)
width: units.gu(43)
height: units.gu(58)
color: "#000000"
}
*/
TextArea{
id: documentContent
selectByMouse : false
x: units.gu(1)
y: units.gu(1)
width: units.gu(43)
height: units.gu(58)
color: "#000000"
}
}
// This rectangle contains our navigation controls
Rectangle {
width: units.gu(43)
height: units.gu(5)
anchors.top: addressBarArea.bottom
x: units.gu(1.5)
color: "#00FFFFFF"
Row{
width: units.gu(43)
height: units.gu(5)
anchors.verticalCenter: parent.verticalCenter
spacing: units.gu(2)
Button {
text: "<"
onClicked: updateContentWindow(switchToPreviousDocument(aDocument), addressBar.text)
}
Button {
text: "Home"
onClicked: updateContentWindow(getCurrentDocumentKey(aDocument.contents),'helloworld')
}
Button {
text: "Save"
onClicked: updateContentWindow(getCurrentDocumentKey(aDocument.contents),addressBar.text)
}
Button {
text: ">"
onClicked: updateContentWindow(switchToNextDocument(aDocument), addressBar.text)
}
}
}
Rectangle {
id: addressBarArea
width: units.gu(45)
height: units.gu(5)
anchors.top: parent.top
TextField {
id: addressBar
width: units.gu(43)
anchors.verticalCenter: parent.verticalCenter
x: units.gu(1)
hasClearButton: false
/*!
There is an object within in the 'aDocument' model defined earlier called 'contents', which contains a key called 'helloworld', which represents a search string. In our example the key will represent the name of a document in the database, which will be displayed in the address bar. Displaying the key is demonstrated here:
text: displayKey(aDocument.contents)
function displayKey(documentObject){
var keys = Object.keys(documentObject);
return keys[0]
}
*/
text: getCurrentDocumentKey(aDocument.contents)
onAccepted: {
onClicked: updateContentWindow(getCurrentDocumentKey(aDocument.contents),addressBar.text)
}
}
}
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-5/ 0000775 0000000 0000000 00000000000 14367477523 0017704 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-5/u1db-qt-example-5.qdoc 0000664 0000000 0000000 00000032671 14367477523 0023635 0 ustar 00root root 0000000 0000000 /*!
\page u1db-qt-tutorial-5.html
\title U1Db-Qt Index Tutorial
This tutorial is designed to demonstrate a variety of essential U1Db-Qt functionality and usage, including:
\list 1
\li Utilizing the U1db-Qt Index element
\li Various approaches to define U1db-Qt Document elements when using the Index element
\li Partnering the U1db-Qt Index element and a QML ListView element
\endlist
\section1 Storing Data
\section2 The Database Element
\section3 Creating a Database
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
\code
U1db.Database {
id: aDatabase
path: "aDatabase4"
}
\endcode
\section1 The Document Element
\section2 Declaring Documents (at Runtime)
A Document can be instantiated at runtime, or generated dynamically. The examples below demonstrate the former.
A very basic Document could include its unique 'id' and 'docId' properties. While it is not mandatory to define these properties, in some cases they can be convenient references. More advanced applications would likely find these very useful, and in some cases may be an absolute necessity to achieve the objectives of the program.
This example of a very simple Document will not initially do anything, until more properties are added and defined:
\code
U1db.Document {
id: aDocument1
docId: 'helloworld1'
}
\endcode
A basic but still practical Document definition contains several essential properties. In addition to 'id' and 'docId' (discussed above), the 'database', 'create', and 'defaults' properties are also very important, and are introduced below.
The 'database' property ensures that the Document is attached to an already defined (or possibly soon to be defined one) identified by its id (in this case 'aDatabase'). For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
}
\endcode
Should the Database not already contain a Document with the same docId ('hellowworld1' in this example) when a 'create' property is present and set to true it will be generated. For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
create: true
}
\endcode
However, the Document still requires some data to be useful, which is what the 'defaults' property provides. The value of 'defaults' is a map of data that will be stored in the database (again when the create property is et to true). It contain key:value pairs, where the value can be a string, number, or nested object (e.g. additional fields, lists). For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
create: true
defaults:{"hello": { "world": { "message":"Hello World", "id": 1 } } }
}
\endcode
As mentioned above, lists can also be nested in Document data. Lists provide a convenient method for producing multiple instances of the same key (AKA 'field' or 'sub-field'). The example code below shows valid use of the 'message' and 'id' sub-fields multiple times within the same object.
\code
U1db.Document {
id: aDocument2
database: aDatabase
docId: 'helloworld2'
create: true
defaults:{"hello": { "world": [
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
] } }
}
\endcode
When the default Javascript Object Notation itself is formatted with appropriate line breaks and indentation, it becomes easier to visualize an embedded list, containing sub-fields 'message' and 'id' (and their respective values):
\code
{"hello":
{ "world":
[
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
]
}
}
\endcode
In dot notation these sub-fields are represented by 'hello.world.message' and 'hello.world.id' respectively. Later in this tutorial these will be utilized within the 'expression' property of U1Db-Qt's Index element, in close collaboration with a QML ListView's delegates.
Normally when a docId already exists in a database, and when the set flag is set to true, the value in 'defaults' will be ignored (and the existing data in the database will remain untouched). Sometimes a developer needs to easily overwrite the data in an existing document. The 'contents' property can be used for just that purpose. When 'contents' is defined, its value will replace existing data in the database, for the document identified by the docId. In addition, 'contents' can be used to add new documents, in the same way as the 'create: true' + 'defaults' combination does; in other words, if the document defined by 'docId' does not exist it will be created.
\code
U1db.Document {
id: aDocument3
database: aDatabase
docId: 'helloworld3'
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
\endcode
If 'defaults' exists, 'create' is set to 'true' (or 'false' for that matter) and 'contents' is also defined, it is the latter that takes precidence. In other words, 'create' and 'defaults' will be ignored. The following example demonstrates this scenario:
\code
U1db.Document {
id: aDocument3
database: aDatabase
docId: 'helloworld3'
create: true
default:{"hello": { "world": [{ "message":"Hello World", "id": 3 }] } }
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
\endcode
This snippet simply represents the absence of the 'create' property, which is synonymous with 'create: false'. The Document can still be recognized within the application, but until applicable properties (such as those outlined above) are added and/or modified then nothing will be added or modified in the database, and this instance may have very little practical value.
\code
U1db.Document {
id: aDocument4
database: aDatabase
docId: 'helloworld4'
defaults:{"hello": { "world": { "message":"Hello World", "id": 4 } } }
}
\endcode
\section3 Samples of Stored Documents
The data stored in the database after defining the above Document elements (and then running the application, will consist of the following:
\table
\header
\li docId
\li content
\row
\li 'helloworld1'
\li
\code
{
"hello": {
"world": {
"id": 1,
"message": "Hello World"
}
}
}
\endcode
\row
\li 'helloworld2'
\li
\code
{
"hello": {
"world": [
{
"id": 2,
"message": "Hello World"
},
{
"id": 2.5,
"message": "Hello World"
}
]
}
}
\endcode
\row
\li 'helloworld3'
\li
\code
{
"hello": {
"world": [
{
"id": 3,
"message": "Hello World"
},
{
"id": 3.33,
"message": "Hello World"
},
{
"id": 3.66,
"message": "Hello World"
}
]
}
}
\endcode
\endtable
\section1 Retrieving Data
To retrieve the Documents that were declared earlier requires two additional elements: Index and Query.
\section2 The Index Element
\section3 Creating and Index Element
The Index element requires both a unique 'id' and a pointer to a 'database' in order to begin becoming useful, as demonstrated here:
\code
U1db.Index{
database: aDatabase
id: by_helloworld
}
\endcode
In the future, the Index element will support on disk storage of appropriate results / data. At the present time only in memory indexing is done, but once the storing capability is implemented, defining and identifying it is as simple as using the 'name' property (which will be stored in the database along with the relvent data that goes with it). The snippet below shows the use of the 'name' property:
\code
U1db.Index{
database: aDatabase
id: by_helloworld
//name: "by-helloworld"
}
\endcode
The Index element describes, using dot notation, the fields and sub-fields where the developer expects to find information. That information is defined in a list, and added as the value for the 'expression' property. The list can contain one or more entries, as exemplified here (the property is commented out due to its current status):
\code
U1db.Index{
database: aDatabase
id: by_helloworld
//name: "by-helloworld"
expression: ["hello.world.id","hello.world.message"]
}
\endcode
\section2 The QueryElement
\section3 Creating a Query Element
The Query element has two responsibilities: a bridge from Database+Index to other parts of the application, as well as further filtering of data in the database (in addition to what Index provides).
In order to fulfil its duties as a bridge to an Index (and Database), the 'index' property must point to an Index element, identified by its 'id'. For example:
\code
U1db.Query{
id: aQuery
index: by_helloworld
}
\endcode
While Index helps to filter data based on 'where' it is located (e.g. field.sub-field), Query helps determine the additional set of criteria for 'what' is being searched for. The intent of the 'query' property is to provide the mechanism for defnining the search criteria, but at the time of writing that functionality is not yet available. However, once the implementation is in place, using it is only requires defining the property's value (e.g. "Hello World"). Wild card searches using '*' are supported, which is the default query (i.e. if 'query' is not set it is assumed to be '*'). For example (the property is commented out due to its current status):
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "*"
}
\endcode
When the 'query' property becomes available, only wildcard search definitions for "starts with" will be suppoprted. Thus the following would be supported:
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "Hello*"
}
\endcode
But this would not:
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "*World"
}
\endcode
Note: again, the 'query' property is commented out in the above two snippets due to its current status
\section1 Using Data
\section2 Data and the Application UI
\section3 Using Data With Models and Views
This simple snippet represents how to attach a ListModel to a ListView. In this instance the model 'aQuery' is representative of the Query + Index combination defined earlier:
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
}
\endcode
\section4 Data and Delegates
How a model and ListView + delegates work together is a common QML concept, and not specific to U1Db-Qt. However, the asynchronous nature of this relationship is important to understand. When using QML ListView, delegates will be created based on particular properties such as the size of the application window, ListView, and delegate itself (amongst other factors). Each delegate can then represent a Document retrieved from the Database based on the record's index. This example demonstrates some of the property definitions that contribute to determining the number of delegates a ListView will contain:
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
}
}
\endcode
When the number of Documents is less than or equal to the number of delegates then there is a one to one mapping of index to delegate (e.g. the first delegate will represent the Document with an index = 0; the second, index = 1; and so on).
When there are more Documents than delegates the ListView will request a new index depending on the situation (e.g. a user scrolls up or down). For example, if a ListView has 10 delegates, but 32 Documents to handle, when a user initially scrolls the first delegate will change from representing the Document with index = 0 to the Document that might have index = 8; the second, from index = 1 to index = 9; ...; the 10th delegate from index = 9 to index = 17. A second scrolling gesture the first index may change to 15, and the final index 24. And so on. Scrolling in the opposite direction will have a similar effect, but the Document index numbers for each delegate will obviously start to decline (towards their original values).
The following snippet, which modifies the above delegate definition, could demonstrate this effect if there were enough Documents to do so (i.e. some number greater than the number of delegates):
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
text: index
}
}
\endcode
The object called 'contents' contains one or more properties. This example demonstrates the retrieval of data based on the U1db.Index defined earlier (id: by-helloworld). In this instance the Index contained two expressions simultaniously, "hello.world.id" and "hello.world.message"
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
text: "(" + index + ") '" + contents.message + " " + contents.id + "'"
}
}
\endcode
*/
u1db-qt-0.1.7/examples/u1db-qt-example-5/u1db-qt-example-5.qml 0000664 0000000 0000000 00000005453 14367477523 0023476 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
MainView {
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: Qt.resolvedUrl("aDatabase5")
}
U1db.Document {
database: aDatabase
docId: 'helloworld1'
create: true
defaults:{"hello": { "world": { "message":"Hello World", "id": 1 } } }
}
U1db.Document {
database: aDatabase
docId: 'helloworld2'
create: true
defaults:{"hello": { "world": [
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
] } }
}
U1db.Document {
database: aDatabase
docId: 'helloworld3'
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
U1db.Document {
database: aDatabase
docId: 'helloworld4'
defaults:{"hello": { "world": { "message":"Hello World", "id": 4 } } }
}
U1db.Index{
database: aDatabase
id: by_helloworld
expression: ["hello.world.id","hello.world.message"]
}
U1db.Query{
id: aQuery
index: by_helloworld
query: [{"id":"*"},{"message":"Hel*"}]
}
Tabs {
id: tabs
Tab {
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
text: "(" + index + ") '" + contents.message + " " + contents.id + "'"
}
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-6/ 0000775 0000000 0000000 00000000000 14367477523 0017705 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-6/u1db-qt-example-6.qdoc 0000664 0000000 0000000 00000032745 14367477523 0023641 0 ustar 00root root 0000000 0000000 /*!
\page u1db-qt-tutorial-6.html
\title U1Db-Qt Synchronizing Tutorial
This tutorial is designed to demonstrate a variety of essential U1Db-Qt functionality and usage, including:
\list 1
\li Synchronizing two databases
\li Utilizing the U1db-Qt Index element
\li Various approaches to define U1db-Qt Document elements when using the Index element
\li Partnering the U1db-Qt Index element and a QML ListView element
\endlist
\section1 Storing Data
\section2 The Database Element
\section3 Creating a Database
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
\code
U1db.Database {
id: aDatabase
path: "aDatabase4"
}
\endcode
\section1 The Document Element
\section2 Declaring Documents (at Runtime)
A Document can be instantiated at runtime, or generated dynamically. The examples below demonstrate the former.
A very basic Document could include its unique 'id' and 'docId' properties. While it is not mandatory to define these properties, in some cases they can be convenient references. More advanced applications would likely find these very useful, and in some cases may be an absolute necessity to achieve the objectives of the program.
This example of a very simple Document will not initially do anything, until more properties are added and defined:
\code
U1db.Document {
id: aDocument1
docId: 'helloworld1'
}
\endcode
A basic but still practical Document definition contains several essential properties. In addition to 'id' and 'docId' (discussed above), the 'database', 'create', and 'defaults' properties are also very important, and are introduced below.
The 'database' property ensures that the Document is attached to an already defined (or possibly soon to be defined one) identified by its id (in this case 'aDatabase'). For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
}
\endcode
Should the Database not already contain a Document with the same docId ('hellowworld1' in this example) when a 'create' property is present and set to true it will be generated. For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
create: true
}
\endcode
However, the Document still requires some data to be useful, which is what the 'defaults' property provides. The value of 'defaults' is a map of data that will be stored in the database (again when the create property is et to true). It contain key:value pairs, where the value can be a string, number, or nested object (e.g. additional fields, lists). For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
create: true
defaults:{"hello": { "world": { "message":"Hello World", "id": 1 } } }
}
\endcode
As mentioned above, lists can also be nested in Document data. Lists provide a convenient method for producing multiple instances of the same key (AKA 'field' or 'sub-field'). The example code below shows valid use of the 'message' and 'id' sub-fields multiple times within the same object.
\code
U1db.Document {
id: aDocument2
database: aDatabase
docId: 'helloworld2'
create: true
defaults:{"hello": { "world": [
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
] } }
}
\endcode
When the default Javascript Object Notation itself is formatted with appropriate line breaks and indentation, it becomes easier to visualize an embedded list, containing sub-fields 'message' and 'id' (and their respective values):
\code
{"hello":
{ "world":
[
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
]
}
}
\endcode
In dot notation these sub-fields are represented by 'hello.world.message' and 'hello.world.id' respectively. Later in this tutorial these will be utilized within the 'expression' property of U1Db-Qt's Index element, in close collaboration with a QML ListView's delegates.
Normally when a docId already exists in a database, and when the set flag is set to true, the value in 'defaults' will be ignored (and the existing data in the database will remain untouched). Sometimes a developer needs to easily overwrite the data in an existing document. The 'contents' property can be used for just that purpose. When 'contents' is defined, its value will replace existing data in the database, for the document identified by the docId. In addition, 'contents' can be used to add new documents, in the same way as the 'create: true' + 'defaults' combination does; in other words, if the document defined by 'docId' does not exist it will be created.
\code
U1db.Document {
id: aDocument3
database: aDatabase
docId: 'helloworld3'
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
\endcode
If 'defaults' exists, 'create' is set to 'true' (or 'false' for that matter) and 'contents' is also defined, it is the latter that takes precidence. In other words, 'create' and 'defaults' will be ignored. The following example demonstrates this scenario:
\code
U1db.Document {
id: aDocument3
database: aDatabase
docId: 'helloworld3'
create: true
default:{"hello": { "world": [{ "message":"Hello World", "id": 3 }] } }
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
\endcode
This snippet simply represents the absence of the 'create' property, which is synonymous with 'create: false'. The Document can still be recognized within the application, but until applicable properties (such as those outlined above) are added and/or modified then nothing will be added or modified in the database, and this instance may have very little practical value.
\code
U1db.Document {
id: aDocument4
database: aDatabase
docId: 'helloworld4'
defaults:{"hello": { "world": { "message":"Hello World", "id": 4 } } }
}
\endcode
\section3 Samples of Stored Documents
The data stored in the database after defining the above Document elements (and then running the application, will consist of the following:
\table
\header
\li docId
\li content
\row
\li 'helloworld1'
\li
\code
{
"hello": {
"world": {
"id": 1,
"message": "Hello World"
}
}
}
\endcode
\row
\li 'helloworld2'
\li
\code
{
"hello": {
"world": [
{
"id": 2,
"message": "Hello World"
},
{
"id": 2.5,
"message": "Hello World"
}
]
}
}
\endcode
\row
\li 'helloworld3'
\li
\code
{
"hello": {
"world": [
{
"id": 3,
"message": "Hello World"
},
{
"id": 3.33,
"message": "Hello World"
},
{
"id": 3.66,
"message": "Hello World"
}
]
}
}
\endcode
\endtable
\section1 Retrieving Data
To retrieve the Documents that were declared earlier requires two additional elements: Index and Query.
\section2 The Index Element
\section3 Creating and Index Element
The Index element requires both a unique 'id' and a pointer to a 'database' in order to begin becoming useful, as demonstrated here:
\code
U1db.Index{
database: aDatabase
id: by_helloworld
}
\endcode
In the future, the Index element will support on disk storage of appropriate results / data. At the present time only in memory indexing is done, but once the storing capability is implemented, defining and identifying it is as simple as using the 'name' property (which will be stored in the database along with the relvent data that goes with it). The snippet below shows the use of the 'name' property:
\code
U1db.Index{
database: aDatabase
id: by_helloworld
//name: "by-helloworld"
}
\endcode
The Index element describes, using dot notation, the fields and sub-fields where the developer expects to find information. That information is defined in a list, and added as the value for the 'expression' property. The list can contain one or more entries, as exemplified here (the property is commented out due to its current status):
\code
U1db.Index{
database: aDatabase
id: by_helloworld
//name: "by-helloworld"
expression: ["hello.world.id","hello.world.message"]
}
\endcode
\section2 The QueryElement
\section3 Creating a Query Element
The Query element has two responsibilities: a bridge from Database+Index to other parts of the application, as well as further filtering of data in the database (in addition to what Index provides).
In order to fulfil its duties as a bridge to an Index (and Database), the 'index' property must point to an Index element, identified by its 'id'. For example:
\code
U1db.Query{
id: aQuery
index: by_helloworld
}
\endcode
While Index helps to filter data based on 'where' it is located (e.g. field.sub-field), Query helps determine the additional set of criteria for 'what' is being searched for. The intent of the 'query' property is to provide the mechanism for defnining the search criteria, but at the time of writing that functionality is not yet available. However, once the implementation is in place, using it is only requires defining the property's value (e.g. "Hello World"). Wild card searches using '*' are supported, which is the default query (i.e. if 'query' is not set it is assumed to be '*'). For example (the property is commented out due to its current status):
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "*"
}
\endcode
When the 'query' property becomes available, only wildcard search definitions for "starts with" will be suppoprted. Thus the following would be supported:
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "Hello*"
}
\endcode
But this would not:
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "*World"
}
\endcode
Note: again, the 'query' property is commented out in the above two snippets due to its current status
\section1 Using Data
\section2 Data and the Application UI
\section3 Using Data With Models and Views
This simple snippet represents how to attach a ListModel to a ListView. In this instance the model 'aQuery' is representative of the Query + Index combination defined earlier:
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
}
\endcode
\section4 Data and Delegates
How a model and ListView + delegates work together is a common QML concept, and not specific to U1Db-Qt. However, the asynchronous nature of this relationship is important to understand. When using QML ListView, delegates will be created based on particular properties such as the size of the application window, ListView, and delegate itself (amongst other factors). Each delegate can then represent a Document retrieved from the Database based on the record's index. This example demonstrates some of the property definitions that contribute to determining the number of delegates a ListView will contain:
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
}
}
\endcode
When the number of Documents is less than or equal to the number of delegates then there is a one to one mapping of index to delegate (e.g. the first delegate will represent the Document with an index = 0; the second, index = 1; and so on).
When there are more Documents than delegates the ListView will request a new index depending on the situation (e.g. a user scrolls up or down). For example, if a ListView has 10 delegates, but 32 Documents to handle, when a user initially scrolls the first delegate will change from representing the Document with index = 0 to the Document that might have index = 8; the second, from index = 1 to index = 9; ...; the 10th delegate from index = 9 to index = 17. A second scrolling gesture the first index may change to 15, and the final index 24. And so on. Scrolling in the opposite direction will have a similar effect, but the Document index numbers for each delegate will obviously start to decline (towards their original values).
The following snippet, which modifies the above delegate definition, could demonstrate this effect if there were enough Documents to do so (i.e. some number greater than the number of delegates):
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
text: index
}
}
\endcode
The object called 'contents' contains one or more properties. This example demonstrates the retrieval of data based on the U1db.Index defined earlier (id: by-helloworld). In this instance the Index contained two expressions simultaniously, "hello.world.id" and "hello.world.message"
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
text: "(" + index + ") '" + contents.message + " " + contents.id + "'"
}
}
\endcode
*/
u1db-qt-0.1.7/examples/u1db-qt-example-6/u1db-qt-example-6.qml 0000664 0000000 0000000 00000011534 14367477523 0023475 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
Item {
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
path: Qt.resolvedUrl("aDatabase6");
}
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld'
create: true
contents:{"hello": { "world": [ { "message": "Hello World" } ] } }
}
U1db.Index{
database: aDatabase
id: by_helloworld
expression: ["hello.world.message"]
}
U1db.Query{
id: aQuery
index: by_helloworld
query: [{"message":"Hel*"}]
}
U1db.Synchronizer{
id: aSynchronizer
source: aDatabase
targets: [{remote:true},
{remote:true,
ip:"127.0.0.1",
port: 7777,
name:"example1.u1db",
resolve_to_source:true},
{remote:"OK"}]
synchronize: false
}
MainView {
id: u1dbView
width: units.gu(45)
height: units.gu(80)
anchors.top: parent.top;
Tabs {
id: tabs
anchors.fill: parent
Tab {
objectName: "Tab1"
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
Rectangle {
width: units.gu(45)
height: units.gu(40)
anchors.top: parent.top;
border.width: 1
Text {
id: sourceLabel
anchors.top: parent.top;
font.bold: true
text: "aDatabase6 Contents"
}
ListView {
id: sourceListView
width: units.gu(45)
height: units.gu(35)
anchors.top: sourceLabel.bottom;
model: aQuery
delegate: Text {
wrapMode: Text.WordWrap
x: 6; y: 77
text: {
text: "(" + index + ") '" + contents.message + "'"
}
}
}
}
Rectangle {
id: lowerRectangle
width: units.gu(45)
height: units.gu(35)
anchors.bottom: parent.bottom;
border.width: 1
Text {
id: errorsLabel
anchors.top: parent.top;
font.bold: true
text: "Log:"
}
ListView {
parent: lowerRectangle
width: units.gu(45)
height: units.gu(30)
anchors.top: errorsLabel.bottom;
model: aSynchronizer
delegate:Text {
width: units.gu(40)
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: sync_output.message_value
}
}
Button{
parent: lowerRectangle
anchors.bottom: parent.bottom;
text: "Sync"
onClicked: aSynchronizer.synchronize = true
anchors.left: parent.left
anchors.right: parent.right
}
}
}
}
}
}
}
u1db-qt-0.1.7/examples/u1db-qt-example-7/ 0000775 0000000 0000000 00000000000 14367477523 0017706 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/examples/u1db-qt-example-7/u1db-qt-example-7.qml 0000664 0000000 0000000 00000003603 14367477523 0023475 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2015 Canonical, Ltd.
*
* Authors:
* Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
MainView {
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: aDatabase
}
U1db.Document {
database: aDatabase
docId: "department"
contents: {"department": "department of redundancy department",
"managers": [
{"name": "Mary", "phone_number": "12345"},
{"name": "Katherine"},
{"name": "Rob", "phone_number": "54321"}
]
}
}
U1db.Index{
database: aDatabase
id: by_phonenumber
expression: ["managers.phone_number"]
}
U1db.Query{
id: aQuery
index: by_phonenumber
}
Tabs {
id: tabs
Tab {
title: i18n.tr("Hello U1Db!")
page: Page {
id: helloPage
ListView {
anchors.fill: parent
model: aQuery
delegate: Text {
text: "(" + index + ") " + JSON.stringify(contents)
}
}
}
}
}
}
u1db-qt-0.1.7/gallery/ 0000775 0000000 0000000 00000000000 14367477523 0014455 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/gallery/CMakeLists.txt 0000664 0000000 0000000 00000000325 14367477523 0017215 0 ustar 00root root 0000000 0000000 install(FILES gallery.qml SplitView.qml
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/u1db-qt/gallery
)
install(FILES u1db-qt-gallery.desktop
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications
)
u1db-qt-0.1.7/gallery/SplitView.qml 0000664 0000000 0000000 00000003666 14367477523 0017131 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
import QtWebKit 3.0
import QtWebKit.experimental 1.0
Tab {
id: exampleView
property string example
title: "Example %1".arg(example)
Row {
id: splitView
property string qml: Qt.resolvedUrl('../examples/u1db-qt-example-%1.qml'.arg(example))
property string html: 'file:////usr/share/u1db-qt/examples/u1db-qt-example-%1.html'.arg(example)
anchors.fill: parent
Loader {
width: parent.width / 3
source: splitView.qml
asynchronous: true
}
// TODO: syntax highlighting
// FIXME: switching tabs with web views may crash lp#1124065
WebView {
width: parent.width / 3
height: parent.height
url: splitView.qml
// FIXME: default font size is extremely small lp#1169989
experimental.preferences.minimumFontSize: units.dp(24)
}
WebView {
width: parent.width / 3
height: parent.height
url: splitView.html
experimental.preferences.minimumFontSize: units.dp(24)
// TODO: open help browser onNavigationRequested: { url }
}
}
}
u1db-qt-0.1.7/gallery/gallery.qml 0000664 0000000 0000000 00000002435 14367477523 0016633 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import Ubuntu.Components 0.1
MainView {
width: units.gu(60)
height: units.gu(80)
Page {
Tabs {
/* FIXME: lp#1167568 Repeater {
model: ["1", "2", "2b", "3", "4", "5"]
SplitView {
example: modelData
}
} */
SplitView { example: "1" }
SplitView { example: "2" }
SplitView { example: "2b" }
SplitView { example: "3" }
SplitView { example: "4" }
SplitView { example: "5" }
}
}
}
u1db-qt-0.1.7/gallery/u1db-qt-gallery.desktop 0000664 0000000 0000000 00000000344 14367477523 0020763 0 ustar 00root root 0000000 0000000 [Desktop Entry]
Type=Application
Exec=qmlscene /usr/share/u1db-qt/gallery/gallery.qml
Path=/usr/share/u1db-qt/gallery
Name=U1Db QML Example Gallery
Icon=/usr/share/icons/unity-icon-theme/places/svg/service-u1.svg
Terminal=false
u1db-qt-0.1.7/libu1db-qt.pc.in 0000664 0000000 0000000 00000000453 14367477523 0015715 0 ustar 00root root 0000000 0000000 prefix=@PREFIX@
exec_prefix=@EXEC_PREFIX@
libdir=${exec_prefix}/lib
includedir=${prefix}/@INCLUDE_INSTALL_DIR@
Name: @U1DB_QT_LIBNAME@
Description: Qt binding and QML plugin for U1DB.
Version: 1.0
Requires: @QT_PKGCONFIG_DEPENDENCIES@
Libs: -L${libdir} -l@U1DB_QT_LIBNAME@
Cflags: -I${includedir}
u1db-qt-0.1.7/modules/ 0000775 0000000 0000000 00000000000 14367477523 0014466 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/modules/CMakeLists.txt 0000664 0000000 0000000 00000000027 14367477523 0017225 0 ustar 00root root 0000000 0000000 add_subdirectory(U1db)
u1db-qt-0.1.7/modules/U1db/ 0000775 0000000 0000000 00000000000 14367477523 0015261 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/modules/U1db/CMakeLists.txt 0000664 0000000 0000000 00000003110 14367477523 0020014 0 ustar 00root root 0000000 0000000 find_package(Qt5Quick REQUIRED)
find_package(Qt5Network REQUIRED)
get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION)
# See http://doc-snapshot.qt-project.org/5.0/qtcore/qlibraryinfo.html#LibraryLocation-enum
# exec_program(${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_QML" OUTPUT_VARIABLE QT_IMPORTS_DIR)
exec_program(${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_QML" OUTPUT_VARIABLE QT_IMPORTS_DIR)
file(TO_CMAKE_PATH "${QT_IMPORTS_DIR}" QT_IMPORTS_DIR)
set(U1DBPlugin_SRCS
plugin.cpp
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${Qt5Sql_INCLUDE_DIRS}
${Qt5Network_INCLUDE_DIRS}
)
add_library(U1DBPlugin SHARED ${U1DBPlugin_SRCS})
add_dependencies(check U1DBPlugin)
target_link_libraries(U1DBPlugin
${U1DB_QT_LIBNAME}
${Qt5Quick_LIBRARIES}
${Qt5Network_LIBRARIES}
)
include_directories(
${CMAKE_SOURCE_DIR}/src
${U1DB_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}
${Qt5Quick_INCLUDE_DIRS}
${Qt5Network_INCLUDE_DIRS}
)
# copy qmldir file into build directory for shadow builds
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
)
install(TARGETS U1DBPlugin
LIBRARY DESTINATION ${QT_IMPORTS_DIR}/U1db
)
install(FILES qmldir
DESTINATION ${QT_IMPORTS_DIR}/U1db
)
add_custom_command(
TARGET U1DBPlugin
POST_BUILD
COMMAND "qmlplugindump" "U1db" "1.0" "${CMAKE_BINARY_DIR}/modules" ">" "plugins.qmltypes"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plugins.qmltypes
DESTINATION ${QT_IMPORTS_DIR}/U1db
)
u1db-qt-0.1.7/modules/U1db/plugin.cpp 0000664 0000000 0000000 00000002270 14367477523 0017264 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include "database.h"
#include "document.h"
#include "index.h"
#include "query.h"
#include "synchronizer.h"
#include "plugin.h"
#include
QT_USE_NAMESPACE_U1DB
void U1DBPlugin::registerTypes(const char *uri)
{
qmlRegisterType(uri, 1, 0, "Database");
qmlRegisterType(uri, 1, 0, "Document");
qmlRegisterType(uri, 1, 0, "Index");
qmlRegisterType(uri, 1, 0, "Query");
qmlRegisterType(uri, 1, 0, "Synchronizer");
}
u1db-qt-0.1.7/modules/U1db/plugin.h 0000664 0000000 0000000 00000001755 14367477523 0016740 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_PLUGIN_H
#define U1DB_PLUGIN_H
#include
class U1DBPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri);
};
#endif // U1DB_PLUGIN_H
u1db-qt-0.1.7/modules/U1db/qmldir 0000664 0000000 0000000 00000000036 14367477523 0016473 0 ustar 00root root 0000000 0000000 module U1db
plugin U1DBPlugin
u1db-qt-0.1.7/qtcreator/ 0000775 0000000 0000000 00000000000 14367477523 0015022 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/qtcreator/CMakeLists.txt 0000664 0000000 0000000 00000000327 14367477523 0017564 0 ustar 00root root 0000000 0000000 set(U1DB_WIZARDS "${CMAKE_INSTALL_PREFIX}/share/qtcreator/templates/qml")
install(DIRECTORY "settings"
DESTINATION "${U1DB_WIZARDS}"
)
install(DIRECTORY "contacts"
DESTINATION "${U1DB_WIZARDS}"
)
u1db-qt-0.1.7/qtcreator/contacts/ 0000775 0000000 0000000 00000000000 14367477523 0016640 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/qtcreator/contacts/main.qml 0000664 0000000 0000000 00000004560 14367477523 0020304 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
import Ubuntu.Components.ListItems 0.1 as ListItem
MainView {
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: contactsDatabase
/*
Uncomment to persistently store contacts on disk
path: "contacts.db"
*/
}
U1db.Document {
database: contactsDatabase
docId: 'person0'
create: true
defaults: { 'name': 'John', 'city': 'Dublin', 'phone': 65849 }
}
U1db.Document {
database: contactsDatabase
docId: 'person1'
create: true
defaults: { 'name': 'Ivanka', 'city': 'Dublin', 'phone': 98765 }
}
U1db.Document {
database: contactsDatabase
docId: 'person2'
create: true
defaults: { 'name': 'Leonardo', 'city': 'Rome', 'phone': 12345 }
}
U1db.Index {
database: contactsDatabase
id: byCityName
expression: [ "city" ]
}
U1db.Query {
id: numberOne
index: byCityName
query: [ "Dublin" ]
}
Page {
Tabs {
Tab {
title: i18n.tr("People living in Dublin")
page: Page {
anchors.centerIn: parent
ListView {
width: units.gu(45)
height: units.gu(80)
model: numberOne
delegate: ListItem.Subtitled {
text: contents.name
subText: contents.city
}
}
}
}
}
}
}
u1db-qt-0.1.7/qtcreator/contacts/template.xml 0000664 0000000 0000000 00000001036 14367477523 0021175 0 ustar 00root root 0000000 0000000
Showing a U1Db query in a ListViewUbuntu Components can be used to display a U1Db query.<br/>Any changes are updated automatically.<br/><br/>Requires <b>Qt 5.0</b> or newer.
u1db-qt-0.1.7/qtcreator/settings/ 0000775 0000000 0000000 00000000000 14367477523 0016662 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/qtcreator/settings/main.qml 0000664 0000000 0000000 00000005755 14367477523 0020335 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import U1db 1.0 as U1db
import Ubuntu.Components 0.1
MainView {
width: units.gu(45)
height: units.gu(80)
U1db.Database {
id: settingsDatabase
/*
Uncomment to persistently store settings on disk
path: "settings.db"
*/
}
U1db.Document {
id: settingsDocument
database: settingsDatabase
docId: 'settings'
create: true
defaults: { "sound": true, "music": false, "username": "Joe User" }
}
Page {
Tabs {
Tab {
title: i18n.tr("Game Settings")
page: Page {
anchors.centerIn: parent
Column {
spacing: units.gu(2)
Row {
spacing: units.gu(2)
Label {
text: i18n.tr("Username")
width: units.gu(19)
anchors.verticalCenter: parent.verticalCenter
}
TextField {
placeholderText: settingsDocument.contents.username
}
}
Row {
spacing: units.gu(2)
Label {
text: i18n.tr("Sound")
width: units.gu(19)
anchors.verticalCenter: parent.verticalCenter
}
Switch {
checked: settingsDocument.contents.sound
}
}
Row {
spacing: units.gu(2)
Label {
text: i18n.tr("Music")
width: units.gu(19)
anchors.verticalCenter: parent.verticalCenter
}
Switch {
checked: settingsDocument.contents.music
}
}
}
}
}
}
}
}
u1db-qt-0.1.7/qtcreator/settings/template.xml 0000664 0000000 0000000 00000001046 14367477523 0021220 0 ustar 00root root 0000000 0000000
Storing app settings in U1DbA straightforward example of storing data in a U1Db document.<br/>The data can be displayed using standard QML items.<br/><br/>Requires <b>Qt 5.0</b> or newer.
u1db-qt-0.1.7/src/ 0000775 0000000 0000000 00000000000 14367477523 0013605 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/src/CMakeLists.txt 0000664 0000000 0000000 00000002372 14367477523 0016351 0 ustar 00root root 0000000 0000000 set(U1DB_QT_LIBNAME u1db-qt5)
# Sources
set(U1DB_QT_SRCS
database.cpp
document.cpp
index.cpp
query.cpp
synchronizer.cpp
)
# Generated files
set(U1DB_QT_GENERATED
moc_database.cpp
moc_document.cpp
moc_index.cpp
moc_query.cpp
moc_synchronizer.cpp
)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${U1DB_QT_GENERATED}")
# Resources
set(U1DB_QT_RESOURCES
sql.qrc
)
QT5_ADD_RESOURCES(U1DB_QT_RCC ${U1DB_QT_RESOURCES})
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${Qt5Core_INCLUDE_DIRS}
${Qt5Network_INCLUDE_DIRS}
${Qt5Sql_INCLUDE_DIRS}
${U1DB_INCLUDE_DIRS}
)
add_library(${U1DB_QT_LIBNAME} SHARED ${U1DB_QT_SRCS} ${U1DB_QT_RCC})
target_link_libraries(${U1DB_QT_LIBNAME}
${Qt5Core_LIBRARIES}
${Qt5Sql_LIBRARIES}
${Qt5Network_LIBRARIES}
${U1DB_LDFLAGS}
)
set_target_properties(${U1DB_QT_LIBNAME} PROPERTIES
SOVERSION 3
VERSION 3.0.0
)
# Install
set(INCLUDE_INSTALL_DIR include/lib${U1DB_QT_LIBNAME})
install(TARGETS ${U1DB_QT_LIBNAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES global.h database.h document.h index.h query.h synchronizer.h
DESTINATION ${INCLUDE_INSTALL_DIR}
)
u1db-qt-0.1.7/src/database.cpp 0000664 0000000 0000000 00000072122 14367477523 0016061 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "database.h"
#include "private.h"
QT_BEGIN_NAMESPACE_U1DB
const QString Database::MEMORY_PATH = ":memory:";
namespace
{
class ScopedTransaction
{
public:
ScopedTransaction(QSqlDatabase &db) :
m_db(db),
m_transaction(false)
{
m_transaction = m_db.transaction();
}
~ScopedTransaction()
{
if (m_transaction)
{
m_db.commit();
}
}
QSqlDatabase &m_db;
bool m_transaction;
};
}
/*!
\class Database
\inmodule U1Db
\ingroup cpp
\brief The Database class implements on-disk storage for documents and indexes.
Database can be used as a QAbstractListModel, delegates will then have access to \a docId and \a contents
analogous to the properties of Document.
*/
/*!
\qmltype Database
\instantiates Database
\inqmlmodule U1Db 1.0
\ingroup modules
\brief Database implements on-disk storage for documents and indexes.
In a ListView the Database can be used as a model which includes all documents
in the database. For listing only a subset of documents Query can be used.
\qml
ListView {
model: Database {
id: myDatabase
}
delegate: ListItem.Subtitled {
text: docId
subText: contents.color
}
}
\endqml
\sa Query
*/
/*!
A unique identifier for the state of synchronization
*/
QString
Database::getReplicaUid()
{
QSqlQuery query (m_db.exec("SELECT value FROM u1db_config WHERE name = 'replica_uid'"));
if (!query.lastError().isValid() && query.next())
return query.value(0).toString();
return setError(QString("Failed to get replica UID: %1\n%2").arg(query.lastError().text()).arg(query.lastQuery())) ? QString() : QString();
}
/*!
Sanitize path
*/
QString Database::sanitizePath(const QString& path)
{
if (path == Database::MEMORY_PATH)
return path;
if (!path.count())
return Database::MEMORY_PATH;
QUrl url(path);
if (url.isValid() && url.isLocalFile())
{
return url.path();
}
else if (QDir::isRelativePath(path))
{
QString dataPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
return QDir(dataPath).absoluteFilePath(path);
}
return path;
}
/*!
Checks if the underlying SQLite database is ready to be used
Only to be used as a utility function by initializeIfNeeded()
*/
bool
Database::isInitialized()
{
m_db.exec("PRAGMA case_sensitive_like=ON");
QSqlQuery query(m_db.exec(
"SELECT value FROM u1db_config WHERE name = 'sql_schema'"));
return query.next();
}
/*!
Describes the error as a string if the last operation failed.
*/
bool
Database::setError(const QString& error)
{
qWarning("u1db: %s", qPrintable(error));
m_error = error;
Q_EMIT errorChanged(error);
return false;
}
/*!
\qmlproperty string Database::error
The last error as a string if the last operation failed.
*/
/*!
The last error as a string if the last operation failed.
*/
QString
Database::lastError()
{
return m_error;
}
/*!
Ensures that the underlying database works, or tries to set it up:
The SQlite backend is loaded - it's an optional Qt5 module and can fail
If @path is an existing database, it'll be opened
For a new database, the default schema will be applied
*/
bool
Database::initializeIfNeeded(const QString& path)
{
if (m_db.isOpen())
return true;
/* A unique ID is used for the connection name to ensure that we aren't
re-using or replacing other opend databases. */
if (!m_db.isValid())
m_db = QSqlDatabase::addDatabase("QSQLITE",QUuid::createUuid().toString());
if (!m_db.isValid())
return setError("QSqlDatabase error");
if (path != Database::MEMORY_PATH)
{
QDir parent(QFileInfo(path).dir());
if (!parent.mkpath(parent.path()))
setError(QString("Failed to make parent folder %1").arg(parent.path()));
}
m_db.setDatabaseName(path);
if (!m_db.open())
return setError(QString("Failed to open '%1`: %2").arg(path).arg(m_db.lastError().text()));
if (!isInitialized())
{
if (!isInitialized())
{
QFile file(":/dbschema.sql");
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
ScopedTransaction t(m_db);
while (!file.atEnd())
{
QByteArray line = file.readLine();
while (!line.endsWith(";\n") && !file.atEnd())
line += file.readLine();
if (m_db.exec(line).lastError().isValid())
return setError(QString("Failed to apply internal schema: %1\n%2").arg(m_db.lastError().text()).arg(QString(line)));
}
QSqlQuery query(m_db.exec());
query.prepare("INSERT OR REPLACE INTO u1db_config VALUES ('replica_uid', :uuid)");
query.bindValue(":uuid", QUuid::createUuid().toString());
if (!query.exec())
return setError(QString("Failed to apply internal schema: %1\n%2").arg(m_db.lastError().text()).arg(query.lastQuery()));
// Double-check
if (query.boundValue(0).toString() != getReplicaUid())
return setError(QString("Invalid replica uid: %1").arg(query.boundValue(0).toString()));
}
else
return setError(QString("Failed to read internal schema: FileError %1").arg(file.error()));
}
}
return true;
}
/*!
Instantiate a new Database with an optional \a parent,
usually by declaring it as a QML item.
*/
Database::Database(QObject *parent) :
QAbstractListModel(parent), m_path("")
{
initializeIfNeeded();
}
/*!
Used to implement QAbstractListModel
Returns docId matching the given row index
assuming all documents are ordered consistently
*/
QString
Database::getDocIdByRow(int row) const
{
if (!m_db.isOpen())
return QString();
QSqlQuery query(m_db.exec());
query.prepare("SELECT doc_id FROM document LIMIT 1 OFFSET :row");
query.bindValue(":row", row);
if (query.exec() && query.next())
return query.value("doc_id").toString();
return QString();
}
/*!
\internal
Used to implement QAbstractListModel
Implements the variables exposed to the Delegate in a model
QVariant contents
QString docId
int index (built-in)
*/
QVariant
Database::data(const QModelIndex & index, int role) const
{
QString docId(getDocIdByRow(index.row()));
if (role == 0) // contents
return getDocUnchecked(docId);
if (role == 1) // docId
return docId;
return QVariant();
}
/*!
\internal
Used to implement QAbstractListModel
Defines \b{contents} and \b{docId} as variables exposed to the Delegate in a model
\b{index} is supported out of the box.
*/
QHash
Database::roleNames() const
{
QHash roles;
roles.insert(0, "contents");
roles.insert(1, "docId");
return roles;
}
/*!
\internal
Used to implement QAbstractListModel
The number of rows: the number of documents in the database.
*/
int
Database::rowCount(const QModelIndex & parent) const
{
if (!m_db.isOpen())
return 0;
QSqlQuery query(m_db.exec());
query.prepare("SELECT COUNT(*) AS count FROM document");
if (!(query.exec() && query.next()))
return 0;
return query.value("count").toInt();
}
/*!
Same functionality as Database::getDoc() except it won't set Database::lastError() and it
doesn't implicitly try to initialize the underlying database.
\a docId must be a valid unique ID string
Use cases: model implementations, Document::getContents()
*/
QVariant
Database::getDocUnchecked(const QString& docId) const
{
if (!m_db.isOpen())
return QVariant();
QSqlQuery query(m_db.exec());
query.prepare("SELECT doc_rev, content FROM document WHERE doc_id = :docId");
query.bindValue(":docId", docId);
if (query.exec() && query.next())
{
// Convert JSON string to the Variant that QML expects
QJsonDocument json(QJsonDocument::fromJson(query.value("content").toByteArray()));
Q_EMIT docLoaded(docId, json.object().toVariantMap());
return json.object().toVariantMap();
}
return QVariant();
}
/*!
* \internal
* \brief Database::getDocumentContents
*
* Returns the string representation of a document that has
* been selected from the database using a document id.
*
*/
QString
Database::getDocumentContents(const QString& docId)
{
if (!initializeIfNeeded())
return QString();
QSqlQuery query(m_db.exec());
query.prepare("SELECT document.doc_rev, document.content, "
"count(conflicts.doc_rev) AS conflicts FROM document LEFT OUTER JOIN "
"conflicts ON conflicts.doc_id = document.doc_id WHERE "
"document.doc_id = :docId GROUP BY document.doc_id, "
"document.doc_rev, document.content");
query.bindValue(":docId", docId);
if (query.exec())
{
if (query.next())
{
if (query.value("conflicts").toInt() > 0)
setError(QString("Conflicts in %1").arg(docId));
return query.value("content").toString();
}
return setError(QString("Failed to get document %1: No document").arg(docId)) ? QString() : QString();
}
return setError(QString("Failed to get document %1: %2\n%3").arg(docId).arg(query.lastError().text()).arg(query.lastQuery())) ? QString() : QString();
}
/*!
\qmlmethod Variant Database::getDoc(string)
Returns the contents of a document by \a docId in a form that QML recognizes
as a Variant object, it's identical to Document::getContents() with the
same \a docId.
*/
/*!
* Returns the contents of a document by \a docId in a form that QML recognizes
* as a Variant object, it's identical to Document::getContents() with the
* same \a docId.
*/
QVariant
Database::getDoc(const QString& docId)
{
if (!initializeIfNeeded())
return QVariant();
QSqlQuery query(m_db.exec());
query.prepare("SELECT document.doc_rev, document.content, "
"count(conflicts.doc_rev) AS conflicts FROM document LEFT OUTER JOIN "
"conflicts ON conflicts.doc_id = document.doc_id WHERE "
"document.doc_id = :docId GROUP BY document.doc_id, "
"document.doc_rev, document.content");
query.bindValue(":docId", docId);
if (query.exec())
{
if (query.next())
{
if (query.value("conflicts").toInt() > 0)
setError(QString("Conflicts in %1").arg(docId));
// Convert JSON string to the Variant that QML expects
QJsonDocument json(QJsonDocument::fromJson(query.value("content").toByteArray()));
Q_EMIT docLoaded(docId, json.object().toVariantMap());
return json.object().toVariantMap();
}
return setError(QString("Failed to get document %1: No document").arg(docId)) ? QVariant() : QVariant();
}
return setError(QString("Failed to get document %1: %2\n%3").arg(docId).arg(query.lastError().text()).arg(query.lastQuery())) ? QVariant() : QVariant();
}
/*!
* \internal
This function creates a new revision number.
It returns a string for use in the document table's 'doc_rev' field.
*/
QString Database::getNextDocRevisionNumber(QString doc_id)
{
QString revision_number = getReplicaUid()+":1";
QString current_revision_number = getCurrentDocRevisionNumber(doc_id);
/*!
Some revisions contain information from previous
conflicts/syncs. Revisions are delimited by '|'.
*/
QStringList current_revision_list = current_revision_number.split("|");
Q_FOREACH (QString current_revision, current_revision_list) {
/*!
Each revision contains two pieces of information,
the uid of the database that made the revsion, and a counter
for the revsion. This information is delimited by ':'.
*/
QStringList current_revision_number_list = current_revision.split(":");
if(current_revision_number_list[0]==getReplicaUid()) {
/*!
If the current revision uid is the same as this Database's uid the counter portion is increased by one.
*/
int revision_generation_number = current_revision_number_list[1].toInt()+1;
revision_number = getReplicaUid()+":"+QString::number(revision_generation_number);
}
else {
/*!
If the current revision uid is not the same as this Database's uid then the revision represents a change that originated in another database.
*/
//revision_number+="|"+current_revision;
/* Not sure if the above is necessary,
*and did not appear to be working as intended either.
*
* Commented out, but maybe OK to delete.
*/
}
}
/*!
The Database UID has curly brackets, but they are not required for the revision number and need to be removed.
*/
revision_number = revision_number.replace("{","");
revision_number = revision_number.replace("}","");
return revision_number;
}
/*!
* \internal
The getCurrentDocRevisionNumber(QString doc_id) function
returns the current string value from the document table's
doc_rev field.
*/
QString Database::getCurrentDocRevisionNumber(QString doc_id){
if (!initializeIfNeeded())
return QString();
QSqlQuery query(m_db.exec());
query.prepare("SELECT doc_rev from document WHERE doc_id = :docId");
query.bindValue(":docId", doc_id);
if (query.exec())
{
while (query.next())
{
return query.value("doc_rev").toString();
}
}
else{
return setError(query.lastError().text()) ? QString() : QString();
}
return QString();
}
/*!
* \internal
* \brief Database::updateSyncLog
*
* This method is used at the end of a synchronization session,
* to update the database with the latest information known about the peer
* database that was synced against.
*/
void Database::updateSyncLog(bool insert, QString uid, QString generation, QString transaction_id)
{
if (!initializeIfNeeded())
return;
QSqlQuery query(m_db.exec());
if(insert==true){
query.prepare("INSERT INTO sync_log(known_generation,known_transation_id,known_transation_id) VALUES(:knownGeneration, :knownTransactionId, :replicaUid)");
}
else{
query.prepare("UPDATE sync_log SET known_generation = :knownGeneration, known_transation_id = :knownTransactionId WHERE replica_uid = :replicaUid");
}
query.bindValue(":replicaUid", uid);
query.bindValue(":knownGeneration", generation);
query.bindValue(":knownTransactionId", transaction_id);
if (!query.exec())
{
setError(query.lastError().text());
}
}
/*!
* \internal
*
* Whenever a document as added or modified it needs a new revision number.
*
* The revision number contains information about revisions made at the source,
* but also revisions to the document by target databases (and then synced with the source).
*
*/
void Database::updateDocRevisionNumber(QString doc_id,QString revision){
if (!initializeIfNeeded())
return;
QSqlQuery query(m_db.exec());
query.prepare("UPDATE document SET doc_rev = :revisionId WHERE doc_id = :docId");
query.bindValue(":docId", doc_id);
query.bindValue(":revisionId", revision);
if (!query.exec())
{
setError(query.lastError().text());
}
}
/*!
The getCurrentGenerationNumber() function searches for the
current generation number from the sqlite_sequence table.
The return value can then be used during a synchronization session,
amongst other things.
*/
int Database::getCurrentGenerationNumber(){
int sequence_number = -1;
QSqlQuery query(m_db.exec());
query.prepare("SELECT seq FROM sqlite_sequence WHERE name = 'transaction_log'");
if (query.exec())
{
while (query.next())
{
sequence_number = (query.value("seq").toInt());
}
}
else{
setError(query.lastError().text());
}
return sequence_number;
}
/*!
The generateNewTransactionId() function generates a random
transaction id string, for use when creating new transations.
*/
QString Database::generateNewTransactionId(){
QString uid = "T-"+QUuid::createUuid().toString();
uid = uid.replace("}","");
uid = uid.replace("{","");
return uid;
}
/*!
Each time a document in the Database is created or updated a
new transaction is performed, and information about it inserted into the
transation_log table using the createNewTransaction(QString doc_id)
function.
*/
int Database::createNewTransaction(QString doc_id){
QString transaction_id = generateNewTransactionId();
QSqlQuery query(m_db.exec());
QString queryString = "INSERT INTO transaction_log(doc_id, transaction_id) VALUES('"+doc_id+"', '"+transaction_id+"')";
if (!query.exec(queryString)){
return -1;
}
else{
return 0;
}
return -1;
}
/*!
\qmlmethod string Database::putDoc(var, string)
Updates the existing \a contents of the document identified by \a docId if
there's no error.
If no \a docId is given or \a docId is an empty string the \a contents will be
stored under an autogenerated name.
Returns the new revision of the document, or -1 on failure.
*/
/*!
Updates the existing \a contents of the document identified by \a docId if
there's no error.
If no \a docId is given or \a docId is an empty string the \a contents will be
stored under an autogenerated name.
Returns the new revision of the document, or -1 on failure.
*/
QString
Database::putDoc(QVariant contents, const QString& docId)
{
if (!initializeIfNeeded())
return "";
if (contents.canConvert())
contents = contents.value();
ScopedTransaction t(m_db);
QString newOrEmptyDocId(docId);
QVariant oldDoc = newOrEmptyDocId.isEmpty() ? QVariant() : getDocUnchecked(newOrEmptyDocId);
QString revision_number = getNextDocRevisionNumber(newOrEmptyDocId);
QSqlQuery query(m_db.exec());
if (oldDoc.isValid())
{
query.prepare("UPDATE document SET doc_rev=:docRev, content=:docJson WHERE doc_id = :docId");
query.bindValue(":docId", newOrEmptyDocId);
query.bindValue(":docRev", revision_number);
// Parse Variant from QML as JsonDocument, fallback to string
QString json(QJsonDocument::fromVariant(contents).toJson());
query.bindValue(":docJson", json.isEmpty() ? contents : json);
if (!query.exec())
return setError(QString("Failed to put/ update document %1: %2\n%3").arg(newOrEmptyDocId).arg(query.lastError().text()).arg(query.lastQuery())) ? "" : "";
query.prepare("DELETE FROM document_fields WHERE doc_id = :docId");
query.bindValue(":docId", newOrEmptyDocId);
if (!query.exec())
return setError(QString("Failed to delete document field %1: %2\n%3").arg(newOrEmptyDocId).arg(query.lastError().text()).arg(query.lastQuery())) ? "" : "";
createNewTransaction(newOrEmptyDocId);
}
else
{
if (newOrEmptyDocId.isEmpty())
newOrEmptyDocId = QString("D-%1").arg(QUuid::createUuid().toString().mid(1).replace("}",""));
if (!QRegExp("^[a-zA-Z0-9.%_-]+$").exactMatch(newOrEmptyDocId))
return setError(QString("Invalid docID %1").arg(newOrEmptyDocId)) ? "" : "";
query.prepare("INSERT INTO document (doc_id, doc_rev, content) VALUES (:docId, :docRev, :docJson)");
query.bindValue(":docId", newOrEmptyDocId);
query.bindValue(":docRev", revision_number);
// Parse Variant from QML as JsonDocument, fallback to string
QJsonDocument json(QJsonDocument::fromVariant(contents));
query.bindValue(":docJson", json.isEmpty() ? contents : json.toJson());
if (!query.exec())
return setError(QString("Failed to put document %1: %2\n%3").arg(docId).arg(query.lastError().text()).arg(query.lastQuery())) ? "" : "";
createNewTransaction(newOrEmptyDocId);
}
beginResetModel();
endResetModel();
/* FIXME investigate correctly notifying about new rows
beginInsertRows(QModelIndex(), rowCount(), 0);
endInsertRows();
*/
Q_EMIT docChanged(newOrEmptyDocId, contents);
return revision_number;
}
/*!
\qmlmethod void Database::deleteDoc(string)
Deletes the document identified by \a docId.
*/
/*!
Deletes the document identified by \a docId.
*/
void
Database::deleteDoc(const QString& docId)
{
putDoc(QString(), docId);
}
/*!
* \brief Database::resetModel
*
* Resets the Database model.
*/
void Database::resetModel(){
beginResetModel();
endResetModel();
}
/*!
\qmlmethod list Database::listDocs()
Returns a list of all stored documents by their docId.
*/
/*!
Returns a list of all stored documents by their docId.
*/
QList
Database::listDocs()
{
QList list;
if (!initializeIfNeeded())
return list;
QSqlQuery query(m_db.exec());
query.prepare("SELECT document.doc_id, document.doc_rev, document.content, "
"count(conflicts.doc_rev) FROM document LEFT OUTER JOIN conflicts "
"ON conflicts.doc_id = document.doc_id GROUP BY document.doc_id, "
"document.doc_rev, document.content");
if (query.exec())
{
while (query.next())
{
list.append(query.value("doc_id").toString());
}
return list;
}
return setError(QString("Failed to list documents: %1\n%2").arg(query.lastError().text()).arg(query.lastQuery())) ? list : list;
}
/*!
\qmlproperty string Database::path
A relative \a path can be given to store the database in an app-specific
writable folder. This is recommended as it ensures to work with confinement.
If more control is needed absolute paths or local file URIs can be used.
By default or if the path is empty everything is stored in memory.
*/
/*!
A relative \a path can be given to store the database in an app-specific
writable folder. This is recommended as it ensures to work with confinement.
If more control is needed absolute paths or local file URIs can be used.
By default or if the path is empty everything is stored in memory.
*/
void
Database::setPath(const QString& path)
{
if (m_path == path)
return;
beginResetModel();
m_db.close();
initializeIfNeeded(sanitizePath(path));
endResetModel();
m_path = path;
Q_EMIT pathChanged(m_path);
}
/*!
* Returns the path of the database.
*/
QString
Database::getPath()
{
return m_path;
}
/*!
Stores a new index under the given \a indexName, with \a expressions.
An existing index won't be replaced implicitly, an error will be set in that case.
*/
QString
Database::putIndex(const QString& indexName, QStringList expressions)
{
if (indexName.isEmpty() || expressions.isEmpty())
return QString("Either name or expressions is empty");
Q_FOREACH (QString expression, expressions)
if (expression.isEmpty() || expression.isNull())
return QString("Empty expression in list");
if (!initializeIfNeeded())
return QString("Database isn't ready");
ScopedTransaction t(m_db);
QStringList results = getIndexExpressions(indexName);
bool changed = false;
Q_FOREACH (QString expression, expressions)
if (results.contains(expression))
changed = true;
if (changed)
return QString("Index conflicts with existing index");
QSqlQuery query(m_db.exec());
query.prepare("INSERT INTO index_definitions VALUES (:indexName, :offset, :field)");
QVariantList indexNameData;
QVariantList offsetData;
QVariantList fieldData;
for (int i = 0; i < expressions.count(); ++i)
{
indexNameData << indexName;
offsetData << i;
fieldData << expressions.at(i);
}
query.addBindValue(indexNameData);
query.addBindValue(offsetData);
query.addBindValue(fieldData);
if (!query.execBatch())
return QString("Failed to insert index definition: %1\n%2").arg(m_db.lastError().text()).arg(query.lastQuery());
return QString();
}
/*!
Gets the expressions saved with putIndex().
\a indexName: the unique name of an existing index
*/
QStringList
Database::getIndexExpressions(const QString& indexName)
{
QStringList expressions;
if (!initializeIfNeeded())
return expressions;
QSqlQuery query(m_db.exec());
query.prepare("SELECT field FROM index_definitions WHERE name = :indexName ORDER BY offset DESC");
query.bindValue(":indexName", indexName);
if (!query.exec())
return setError(QString("Failed to lookup index definition: %1\n%2").arg(m_db.lastError().text()).arg(query.lastQuery())) ? expressions : expressions;
while (query.next())
expressions.append(query.value("field").toString());
return expressions;
}
/*!
Lists the index keys of an index created with putIndex().
\a indexName: the unique name of an existing index
*/
QStringList
Database::getIndexKeys(const QString& indexName)
{
QStringList list;
if (!initializeIfNeeded())
return list;
QStringList expressions = getIndexExpressions(indexName);
QString valueFields, tables, noValueWhere;
int i = 0;
Q_FOREACH (QString expression, expressions)
{
valueFields += QString("d%1.value,").arg(i);
tables += QString("document_fields d%1,").arg(i);
noValueWhere += QString("d.doc_id = d%1.doc_id AND d%1.field_name = \"%2\" AND ").arg(
i).arg(expression);
}
if (valueFields.endsWith(","))
valueFields.chop(1);
if (tables.endsWith(","))
tables.chop(1);
if (noValueWhere.endsWith("AND "))
noValueWhere.chop(4);
QString where;
i = 0;
Q_FOREACH (QString expression, expressions)
{
where += QString("%1 AND d%2.value NOT NULL AND ").arg(noValueWhere).arg(i);
i++;
}
if (where.endsWith("AND "))
where.chop(4);
QSqlQuery query(m_db.exec());
query.prepare(QString("SELECT %1 FROM document d, %2 WHERE %3 GROUP BY %1").arg(
valueFields, tables, where));
if (!query.exec())
return setError(QString("Failed to get index keys: %1\n%2").arg(m_db.lastError().text()).arg(query.lastQuery())) ? list : list;
while (query.next())
list.append(query.value("value").toString());
return list;
}
/* Handy functions for synchronization. */
/*!
* \internal
* \brief Database::listTransactionsSince
*
* This lists transactions for the database since a particular generation number.
*
*/
QList Database::listTransactionsSince(int generation){
QList list;
if (!initializeIfNeeded())
return list;
QSqlQuery query(m_db.exec());
QString queryStmt = "SELECT generation, doc_id, transaction_id FROM transaction_log where generation > "+QString::number(generation);
if (query.exec(queryStmt))
{
while (query.next())
{
list.append(query.value("generation").toString()+"|"+query.value("doc_id").toString()+"|"+query.value("transaction_id").toString());
}
return list;
}
return list;
}
/*!
* \internal
* \brief Database::getSyncLogInfo
*
* Provides the information about previous synchronizations between the database and another (if any).
*
*/
QMap Database::getSyncLogInfo(QMap lastSyncInformation, QString uid, QString prefix){
if (!initializeIfNeeded())
return lastSyncInformation;
QString queryStmt = "SELECT known_transaction_id, known_generation FROM sync_log WHERE replica_uid = '"+uid +"'";
QSqlQuery query(m_db.exec());
if (query.exec(queryStmt))
{
while (query.next())
{
lastSyncInformation.insert(prefix + "_replica_generation", query.value(1).toInt());
lastSyncInformation.insert(prefix + "_replica_transaction_id",query.value(0).toString());
return lastSyncInformation;
}
}
else{
setError(query.lastError().text());
}
return lastSyncInformation;
}
QT_END_NAMESPACE_U1DB
#include "moc_database.cpp"
u1db-qt-0.1.7/src/database.h 0000664 0000000 0000000 00000007316 14367477523 0015531 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_DATABASE_H
#define U1DB_DATABASE_H
#include "global.h"
#include
#include
#include
#include
QT_BEGIN_NAMESPACE_U1DB
class Q_DECL_EXPORT Database : public QAbstractListModel {
Q_OBJECT
/*! path */
Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
/*! error */
Q_PROPERTY(QString error READ lastError NOTIFY errorChanged)
public:
Database(QObject* parent = 0);
// QAbstractListModel
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
QHashroleNames() const;
int rowCount(const QModelIndex & parent = QModelIndex()) const;
void resetModel();
QString getPath();
void setPath(const QString& path);
Q_INVOKABLE QVariant getDoc(const QString& docId);
QString getDocumentContents(const QString& docId);
QVariant getDocUnchecked(const QString& docId) const;
Q_INVOKABLE QString putDoc(QVariant newDoc, const QString& docID=QString());
Q_INVOKABLE void deleteDoc(const QString& docID);
Q_INVOKABLE QList listDocs();
Q_INVOKABLE QString lastError();
Q_INVOKABLE QString putIndex(const QString& index_name, QStringList expressions);
Q_INVOKABLE QStringList getIndexExpressions(const QString& indexName);
Q_INVOKABLE QStringList getIndexKeys(const QString& indexName);
/* Functions handy for Synchronization */
QString getNextDocRevisionNumber(QString doc_id);
QString getCurrentDocRevisionNumber(QString doc_id);
void updateDocRevisionNumber(QString doc_id,QString revision);
void updateSyncLog(bool insert, QString uid, QString generation, QString transaction_id);
QList listTransactionsSince(int generation);
QMap getSyncLogInfo(QMap lastSyncInformation, QString uid, QString prefix);
Q_SIGNALS:
/*!
\signal Database::pathChanged
The database path changed - the empty string means it's in-memory only.
*/
void pathChanged(const QString& path);
/*!
\signal Database::errorChanged
An error occurred. Use lastError() to check it.
*/
void errorChanged(const QString& error);
/*!
A document's contents were modified.
*/
void docChanged(const QString& docId, QVariant content);
/*!
A document was loaded via its docID.
*/
void docLoaded(const QString& docId, QVariant content) const;
private:
//Q_DISABLE_COPY(Database)
static const QString MEMORY_PATH;
QString m_path;
QSqlDatabase m_db;
QString m_error;
QString getReplicaUid();
QString sanitizePath(const QString& path);
bool isInitialized();
bool initializeIfNeeded(const QString& path=Database::MEMORY_PATH);
bool setError(const QString& error);
QString getDocIdByRow(int row) const;
int createNewTransaction(QString doc_id);
QString generateNewTransactionId();
int getCurrentGenerationNumber();
};
QT_END_NAMESPACE_U1DB
#endif // U1DB_DATABASE_H
u1db-qt-0.1.7/src/dbschema.sql 0000664 0000000 0000000 00000002054 14367477523 0016075 0 ustar 00root root 0000000 0000000 -- Database schema
CREATE TABLE transaction_log (
generation INTEGER PRIMARY KEY AUTOINCREMENT,
doc_id TEXT NOT NULL,
transaction_id TEXT NOT NULL
);
CREATE TABLE document (
doc_id TEXT PRIMARY KEY,
doc_rev TEXT NOT NULL,
content TEXT
);
CREATE TABLE document_fields (
doc_id TEXT NOT NULL,
field_name TEXT NOT NULL,
value TEXT
);
CREATE INDEX document_fields_field_value_doc_idx
ON document_fields(field_name, value, doc_id);
CREATE TABLE sync_log (
replica_uid TEXT PRIMARY KEY,
known_generation INTEGER,
known_transaction_id TEXT
);
CREATE TABLE conflicts (
doc_id TEXT,
doc_rev TEXT,
content TEXT,
CONSTRAINT conflicts_pkey PRIMARY KEY (doc_id, doc_rev)
);
CREATE TABLE index_definitions (
name TEXT,
offset INT,
field TEXT,
CONSTRAINT index_definitions_pkey PRIMARY KEY (name, offset)
);
create index index_definitions_field on index_definitions(field);
CREATE TABLE u1db_config (
name TEXT PRIMARY KEY,
value TEXT
);
INSERT INTO u1db_config VALUES ('sql_schema', '0');
u1db-qt-0.1.7/src/document.cpp 0000664 0000000 0000000 00000015215 14367477523 0016133 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include "document.h"
#include "private.h"
QT_BEGIN_NAMESPACE_U1DB
/*!
\class Document
\inmodule U1db
\ingroup cpp
\brief The Document class proxies a single document stored in the Database.
*/
/*!
\qmltype Document
\instantiates Document
\inqmlmodule U1db 1.0
\ingroup modules
\brief Document proxies a single document stored in the Database.
This is the declarative API equivalent of Database::putDoc() and
Database::getDoc().
\qml
Document {
docId: 'myId'
defaults: {
color: 'blue'
}
create: true
}
\endqml
\sa Database
*/
/*!
Instantiate a new Document with an optional \a parent,
usually by declaring it as a QML item.
*/
Document::Document(QObject *parent) :
QObject(parent), m_database(0), m_create(false)
{
}
/*!
Returns the \l Database.
*/
Database*
Document::getDatabase()
{
return m_database;
}
void
Document::onDocChanged(const QString& docId, QVariant content)
{
if (docId == m_docId)
{
m_contents = m_database->getDocUnchecked(m_docId);
Q_EMIT contentsChanged(m_contents);
}
}
void
Document::onPathChanged(const QString& path)
{
if (!m_docId.isEmpty())
{
if (m_create && m_defaults.isValid())
{
// Make sure we create defaults on new path
m_create = false;
setCreate(true);
}
if (m_contents.isValid() && m_database && !m_docId.isEmpty())
{
if (!m_database->getDocUnchecked(m_docId).isValid())
{
// Put current contents on new database
m_database->putDoc(m_contents, m_docId);
}
}
m_contents = m_database->getDocUnchecked(m_docId);
Q_EMIT contentsChanged(m_contents);
}
}
/*!
The \a database is used to lookup the contents of the document, reflecting
changes done to it and conversely changes are saved to the database.
*/
void
Document::setDatabase(Database* database)
{
if (m_database == database)
return;
if (m_database)
QObject::disconnect(m_database, 0, this, 0);
m_database = database;
if (m_database)
{
if (!m_docId.isEmpty())
{
m_contents = m_database->getDocUnchecked(m_docId);
Q_EMIT contentsChanged(m_contents);
}
QObject::connect(m_database, &Database::pathChanged, this, &Document::onPathChanged);
QObject::connect(m_database, &Database::docChanged, this, &Document::onDocChanged);
}
Q_EMIT databaseChanged(database);
}
/*!
Returns the docId.
*/
QString
Document::getDocId()
{
return m_docId;
}
/*!
\qmlproperty string Document::docId
The docId can be that of an existing document in the database and
will determine what getContents() returns.
If no such documents exists, setDefaults() can be used to supply a preset.
*/
/*!
The \a docId can be that of an existing document in the database and
will determine what getContents() returns.
If no such documents exists, setDefaults() can be used to supply a preset.
*/
void
Document::setDocId(const QString& docId)
{
if (m_docId == docId)
return;
m_docId = docId;
Q_EMIT docIdChanged(docId);
if (m_database)
{
m_contents = m_database->getDocUnchecked(docId);
Q_EMIT contentsChanged(m_contents);
}
}
/*!
Returns whether the document will be newly created if it doesn't exist.
*/
bool
Document::getCreate()
{
return m_create;
}
/*!
\qmlproperty bool Document::create
If \a create is true, docId is not empty and no document with the same docId
exists, defaults will be used to store the document.
*/
/*!
If \a create is true, docId is not empty and no document with the same docId
exists, defaults will be used to store the document.
*/
void
Document::setCreate(bool create)
{
if (m_create == create)
return;
m_create = create;
Q_EMIT createChanged(create);
if (m_create && m_database && m_defaults.isValid() && !m_database->getDocUnchecked(m_docId).isValid())
m_database->putDoc(m_defaults, m_docId);
}
/*!
Returns the defaults to be used when the document is newly created
because it doesn't exist, if create is true.
*/
QVariant
Document::getDefaults()
{
return m_defaults;
}
/*!
\qmlproperty Variant Document::content
The default contents of the document, which are used only if
create is true, docId is not empty and no document with the same
docId exists in the database yet.
If the \a defaults change, it's up to the API user to handle it.
*/
/*!
The default contents of the document, which are used only if
create is true, docId is not empty and no document with the same
docId exists in the database yet.
If the \a defaults change, it's up to the API user to handle it.
*/
void
Document::setDefaults(QVariant defaults)
{
if (defaults.canConvert())
defaults = defaults.value();
if (m_defaults == defaults)
return;
m_defaults = defaults;
Q_EMIT defaultsChanged(defaults);
if (m_create && m_database && m_defaults.isValid() && !m_database->getDocUnchecked(m_docId).isValid())
m_database->putDoc(m_defaults, m_docId);
}
/*!
Returns the current contents of the document.
*/
QVariant
Document::getContents()
{
return m_contents;
}
/*!
\qmlproperty Variant Document::contents
Updates the \a contents of the document. A valid docId must be set.
*/
/*!
Updates the \a contents of the document. A valid docId must be set.
*/
void
Document::setContents(QVariant contents)
{
if (contents.canConvert())
contents = contents.value();
if (m_contents == contents)
return;
m_contents = contents;
Q_EMIT contentsChanged(contents);
if (m_database && !m_docId.isEmpty())
m_database->putDoc(m_contents, m_docId);
}
QT_END_NAMESPACE_U1DB
#include "moc_document.cpp"
u1db-qt-0.1.7/src/document.h 0000664 0000000 0000000 00000005337 14367477523 0015604 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_DOCUMENT_H
#define U1DB_DOCUMENT_H
#include
#include
#include "database.h"
QT_BEGIN_NAMESPACE_U1DB
class Q_DECL_EXPORT Document : public QObject {
Q_OBJECT
#ifdef Q_QDOC
/*! database */
Q_PROPERTY(Database* database READ getDatabase WRITE setDatabase NOTIFY databaseChanged)
#else
Q_PROPERTY(QT_PREPEND_NAMESPACE_U1DB(Database*) database READ getDatabase WRITE setDatabase NOTIFY databaseChanged)
#endif
/*! docId */
Q_PROPERTY(QString docId READ getDocId WRITE setDocId NOTIFY docIdChanged)
/*! create */
Q_PROPERTY(bool create READ getCreate WRITE setCreate NOTIFY createChanged)
/*! defaults */
Q_PROPERTY(QVariant defaults READ getDefaults WRITE setDefaults NOTIFY defaultsChanged)
/*! contents */
Q_PROPERTY(QVariant contents READ getContents WRITE setContents NOTIFY contentsChanged)
public:
Document(QObject* parent = 0);
Database* getDatabase();
void setDatabase(Database* database);
QString getDocId();
void setDocId(const QString& docId);
bool getCreate();
void setCreate(bool create);
QVariant getDefaults();
void setDefaults(QVariant defaults);
QVariant getContents();
void setContents(QVariant contents);
Q_SIGNALS:
/*!
The database changed.
*/
void databaseChanged(Database* database);
/*!
The docId changed.
*/
void docIdChanged(const QString& docId);
/*!
The create flag changed.
*/
void createChanged(bool create);
/*!
The default contents changed.
*/
void defaultsChanged(QVariant defaults);
/*!
The current contents of the document changed.
*/
void contentsChanged(QVariant contents);
private:
Q_DISABLE_COPY(Document)
Database* m_database;
QString m_docId;
bool m_create;
QVariant m_defaults;
QVariant m_contents;
void onDocChanged(const QString& docID, QVariant content);
void onPathChanged(const QString& path);
};
QT_END_NAMESPACE_U1DB
#endif // U1DB_DOCUMENT_H
u1db-qt-0.1.7/src/global.h 0000664 0000000 0000000 00000003251 14367477523 0015217 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_GLOBAL_H
#define U1DB_GLOBAL_H
#ifndef QT_STATIC
# if defined(QT_BUILD_U1DB_LIB)
# define Q_U1DB_EXPORT Q_DECL_EXPORT
# else
# define Q_U1DB_EXPORT Q_DECL_IMPORT
# endif
#else
# define Q_U1DB_EXPORT
#endif
#if defined(QT_NAMESPACE)
# define QT_BEGIN_NAMESPACE_U1DB namespace QT_NAMESPACE { namespace U1db {
# define QT_END_NAMESPACE_U1DB } }
# define QT_USE_NAMESPACE_U1DB using namespace QT_NAMESPACE::U1db;
# define QT_PREPEND_NAMESPACE_U1DB(name) QT_NAMESPACE::U1db::name
#else
# define QT_BEGIN_NAMESPACE_U1DB namespace U1db {
# define QT_END_NAMESPACE_U1DB }
# define QT_USE_NAMESPACE_U1DB using namespace U1db;
# define QT_PREPEND_NAMESPACE_U1DB(name) U1db::name
#endif
// a workaround for moc - if there is a header file that doesn't use u1db
// namespace, we still force moc to do "using namespace" but the namespace have to
// be defined, so let's define an empty namespace here
QT_BEGIN_NAMESPACE_U1DB
QT_END_NAMESPACE_U1DB
#endif // U1DB_GLOBAL_H
u1db-qt-0.1.7/src/index.cpp 0000664 0000000 0000000 00000020015 14367477523 0015416 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include "index.h"
#include "private.h"
QT_BEGIN_NAMESPACE_U1DB
/*!
\class Index
\inmodule U1db
\ingroup cpp
\brief The Index class defines an index to be stored in the database and
queried using Query. Changes in documents affected by the index also update
the index in the database.
*/
/*!
\qmltype Index
\instantiates Index
\inqmlmodule U1db 1.0
\ingroup modules
\brief An Index defines what fields can be filtered using Query.
Documents in the database will be included if they contain all fields in the expression.
\qml
Index {
database: myDatabase
name: 'colorIndex'
expression: [ 'color' ]
}
\endqml
\sa Query
*/
/*!
Instantiate a new Index with an optional \a parent,
usually by declaring it as a QML item.
*/
Index::Index(QObject *parent) :
QObject(parent), m_database(0)
{
}
/*!
Returns the \l Database to lookup documents from and store the index in.
*/
Database*
Index::getDatabase()
{
return m_database;
}
void
Index::onPathChanged(const QString& path)
{
m_database->putIndex(m_name, m_expression);
Q_EMIT dataInvalidated();
}
void
Index::onDocChanged(const QString& docId, QVariant content)
{
Q_EMIT dataInvalidated();
}
/*!
\qmlproperty Database Index::database
Sets the Database to lookup documents from and store the index in. The
dataInvalidated() signal will be emitted on all changes that could affect
the index.
*/
/*!
Sets the \a database to lookup documents from and store the index in. The
dataInvalidated() signal will be emitted on all changes that could affect
the index.
*/
void
Index::setDatabase(Database* database)
{
if (m_database == database)
return;
if (m_database)
QObject::disconnect(m_database, 0, this, 0);
m_database = database;
Q_EMIT databaseChanged(database);
if (m_database)
{
m_database->putIndex(m_name, m_expression);
QObject::connect(m_database, &Database::pathChanged, this, &Index::onPathChanged);
QObject::connect(m_database, &Database::docChanged, this, &Index::onDocChanged);
Q_EMIT dataInvalidated();
}
}
/*!
Returns the name of the index. Both name and expression must be specified.
*/
QString
Index::getName()
{
return m_name;
}
/*!
\qmlproperty string Index::name
Sets the name used. Both an expression and a name must be specified
for an index to be created.
*/
/*!
Sets the \a name used. Both an expression and a name must be specified
for an index to be created.
*/
void
Index::setName(const QString& name)
{
if (m_name == name)
return;
if (m_database)
{
m_database->putIndex(name, m_expression);
Q_EMIT dataInvalidated();
}
m_name = name;
Q_EMIT nameChanged(name);
}
/*!
Returns the expression of the index. Both name and expression must be specified.
*/
QStringList
Index::getExpression()
{
return m_expression;
}
/*!
\qmlproperty list Index::expression
Sets the expression used. Both an expression and a name must be specified
for an index to be created.
Also starts the process of creating the Index result list, which can then be queried or populate the Query model as is.
*/
/*!
Sets the \a expression used. Both an expression and a name must be specified
for an index to be created.
Also starts the process of creating the Index result list, which can then be queried or populate the Query model as is.
*/
void
Index::setExpression(QStringList expression)
{
if (m_expression == expression)
return;
m_expression = expression;
if (m_database)
{
m_database->putIndex(m_name, m_expression);
Q_EMIT dataInvalidated();
}
Q_EMIT expressionChanged(expression);
}
/*!
\internal
* Iterates through the documents stored in the database and creates the list of results based on the Index expressions.
*/
void Index::generateIndexResults()
{
m_results.clear();
Database *db(getDatabase());
if(db){
QList documents = db->listDocs();
Q_FOREACH (QString docId, documents){
QVariant document = db->getDocUnchecked(docId);
QStringList fieldsList;
appendResultsFromMap(docId, fieldsList, document.toMap(),"");
}
}
}
/*!
\internal
*/
QList Index::getAllResults(){
generateIndexResults();
return m_results;
}
/*!
\internal
*
*This method is desinged to recursively iterate through a document, or section of a document, which represents a QVariantMap. As it iterates through the entire document, the method keeps track of the current index expression, and populates a local QVariantMap should the current expression be found in the Index's list of expressions.
*
*If that QVariantMap contains more than one entry it is added to the global results, which can then be utilized by a Query. This needs to be modified to ensure all expressions are found, whereas at the moment if more than one expressions are defined and any of them are found then the map is added to the results list.
*
*/
QStringList Index::appendResultsFromMap(QString docId, QStringList fieldsList, QVariantMap current_section, QString current_field)
{
QMapIterator i(current_section);
QString original_field = current_field;
QVariantMap results_map;
while (i.hasNext()) {
i.next();
if(!original_field.isEmpty()){
current_field = original_field + "." + i.key();
}
else{
current_field = i.key();
}
fieldsList.append(current_field);
QVariant value = i.value();
if(value.userType()==8) // QVariantMap
{
fieldsList = appendResultsFromMap(docId, fieldsList, value.toMap(),current_field);
}
else if(value.userType()==9) // QVariantList
{
fieldsList = getFieldsFromList(docId, fieldsList, value.toList(),current_field);
}
{
if(m_expression.contains(current_field)==true){
results_map.insert(i.key(),value);
}
}
}
if(results_map.count()>0){
QVariantMap mapIdResult;
mapIdResult.insert("docId", docId);
mapIdResult.insert("result", results_map);
m_results.append(mapIdResult);
}
return fieldsList;
}
/*!
\internal
*
*This recursive method is used in conjuntion with Index::appendResultsFromMap, to aid in iterating through a document when an embedded list is found.
*
*/
QStringList Index::getFieldsFromList(QString docId, QStringList fieldsList, QVariantList current_section, QString current_field)
{
QListIterator i(current_section);
while (i.hasNext()) {
QVariant value = i.next();
if(value.userType()==8) // QVariantMap
{
fieldsList = appendResultsFromMap(docId, fieldsList, value.toMap(),current_field);
}
else if(value.userType()==9) // QVariantList
{
fieldsList = getFieldsFromList(docId, fieldsList, value.toList(),current_field);
}
else if(value.userType()==10) // QString
{
fieldsList.append(current_field);
}
else
{
}
}
return fieldsList;
}
QT_END_NAMESPACE_U1DB
#include "moc_index.cpp"
u1db-qt-0.1.7/src/index.h 0000664 0000000 0000000 00000005210 14367477523 0015063 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_INDEX_H
#define U1DB_INDEX_H
#include
#include
#include "database.h"
QT_BEGIN_NAMESPACE_U1DB
class Q_DECL_EXPORT Index : public QObject {
Q_OBJECT
#ifdef Q_QDOC
/*! database */
Q_PROPERTY(Database* database READ getDatabase WRITE setDatabase NOTIFY databaseChanged)
#else
Q_PROPERTY(QT_PREPEND_NAMESPACE_U1DB(Database*) database READ getDatabase WRITE setDatabase NOTIFY databaseChanged)
#endif
/*! name */
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
/*! expression */
Q_PROPERTY(QStringList expression READ getExpression WRITE setExpression NOTIFY expressionChanged)
public:
Index(QObject* parent = 0);
Database* getDatabase();
void setDatabase(Database* database);
QString getName();
void setName(const QString& name);
QStringList getExpression();
void setExpression(QStringList expression);
QList getAllResults();
Q_SIGNALS:
/*!
The database changed.
*/
void databaseChanged(Database* database);
/*!
The index name changed.
*/
void nameChanged(const QString& name);
/*!
The index expression changed.
*/
void expressionChanged(QVariant expression);
/*!
The database, an indexed document or the expressions changed.
*/
void dataInvalidated();
private:
Q_DISABLE_COPY(Index)
Database* m_database;
QString m_name;
QStringList m_expression;
QList m_results;
void onPathChanged(const QString& path);
void onDocChanged(const QString& docId, QVariant content);
QStringList appendResultsFromMap(QString docId, QStringList fieldsList, QVariantMap current_section, QString current_field);
QStringList getFieldsFromList(QString docId, QStringList fieldsList, QVariantList current_section, QString current_field);
void generateIndexResults();
};
QT_END_NAMESPACE_U1DB
#endif // U1DB_INDEX_H
u1db-qt-0.1.7/src/private.h 0000664 0000000 0000000 00000001317 14367477523 0015432 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
u1db-qt-0.1.7/src/query.cpp 0000664 0000000 0000000 00000021143 14367477523 0015457 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include "query.h"
#include "database.h"
#include "private.h"
QT_BEGIN_NAMESPACE_U1DB
/*!
\class Query
\inmodule U1db
\ingroup cpp
\brief The Query class generates a filtered list of documents based on a query using the given Index.
Query can be used as a QAbstractListModel, delegates will then have access to \a docId and \a contents
analogous to the properties of Document.
*/
/*!
\qmltype Query
\instantiates Query
\inqmlmodule U1db 1.0
\ingroup modules
\brief Query filters documents based on the query and index.
In a ListView the Query can be used as a model.
\qml
ListView {
model: Query {
index: Index {
name: 'colorIndex'
expression: [ 'color' ]
database: myDatabase
}
query: [ 'blue' ]
}
delegate: ListItem.Subtitled {
text: docId
subText: contents.color
}
}
\endqml
\sa Index
*/
/*!
Instantiate a new Query with an optional \a parent,
usually by declaring it as a QML item.
*/
Query::Query(QObject *parent) :
QAbstractListModel(parent), m_index(0)
{
}
/*!
\internal
*Used to implement QAbstractListModel
*Implements the variables exposed to the Delegate in a model
*/
QVariant
Query::data(const QModelIndex & index, int role) const
{
if (role == 0) // contents
return m_results.at(index.row());
if (role == 1) // docId
return m_documents.at(index.row());
return QVariant();
}
/*!
\internal
Used to implement QAbstractListModel
Defines \b{contents} and \b{docId} as variables exposed to the Delegate in a model
\b{index} is supported out of the box.
*/
QHash
Query::roleNames() const
{
QHash roles;
roles.insert(0, "contents");
roles.insert(1, "docId");
return roles;
}
/*!
\internal
Used to implement QAbstractListModel
The number of rows: the number of documents given by the query.
*/
int
Query::rowCount(const QModelIndex & parent) const
{
return m_results.count();
}
/*!
FIXME
*/
Index*
Query::getIndex()
{
return m_index;
}
/*!
Emitted whenever the index or documents change, and the results
need to be updated.
*/
void
Query::onDataInvalidated()
{
m_documents.clear();
m_results.clear();
if (!m_index)
return;
generateQueryResults();
}
/*!
\internal
Manually triggers reloading of the query.
*/
void Query::generateQueryResults()
{
QList results(m_index->getAllResults());
/* Convert "*" or 123 or "aa" into a list */
/* Also convert ["aa", 123] into [{foo:"aa", bar:123}] */
QVariantList queryList(m_query.toList());
if (queryList.empty()) {
// * is the default if query is empty
if (!m_query.isValid())
queryList.append(QVariant(QString("*")));
else
queryList.append(m_query);
}
if (queryList.at(0).type() != QVariant::Map) {
QVariantList oldQueryList(queryList);
QListIterator j(oldQueryList);
QListIterator k(m_index->getExpression());
while(j.hasNext() && k.hasNext()) {
QVariant j_value = j.next();
QString k_value = k.next();
QVariantMap valueMap;
// Strip hierarchical components
if (k_value.contains("."))
valueMap.insert(k_value.split(".").last(), j_value);
else
valueMap.insert(k_value, j_value);
queryList.append(QVariant(valueMap));
}
}
Q_FOREACH (QVariantMap mapIdResult, results) {
QString docId((mapIdResult["docId"]).toString());
QVariant result_variant(mapIdResult["result"]);
QVariantMap result(result_variant.toMap());
QMapIterator j(result);
bool match = true;
while(j.hasNext()){
j.next();
if (!iterateQueryList(queryList, j.key(), j.value())) {
match = false;
break;
}
}
if(match == true){
// Results must be unique and not empty aka deleted
if (result_variant.isValid())
{
if (!m_documents.contains(docId))
m_documents.append(docId);
m_results.append(result);
}
}
}
resetModel();
Q_EMIT documentsChanged(m_documents);
Q_EMIT resultsChanged(m_results);
}
/*!
* \brief Query::resetModel
*
* Resets the model of the Query
*
*/
void Query::resetModel(){
beginResetModel();
endResetModel();
}
/*!
\internal
Loop through the query assuming it's a list.
For example:
queryList: { type: 'show' }
field: 'type'
value: 'show'
*/
bool Query::iterateQueryList(QVariantList queryList, QString field, QVariant value)
{
QListIterator j(queryList);
while (j.hasNext()) {
QVariant j_value = j.next();
QVariantMap valueMap(j_value.toMap());
if (!queryMap(valueMap, value.toString(), field))
return false;
}
return true;
}
/*!
\internal
Verify that query is an identical or wild card match.
*/
bool Query::queryMatchesValue(QString query, QString value)
{
if (query == "*")
return true;
if (query == value)
return true;
if (!query.contains ("*"))
return false;
QString prefix(query.split("*")[0]);
return value.startsWith(prefix, Qt::CaseSensitive);
}
/*!
\internal
Handle different types of string values including wildcards.
*/
bool Query::queryString(QString query, QVariant value)
{
QString typeName = value.typeName();
if (typeName == "QVariantList") {
Q_FOREACH (QVariant value_string, value.toList()) {
if (queryString(query, value_string.toString()))
return true;
}
return false;
}
return queryMatchesValue(query, value.toString());
}
/*!
\internal
Loop through the given map of keys and queries.
For example:
map: { type: 'show' }
value: { 'show' }
field: 'type'
*/
bool Query::queryMap(QVariantMap map, QString value, QString field)
{
QMapIterator k(map);
while(k.hasNext()){
k.next();
QString k_key = k.key();
QVariant k_variant = k.value();
QString query = k_variant.toString();
if(field == k_key){
if (!queryMatchesValue(query, value))
return false;
}
}
return true;
}
/*!
\qmlproperty Index Query::index
Sets the Index to use. \a index must have a valid name and index expressions.
If no query is set, the default is all results of the index.
*/
/*!
FIXME \a index
*/
void
Query::setIndex(Index* index)
{
if (m_index == index)
return;
if (m_index)
QObject::disconnect(m_index, 0, this, 0);
m_index = index;
if (m_index){
QObject::connect(m_index, &Index::dataInvalidated, this, &Query::onDataInvalidated);
}
Q_EMIT indexChanged(index);
onDataInvalidated();
}
/*!
FIXME
*/
QVariant
Query::getQuery()
{
return m_query;
}
/*!
\qmlproperty Variant Query::query
A query in one of the allowed forms:
'value', ['value'] or [{'sub-field': 'value'}].
The default is equivalent to '*'.
*/
/*!
FIXME \a query
*/
void
Query::setQuery(QVariant query)
{
if (m_query == query)
return;
m_query = query;
Q_EMIT queryChanged(query);
onDataInvalidated();
}
/*!
\qmlproperty list Query::documents
The docId's of all matched documents.
*/
/*!
FIXME
*/
QStringList
Query::getDocuments()
{
return m_documents;
}
/*!
\qmlproperty list Query::results
The results of the query as a list.
*/
/*!
FIXME
*/
QList
Query::getResults()
{
return m_results;
}
QT_END_NAMESPACE_U1DB
#include "moc_query.cpp"
u1db-qt-0.1.7/src/query.h 0000664 0000000 0000000 00000005530 14367477523 0015126 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_QUERY_H
#define U1DB_QUERY_H
#include
#include
#include "index.h"
QT_BEGIN_NAMESPACE_U1DB
class Q_DECL_EXPORT Query : public QAbstractListModel {
Q_OBJECT
#ifdef Q_QDOC
/*! index */
Q_PROPERTY(Index* index READ getIndex WRITE setIndex NOTIFY indexChanged)
#else
Q_PROPERTY(QT_PREPEND_NAMESPACE_U1DB(Index*) index READ getIndex WRITE setIndex NOTIFY indexChanged)
#endif
/*! query */
Q_PROPERTY(QVariant query READ getQuery WRITE setQuery NOTIFY queryChanged)
/*! documents */
Q_PROPERTY(QStringList documents READ getDocuments NOTIFY documentsChanged)
/*! results */
Q_PROPERTY(QList results READ getResults NOTIFY resultsChanged)
public:
Query(QObject* parent = 0);
// QAbstractListModel
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
QHashroleNames() const;
int rowCount(const QModelIndex & parent = QModelIndex()) const;
Index* getIndex();
void setIndex(Index* index);
QVariant getQuery();
void setQuery(QVariant query);
QStringList getDocuments();
QList getResults();
void resetModel();
Q_SIGNALS:
/*!
The associated index changed.
*/
void indexChanged(Index* index);
/*!
The query changed.
*/
void queryChanged(QVariant query);
/*!
The documents matching the query changed.
*/
void documentsChanged(QStringList documents);
/*!
The results matching the query changed.
*/
void resultsChanged(QList results);
private:
Q_DISABLE_COPY(Query)
Index* m_index;
QStringList m_documents;
QList m_results;
QVariant m_query;
void onDataInvalidated();
bool debug();
void generateQueryResults();
bool iterateQueryList(QVariantList list, QString field, QVariant value);
bool queryMatchesValue(QString query, QString value);
bool queryString(QString query, QVariant value);
bool queryMap(QVariantMap map, QString value, QString field);
bool queryField(QString field, QVariant value);
};
QT_END_NAMESPACE_U1DB
#endif // U1DB_QUERY_H
u1db-qt-0.1.7/src/sql.qrc 0000664 0000000 0000000 00000000165 14367477523 0015115 0 ustar 00root root 0000000 0000000 dbschema.sql
u1db-qt-0.1.7/src/synchronizer.cpp 0000664 0000000 0000000 00000112160 14367477523 0017047 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "synchronizer.h"
#include "private.h"
QT_BEGIN_NAMESPACE_U1DB
/*!
\class Synchronizer
\inmodule U1Db
\ingroup cpp
\brief The Synchronizer class handles synchronizing between two databases.
*/
/*!
\qmltype Synchronizer
\instantiates Synchronizer
\inqmlmodule U1db 1.0
\ingroup modules
\brief Synchronizer handles synchronizing between two databases.
\qml
Synchronizer {
id: mySync
synchronize: false
source: myDatabase
targets: [ {
remote: true,
ip: "127.0.0.1",
port: 7777,
name: "example1.u1db",
resolve_to_source: true
} ]
}
\endqml
*/
/*
Below this line are general methods for this class, such as setting/getting values for various properties.
*/
/*!
Create a new Synchronizer element, with an optional \a parent, usually by declaring it as a QML item.
Synchronizer elements sync two databases together, a 'source' database and a remote or local 'target' database.
Short description of properties:
id: The element's identification.
bool synchronize: Is the element actively synching or not. Should be set to false.
U1DB::Database source: The id of a local database that will be used for synchronization.
QVariant targets: One or more target databases that will be synched with the local database.
bool targets.remote: Is the target database a remote or local database.
QString targets.ip: The ip address of a remote database (if applicable).
int targets.port: Port number of the remote server.
QString targets.name: The name of the database.
bool targets.resolve_to_source: In case of conflict should the sync resolve to the source's data (if true).
Example use with u1db-serve:
1. In a terminal cd into a directory where the u1db Python reference implemented has been downloaded from lp:u1db.
2. Using Python create a database called 'example1.u1db' using u1db, and a document 'helloworld':
# python
>>> import u1db
>>> db = u1db.open("example1.u1db",create=True)
>>> content = {"hello": { "world": { "message":"Hello World Updated" } } }
>>> db.create_doc(content, doc_id="helloworld")
ctrl+d
3. From the u1db directory above type './u1db-serve --port=7777' and hit enter.
4. Open another terminal tab.
5. Change into a directory containing u1db-qt (assuming this class is included in that directory and the installed version on the host computer).
6. Change into the directory where u1db-qt-example-6.qml is located.
7. Type 'qmlscene u1db-qt-example-6.qml' and hit enter.
8. Click the button labelled 'Sync'.
9. Check the terminal windows for output from either the client or server.
*/
Synchronizer::Synchronizer(QObject *parent) :
QAbstractListModel(parent), m_synchronize(false), m_source(NULL)
{
QObject::connect(this, &Synchronizer::syncChanged, this, &Synchronizer::onSyncChanged);
}
/*!
\internal
*Used to implement QAbstractListModel
*Implements the variables exposed to the Delegate in a model
*/
QVariant
Synchronizer::data(const QModelIndex & index, int role) const
{
if (role == 0)
return m_sync_output.at(index.row());
return QVariant();
}
/*!
\internal
Used to implement QAbstractListModel
The number of rows: the number of documents given by the query.
*/
int
Synchronizer::rowCount(const QModelIndex & parent) const
{
return m_sync_output.count();
}
/*!
\internal
Used to implement QAbstractListModel
*/
QHash
Synchronizer::roleNames() const
{
QHash roles;
roles.insert(0, "sync_output");
return roles;
}
/*!
Sets the \a source database.
*/
void Synchronizer::setSource(Database* source)
{
if (m_source == source)
return;
if (m_source)
QObject::disconnect(m_source, 0, this, 0);
m_source = source;
Q_EMIT sourceChanged(source);
}
/*!
* \qmlproperty Variant Synchronizer::targets
* \preliminary
*
* Sets meta-data for databases to be used during a synchronization session.
*
* The QVariant is a list that can contain definitions for more than one database
* to be used as a target. For example:
*
* \code
* targets: [{remote:true},
* {remote:true,
* ip:"127.0.0.1",
* port: 7777,
* name:"example1.u1db",
* resolve_to_source:true},
* {remote:"OK"}]
* \endcode
*
* The above example defines three databases. Two of the three definitions in the
* example are invalid, the first ({remote:true}) and the third ({remote:"OK"}),
* because they are incomplete.
*
* The second definition is a fully defined and valid definition for a local to
* remote synchronization of two databases:
*
* \code
* {remote:true,
* ip:"127.0.0.1",
* port: 7777,
* name:"example1.u1db",
* resolve_to_source:true}
* \endcode
*
* 'remote' determines whether the database is on disk or located on a server.
* 'ip' and 'port' for a server are used only when 'remote' is set to true
* 'name' is the name of the local (on disk) or remote database.
* Note: If 'remote' is false this is the relative/absolute file location.
* 'resolve_to_source' determines whether to resolve conflicts automatically
* in favor of the source (aka local) database's values or the target's.
*/
/*!
* FIXME \a targets
*/
void Synchronizer::setTargets(QVariant targets)
{
if (m_targets == targets)
return;
//if (m_targets)
// QObject::disconnect(m_targets, 0, this, 0);
m_targets = targets;
Q_EMIT targetsChanged(targets);
}
/*!
* \qmlproperty bool Synchronizer::synchronize
* FIXME
*/
/*!
* FIXME \a synchronize
*/
void Synchronizer::setSync(bool synchronize)
{
if (m_synchronize == synchronize)
return;
m_synchronize = synchronize;
Q_EMIT syncChanged(synchronize);
}
/*!
* \qmlproperty bool Synchronizer::resolve_to_source
*
* If true, conflicts during sync will be resolved in favor of the content
* from the source database.
*/
/*!
* If \a resolve_to_source is true, conflicts during sync will be resolved in favor
* of the content from the source database.
*/
void Synchronizer::setResolveToSource(bool resolve_to_source)
{
if (m_resolve_to_source == resolve_to_source)
return;
m_resolve_to_source = resolve_to_source;
Q_EMIT resolveToSourceChanged(resolve_to_source);
}
/*!
* Sets the current value for the active session's \a sync_output.
*
*/
void Synchronizer::setSyncOutput(QList sync_output)
{
if (m_sync_output == sync_output)
return;
m_sync_output = sync_output;
Q_EMIT syncOutputChanged(sync_output);
}
/*!
* \qmlproperty Database Synchronizer::source
*
* Returns the source \l Database.
*/
/*!
Returns the source \l Database.
*/
Database* Synchronizer::getSource()
{
return m_source;
}
/*!
* Returns meta-data for all target databases.
*/
QVariant Synchronizer::getTargets()
{
return m_targets;
}
/*!
* Returns the current value of synchronize. If true then the synchronize
* session is initiated.
*
* This should probaby always be set to false on application start up.
* The application developer should use some trigger to switch it to true
* when needed (e.g. button click).
*/
bool Synchronizer::getSync()
{
return m_synchronize;
}
/*!
* Returns \b true if conflicts during sync will be resolved in favor of the content
* from the source database.
*/
bool Synchronizer::getResolveToSource(){
return m_resolve_to_source;
}
/*!
* \qmlproperty list Synchronizer::sync_output
*
* Returns the output from a sync session. The list should contain numerous
* QVariantMaps, each of which will have various meta-data with informative
* information about what happened in the background of the session.
*
* In some cases the information will be about errors or warnings, and in
* other cases simple log messages. Also included would noramlly be associated
* properties, elements and other data.
*
* The information can be used in any number of ways, such as on screen within an app,
* testing, console output, logs and more. This is designed to be flexible enough that
* the app developer can decide themselves how to best use the data.
*/
/*!
* FIXME
*/
QList Synchronizer::getSyncOutput(){
return m_sync_output;
}
/*
Below this line represents the class' more unique functionality.
In other words, methods that do more than simply modify/retrieve
an element's property values.
*/
/*!
* \brief Synchronizer::onSyncChanged
*
* The synchroization process begins here.
*/
void Synchronizer::onSyncChanged(bool synchronize){
Database* source = getSource();
QList sync_targets;
/*!
* The validator map contains key and value pair definitions,
*that are used to confirm that the values provided for each
*database target are of the expected type for a particular key.
*/
QMapvalidator;
validator.insert("remote","bool");
validator.insert("location","QString");
validator.insert("resolve_to_source","bool");
/*!
* The mandatory map contains the keys that are used to confirm
*that a database target definition contains all the mandatory keys
*necessary for synchronizing.
*/
QListmandatory;
mandatory.append("remote");
mandatory.append("resolve_to_source");
if(synchronize == true){
/*!
A list of valid sync target databases is generated by calling the getValidTargets(validator, mandatory) method, and adding the return value to a QList (sync_targets).
*/
sync_targets=getValidTargets(validator, mandatory);
/*!
* Once the list of sync targets has been generated the sync activity
*can be initiated via the synchronizeTargets function.
*/
synchronizeTargets(source, sync_targets);
/*!
* After the synchronization is complete the model is reset so that
*log and error messages are available at the application level.
*
*/
beginResetModel();
endResetModel();
/*!
The convenience signals syncOutputChanged and syncCompleted are
emitted after the model has been reset.
*/
Q_EMIT syncOutputChanged(m_sync_output);
Q_EMIT syncCompleted();
/*!
* The sync boolean value is reset to its default value (false)
*once all sync activity is complete.
*/
setSync(false);
}
else{
}
}
/*!
* \internal
* \brief Synchronizer::getValidTargets
*
* This method confirms that each sync target definition is valid, based
* on predefined criteria contained in the validator and mandatory lists.
*
*/
QList Synchronizer::getValidTargets(QMapvalidator, QListmandatory){
QList sync_targets;
int index = 0;
QList targets = getTargets().toList();
Q_FOREACH (QVariant target_variant, targets)
{
index++;
QString index_number = QString::number(index);
QMap target = target_variant.toMap();
bool valid = true;
bool complete = true;
QMapIterator i(target);
while (i.hasNext()) {
i.next();
if(validator.contains(i.key())&&validator[i.key()]!=i.value().typeName()){
valid = false;
QString message_value = "For property `" + i.key() + "` Expecting type `" + validator[i.key()] + "`, but received type `" + i.value().typeName()+"`";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",index_number);
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
target.insert("sync",false);
break;
}
if(valid==false){
targets.removeOne(target);
break;
}
else{
QListIterator j(mandatory);
while(j.hasNext()){
QString value = j.next();
if(!target.contains(value)){
QString message_value = "Expected property `" + value + "`, but it is not present.";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",index_number);
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
target.insert("sync",false);
targets.removeOne(target);
complete = false;
break;
}
}
if(complete==false){
break;
}
}
}
if(target.contains("sync")&&target["sync"]==false){
QString message_value = "Not synced due to errors with properties.";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",index_number);
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
}
else
{
target.insert("sync",true);
sync_targets.append(target);
QString message_value = "Mandatory properties were included and their values are valid.";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",index_number);
output_map.insert("message_type","no-errors");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
}
}
return sync_targets;
}
/*!
* \internal
* \brief Synchronizer::synchronizeTargets
*
* The source database is synchronized with the target databases contained
* in the 'targets' list. That list should only contain valid targets, as
* determined by Synchronizer::getValidTargets.
*
*/
void Synchronizer::synchronizeTargets(Database *source, QVariant targets){
if(targets.typeName()== QStringLiteral("QVariantList")){
QList target_list = targets.toList();
QListIterator i(target_list);
int target_index = -1;
while(i.hasNext()){
target_index++;
QVariant target = i.next();
if(target.typeName()== QStringLiteral("QVariantMap")){
QMap target_map = target.toMap();
if(target_map.contains("remote")&&target_map["remote"]==false){
if(target_map.contains("sync")&&target_map["sync"]==true){
QString message_value = "Valid local target.";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",target_index);
output_map.insert("message_type","no-errors");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
syncLocalToLocal(source, target_map);
}
}
else if(target_map.contains("remote")&&target_map["remote"]==true){
if(target_map.contains("sync")&&target_map["sync"]==true){
//ip
//port
//name
//GET /thedb/sync-from/my_replica_uid
QString source_uid = getUidFromLocalDb(source->getPath());
QString get_string = target_map["name"].toString()+"/sync-from/"+source_uid;
QString url_string = "http://"+target_map["ip"].toString();
QString full_get_request = url_string+"/"+get_string;
int port_number = target_map["port"].toInt();
QNetworkAccessManager *manager = new QNetworkAccessManager(source);
QUrl url(full_get_request);
url.setPort(port_number);
QNetworkRequest request(url);
connect(manager, &QNetworkAccessManager::finished, this, &Synchronizer::remoteGetSyncInfoFinished);
QString message_value = "Valid remote target.";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",target_index);
output_map.insert("message_type","no-errors");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
manager->get(QNetworkRequest(request));
}
}
else{
QString message_value = "Unknown error. Please check properties";
QVariantMap output_map;
output_map.insert("concerning_property","targets");
output_map.insert("concerning_index",target_index);
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
}
}
}
}
}
/*!
* \internal
* \brief Synchronizer::syncLocalToLocal
*
* This function synchronizes two local databases, a source database and a target database.
*
*/
void Synchronizer::syncLocalToLocal(Database *sourceDb, QMap target)
{
QString target_db_name = target["location"].toString();
Database *targetDb;
Index *targetIndex;
Query *targetQuery;
Index *sourceIndex;
Query *sourceQuery;
if(target.contains("id")){
targetDb = (Database*)target["id"].value();
} else if(target.contains("target_query")){
targetQuery = (Query*)target["target_query"].value();
targetIndex = targetQuery->getIndex();
targetDb = targetIndex->getDatabase();
} else
targetDb = NULL;
if(target.contains("source_query")){
sourceQuery = (Query*)target["source_query"].value();
sourceIndex = sourceQuery->getIndex();
sourceDb = sourceIndex->getDatabase();
}
if(sourceDb == NULL || targetDb == NULL){
QString message_value = "Either source or target does not exist or is not active.";
QVariantMap output_map;
output_map.insert("concerning_property","source|targets");
//output_map.insert("concerning_index",index_number); // no access to targets index?
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
return;
}
QMap lastSyncInformation;
lastSyncInformation.insert("target_replica_uid",getUidFromLocalDb(target_db_name));
lastSyncInformation.insert("target_replica_generation","");
lastSyncInformation.insert("target_replica_transaction_id",-1);
lastSyncInformation.insert("source_replica_uid",getUidFromLocalDb(sourceDb->getPath()));
lastSyncInformation.insert("source_replica_generation","");
lastSyncInformation.insert("source_replica_transaction_id",-1);
lastSyncInformation = getLastSyncInformation(sourceDb, targetDb, false, lastSyncInformation);
QList transactionsFromSource;
QList transactionsFromTarget;
// Check if target and source have ever been synced before
if(lastSyncInformation["target_replica_uid"].toString() != "" && lastSyncInformation["target_replica_generation"].toString() != "" && lastSyncInformation["target_replica_transaction_id"].toInt() != -1 && lastSyncInformation["source_replica_uid"].toString() != "" && lastSyncInformation["source_replica_generation"].toString() != "" && lastSyncInformation["source_replica_transaction_id"].toInt() != -1)
{
QString message_value = "Source and local database have previously synced.";
QVariantMap output_map;
output_map.insert("concerning_property","source|targets");
output_map.insert("concerning_source",sourceDb->getPath());
output_map.insert("concerning_target",target_db_name);
output_map.insert("message_type","no-errors");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
//Do some syncing
transactionsFromSource = sourceDb->listTransactionsSince(lastSyncInformation["source_replica_generation"].toInt());
transactionsFromTarget = targetDb->listTransactionsSince(lastSyncInformation["target_replica_generation"].toInt());
}
else{
QString message_value = "Source and local database have not previously synced.";
QVariantMap output_map;
output_map.insert("concerning_property","source|targets");
output_map.insert("concerning_source",sourceDb->getPath());
output_map.insert("concerning_target",target_db_name);
output_map.insert("message_type","no-errors");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
//There is a first time for everything, let's sync!
transactionsFromSource = sourceDb->listTransactionsSince(0);
transactionsFromTarget = targetDb->listTransactionsSince(0);
}
/*!
* With two distinct lists present, it is now possible to check what
* updates should be made, or new documents created in one or the other
* database, depending on conditions.
*
* However, two additional lists containing transactions IDs are required
* because the information is contained within delimited strings (see
* below for details).
*
*/
QList transactionIdsFromSource;
QList transactionIdsFromTarget;
Q_FOREACH(QString sourceTransaction, transactionsFromSource){
/*!
* Each sourceTransaction is a pipe delimited string containing
* generation number, document ID, and transaction ID details
* in that order.
*
* Splitting the string into its component pieces provides a
* document ID (the second key in the list).
*/
QStringList transactionDetails = sourceTransaction.split("|");
/*!
* It is only necessary to have unique instances of the
* document ID.
*/
if(!transactionIdsFromSource.contains(transactionDetails[1]))
transactionIdsFromSource.append(transactionDetails[1]);
}
Q_FOREACH(QString targetTransaction, transactionsFromTarget){
/*!
* Each targetTransaction is a pipe delimited string containing
* generation number, document ID, and transaction ID details
* in that order.
*
* Splitting the string into its component pieces provides a
* document ID (the second key in the list).
*/
QStringList transactionDetails = targetTransaction.split("|");
/*!
* It is only necessary to have unique instances of the
* document ID.
*/
if(!transactionIdsFromTarget.contains(transactionDetails[1]))
transactionIdsFromTarget.append(transactionDetails[1]);
}
/* The source replica asks the target replica for the information it has stored about the last time these two replicas were synchronised (if ever).*/
/*
The application wishing to synchronise sends the following GET request to the server:
GET /thedb/sync-from/my_replica_uid
Where thedb is the name of the database to be synchronised, and my_replica_uid is the replica id of the application’s (i.e. the local, or synchronisation source) database
*/
/*
The target responds with a JSON document that looks like this:
{
"target_replica_uid": "other_replica_uid",
"target_replica_generation": 12,
"target_replica_transaction_id": "T-sdkfj92292j",
"source_replica_uid": "my_replica_uid",
"source_replica_generation": 23,
"source_transaction_id": "T-39299sdsfla8"
}
With all the information it has stored for the most recent synchronisation between itself and this particular source replica. In this case it tells us that the synchronisation target believes that when it and the source were last synchronised, the target was at generation 12 and the source at generation 23.
*/
/* The source replica validates that its information regarding the last synchronisation is consistent with the target’s information, and raises an error if not. (This could happen for instance if one of the replicas was lost and restored from backup, or if a user inadvertently tries to synchronise a copied database.) */
/* The source replica generates a list of changes since the last change the target replica knows of. */
/* The source replica checks what the last change is it knows about on the target replica. */
/* If there have been no changes on either replica that the other side has not seen, the synchronisation stops here. */
/* The source replica sends the changed documents to the target, along with what the latest change is that it knows about on the target replica. */
/* The target processes the changed documents, and records the source replica’s latest change. */
/* The target responds with the documents that have changes that the source does not yet know about. */
/* The source processes the changed documents, and records the target replica’s latest change. */
/* If the source has seen no changes unrelated to the synchronisation during this whole process, it now sends the target what its latest change is, so that the next synchronisation does not have to consider changes that were the result of this one.*/
}
/*!
* \internal
* \brief Synchronizer::syncDocument
*
*
* This method is used to synchronize documents from one local database
* to another local database.
*
*/
QVariant Synchronizer::syncDocument(Database *from, Database *to, QString docId)
{
QVariant document = from->getDoc(docId);
to->putDoc(document, docId);
QString revision = from->getCurrentDocRevisionNumber(docId);
to->updateDocRevisionNumber(docId,revision);
return document;
}
/*!
* \internal
* \brief Synchronizer::getLastSyncInformation
*
*
* If the source and target database have ever been synced before the information
* from that previous session is returned. This is only used for local to local
* databases. The local to remote procedure is handled elsewhere in a different manner.
*
*/
QMap Synchronizer::getLastSyncInformation(Database *sourceDb, Database *targetDb, bool remote, QMap lastSyncInformation){
if(remote == true){
QString message_value = "Sync information from remote target not available at this time.";
QVariantMap output_map;
output_map.insert("concerning_property","source|targets");
output_map.insert("concerning_source",sourceDb->getPath());
output_map.insert("message_type","warning");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
return lastSyncInformation;
}
else{
lastSyncInformation["source_replica_uid"].toString();
lastSyncInformation = targetDb->getSyncLogInfo(lastSyncInformation, lastSyncInformation["source_replica_uid"].toString(),"target");
lastSyncInformation = sourceDb->getSyncLogInfo(lastSyncInformation, lastSyncInformation["target_replica_uid"].toString(),"source");
}
return lastSyncInformation;
}
/*!
* \internal
* \brief Synchronizer::getUidFromLocalDb
*
*
* The unique id of a database is needed in certain situations of a
* synchronize session. This method retrieves that id from a local database.
*
*/
QString Synchronizer::getUidFromLocalDb(QString dbFileName)
{
QString dbUid;
QSqlDatabase db;
db = QSqlDatabase::addDatabase("QSQLITE",QUuid::createUuid().toString());
QFile db_file(dbFileName);
if(!db_file.exists())
{
QString message_value = "Database does not exist.";
QVariantMap output_map;
output_map.insert("concerning_property","source|targets");
output_map.insert("concerning_database",dbFileName);
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
return dbUid;
}
else
{
db.setDatabaseName(dbFileName);
if (!db.open()){
QString message_value = db.lastError().text();
QVariantMap output_map;
output_map.insert("concerning_property","source|targets");
output_map.insert("concerning_database",dbFileName);
output_map.insert("message_type","error");
output_map.insert("message_value",message_value);
m_sync_output.append(output_map);
}
else{
QSqlQuery query (db.exec("SELECT value FROM u1db_config WHERE name = 'replica_uid'"));
if(!query.lastError().isValid() && query.next()){
dbUid = query.value(0).toString();
db.close();
dbUid = dbUid.replace("{","");
dbUid = dbUid.replace("}","");
return dbUid;
}
else{
qWarning("u1db: %s", qPrintable(query.lastError().text()));
db.close();
return dbUid;
}
}
}
return dbUid;
}
/*!
* \internal
* \brief Synchronizer::remoteGetSyncInfoFinished
*
* Once the initial exchange between the client application
* and the remote server is complete, this method retrieves
* necessary information from the reply that came from the
* server, and is required for posting data from the client
* in the steps that will follow.
*
* After the data is saved to a string and the network reply
* is closed, the appropriate method for posting
* (postDataFromClientToRemoteServer) is then called.
*
*/
void Synchronizer::remoteGetSyncInfoFinished(QNetworkReply* reply)
{
QNetworkAccessManager *manager = reply->manager();
Database *source = qobject_cast(manager->parent());
QUrl postUrl = reply->request().url();
QByteArray data = reply->readAll();
QString replyData = QString(data);
reply->close();
postDataFromClientToRemoteServer(source, postUrl, replyData);
}
/*!
* \internal
* \brief Synchronizer::postDataFromClientToRemoteServer
*
* This method builds a string for posting from the client
* application to the remote server, using information previously
* gathered from the source and target databases,
* and then initiates the post.
*
*/
void Synchronizer::postDataFromClientToRemoteServer(Database *source, QUrl postUrl, QString replyData)
{
QVariantMap replyMap;
QJsonDocument replyJson = QJsonDocument::fromJson(replyData.toUtf8());
QVariant replyVariant = replyJson.toVariant();
replyMap = replyVariant.toMap();
double source_replica_generation = replyMap["source_replica_generation"].toDouble();
QString source_replica_uid = replyMap["source_replica_uid"].toString();
QString source_replica_transaction_id = replyMap["source_transaction_id"].toString();
//double target_replica_generation = replyMap["target_replica_generation"].toDouble();
QString target_replica_transaction_id = replyMap["target_replica_transaction_id"].toString();
QString target_replica_uid = replyMap["target_replica_uid"].toString();
QNetworkAccessManager *manager = new QNetworkAccessManager(source);
connect(manager, &QNetworkAccessManager::finished, this, &Synchronizer::remotePostSyncInfoFinished);
QByteArray postString;
postString = "[\r\n";
postString.append("{\"last_known_generation\": ");
postString.append(QByteArray::number(source_replica_generation));
postString.append(", \"last_known_trans_id\": \"");
postString.append(source_replica_transaction_id.toUtf8());
postString.append("\"}");
QList transactions = m_source->listTransactionsSince(source_replica_generation);
Q_FOREACH(QString transaction,transactions){
QStringList transactionData = transaction.split("|");
QString content = source->getDocumentContents(transactionData[1]);
content = content.replace("\r\n","");
content = content.replace("\r","");
content = content.replace("\n","");
content = content.replace("\"","\\\"");
postString.append(QString(",\r\n{\"content\": \""+content+"\",\"rev\": \""+m_source->getCurrentDocRevisionNumber(transactionData[1])+"\", \"id\": \""+transactionData[1]+"\",\"trans_id\": \""+transactionData[2]+"\",\"gen\": "+transactionData[0]+"}").toUtf8());
}
postString.append("\r\n]");
QByteArray postDataSize = QByteArray::number(postString.size());
QNetworkRequest request(postUrl);
request.setRawHeader("User-Agent", "U1Db-Qt v1.0");
request.setRawHeader("X-Custom-User-Agent", "U1Db-Qt v1.0");
request.setRawHeader("Content-Type", "application/x-u1db-sync-stream");
request.setRawHeader("Content-Length", postDataSize);
manager->post(QNetworkRequest(request),postString);
}
/*!
* \internal
* \brief Synchronizer::remotePostSyncInfoFinished
*
* This method is a slot, which is called once the data
* from the client application has been posted to the remote
* server.
*
* This is where any new data from the
* remote server is gathered, and then the further steps
* for processing on the client side are begun.
*/
void Synchronizer::remotePostSyncInfoFinished(QNetworkReply* reply)
{
QNetworkAccessManager *manager = reply->manager();
Database *source = qobject_cast(manager->parent());
QByteArray data = reply->readAll();
QString replyData = QString(data);
reply->close();
processDataFromRemoteServer(source, replyData);
}
/*!
* \internal
* \brief Synchronizer::processDataFromRemoteServer
*
* After the remote target database has replied back, the data it has sent
* is processed to determine what action to take on any relevant documents
* that may have been included in the data.
*
*/
void Synchronizer::processDataFromRemoteServer(Database *source, QString replyData)
{
replyData = replyData.replace("\r\n","");
QJsonDocument replyJson = QJsonDocument::fromJson(replyData.toUtf8());
QVariant replyVariant = replyJson.toVariant();
QVariantList replyList = replyVariant.toList();
QListIterator i(replyList);
int index = -1;
while(i.hasNext()){
index++;
QVariant current = i.next();
QString type_name = QString::fromUtf8(current.typeName());
if(type_name == "QVariantMap")
{
QVariantMap map = current.toMap();
if(index == 0)
{
// Meta data
}
else
{
// Document to update
QString id("");
QVariant content("");
QString rev("");
QMapIterator i(map);
while (i.hasNext()) {
i.next();
if(i.key()=="content")
{
content = i.value();
}
else if(i.key()=="id")
{
id = i.value().toString();
}
else if(i.key()=="rev")
{
rev = i.value().toString();
}
}
if(content!=""&&id!=""&&rev!="")
{
source->putDoc(content,id);
source->updateDocRevisionNumber(id,rev);
}
}
}
}
}
QT_END_NAMESPACE_U1DB
#include "moc_synchronizer.cpp"
u1db-qt-0.1.7/src/synchronizer.h 0000664 0000000 0000000 00000010036 14367477523 0016513 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Kevin Wright
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef U1DB_SYNCHRONIZER_H
#define U1DB_SYNCHRONIZER_H
#include
#include
#include
#include "database.h"
#include "index.h"
#include "query.h"
QT_BEGIN_NAMESPACE_U1DB
class Q_DECL_EXPORT Synchronizer : public QAbstractListModel {
Q_OBJECT
#ifdef Q_QDOC
/*! source */
Q_PROPERTY(Database* source READ getSource WRITE setSource NOTIFY sourceChanged)
#else
Q_PROPERTY(QT_PREPEND_NAMESPACE_U1DB(Database*) source READ getSource WRITE setSource NOTIFY sourceChanged)
#endif
/*! synchronize */
Q_PROPERTY(bool synchronize READ getSync WRITE setSync NOTIFY syncChanged)
/*! resolve_to_source */
Q_PROPERTY(bool resolve_to_source READ getResolveToSource WRITE setResolveToSource NOTIFY resolveToSourceChanged)
/*! targets */
Q_PROPERTY(QVariant targets READ getTargets WRITE setTargets NOTIFY targetsChanged)
/*! sync_output */
Q_PROPERTY(QList sync_output READ getSyncOutput NOTIFY syncOutputChanged)
public:
Synchronizer(QObject* parent = 0);
// QAbstractListModel
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
QHashroleNames() const;
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QList getValidTargets(QMapvalidator, QListmandatory);
QMap getLastSyncInformation(Database *sourceDb, Database *targetDb, bool remote, QMap lastSyncInformation);
Database* getSource();
QVariant getTargets();
bool getSync();
bool getResolveToSource();
QList getSyncOutput();
void setSource(Database* source);
void setTargets(QVariant targets);
void setSync(bool synchronize);
void setResolveToSource(bool resolve_to_source);
void setSyncOutput(QList sync_output);
void syncLocalToLocal(Database *sourceDb, QMap target);
void synchronizeTargets(Database *source, QVariant targets);
QVariant syncDocument(Database *from, Database *to, QString docId);
QString getUidFromLocalDb(QString dbFileName);
void postDataFromClientToRemoteServer(Database *source, QUrl postUrl, QString replyData);
void processDataFromRemoteServer(Database *source, QString replyData);
Q_SIGNALS:
/*!
* \brief sourceChanged
* \param source
*/
void sourceChanged(Database* source);
/*!
* \brief targetsChanged
* \param targets
*/
void targetsChanged(QVariant targets);
/*!
* \brief syncChanged
* \param synchronize
*/
void syncChanged(bool synchronize);
/*!
* \brief resolveToSourceChanged
* \param resolve_to_source
*/
void resolveToSourceChanged(bool resolve_to_source);
/*!
* \brief syncOutputChanged
* \param sync_output
*/
void syncOutputChanged(QList sync_output);
/*!
* \brief syncCompleted
*/
void syncCompleted();
private:
//Q_DISABLE_COPY(Synchronizer)
bool m_synchronize;
Database* m_source;
bool m_resolve_to_source;
QVariant m_targets;
QList m_sync_output;
void onSyncChanged(bool synchronize);
void remoteGetSyncInfoFinished(QNetworkReply* reply);
void remotePostSyncInfoFinished(QNetworkReply* reply);
};
QT_END_NAMESPACE_U1DB
#endif // U1DB_SYNCHRONIZER_H
u1db-qt-0.1.7/tests/ 0000775 0000000 0000000 00000000000 14367477523 0014160 5 ustar 00root root 0000000 0000000 u1db-qt-0.1.7/tests/CMakeLists.txt 0000664 0000000 0000000 00000003666 14367477523 0016733 0 ustar 00root root 0000000 0000000 add_custom_target(check COMMAND "env" "CTEST_OUTPUT_ON_FAILURE=1" "${CMAKE_CTEST_COMMAND}")
find_package(Qt5Test REQUIRED)
add_test(NAME plugintest COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/strict-qmltestrunner.sh" "-import" "../modules" "-o" "plugintest-xunit.xml,xunitxml" "-o" "-,txt" "-input" "${CMAKE_CURRENT_SOURCE_DIR}")
set_property(TEST plugintest PROPERTY ENVIRONMENT "XDG_DATA_HOME=/tmp/plugintest")
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${Qt5Test_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src
${Qt5Sql_INCLUDE_DIRS}
${Qt5Quick_INCLUDE_DIRS}
)
add_executable(test-database test-database.cpp)
target_link_libraries(test-database
${Qt5Test_LIBRARIES}
${Qt5Quick_LIBRARIES}
${Qt5Sql_LIBRARIES}
${U1DB_QT_LIBNAME}
)
set_target_properties(test-database PROPERTIES COMPILE_FLAGS -fPIC)
add_test(NAME test-database COMMAND "dbus-test-runner" "--task" "${CMAKE_CURRENT_BINARY_DIR}/test-database" "-p" "-xunitxml" "-p" "-o" "-p" "test-database-xunit.xml" "-p" "-o" "-p" "-,txt")
set_property(TEST test-database PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=.")
set_property(TEST test-database PROPERTY ENVIRONMENT "QT_QPA_PLATFORM=minimal")
add_dependencies(check test-database)
option(BUILD_PYTHON "Build Python wrapper" OFF)
if (BUILD_PYTHON)
find_package(PythonLibs)
if (PYTHONLIBS_FOUND)
set(U1DB_QT_PY_SRCS qt-backend-wrapper.cpp)
include_directories(
${PYTHON_INCLUDE_DIRS}
${Qt5Sql_INCLUDE_DIRS}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -Wall -Wundef -std=c++0x")
add_library(u1dbqt SHARED ${U1DB_QT_PY_SRCS})
target_link_libraries(u1dbqt
${Qt5Core_LIBRARIES}
${Qt5Sql_LIBRARIES}
${U1DB_QT_LIBNAME}
${PYTHON_LDFLAGS}
)
add_custom_command(TARGET u1dbqt POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink libu1dbqt.so u1dbqt.so)
endif ()
endif ()
u1db-qt-0.1.7/tests/qt-backend-wrapper.cpp 0000664 0000000 0000000 00000011630 14367477523 0020354 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include "database.h"
#include
QT_USE_NAMESPACE_U1DB
static PyObject *Module_hello(PyObject *self, PyObject *args)
{
return PyString_FromString("world");
}
static void u1dbqt_database_destructor(PyObject* capsule)
{
Database* db = static_cast(PyCapsule_GetPointer(capsule, NULL));
delete db;
}
static void* u1dbqt_get_ptr(PyObject *self, char* name)
{
PyObject* capsule = PyObject_GetAttrString(self, "qt_db");
assert(capsule != 0);
void* ptr = PyCapsule_GetPointer(capsule, name);
assert(ptr != 0);
return ptr;
}
static void u1dbqt_set_ptr (PyObject *self, char* name, void* ptr, PyCapsule_Destructor destr)
{
// qDebug() << "set_ptr" << PyObject_Str(self) << name;
PyObject* capsule = PyCapsule_New(ptr, name, destr);
assert(capsule != 0);
assert (PyObject_SetAttrString(self, "qt_db", capsule) != -1);
}
static PyObject *Database_init(PyObject *self, PyObject *args, PyObject *kwd)
{
char *path = ":memory:";
static char *kwlist[] = {"self", "path", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwd, "Os", kwlist,
&self, &path))
return NULL;
Database* db = new Database();
db->setPath(path);
u1dbqt_set_ptr(self, "u1dbqt.db", db, u1dbqt_database_destructor);
// qDebug() << "__init__" << db;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *Database_put_doc(PyObject *self, PyObject *args, PyObject* kwd)
{
char *contents = NULL;
char *docId = NULL;
static char *kwlist[] = {"self", "contents", "doc_id", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwd, "Ozz", kwlist,
&self, &contents, &docId))
return NULL;
Database* db = static_cast(u1dbqt_get_ptr(self, "u1dbqt.db"));
if (db->putDoc(QVariant())) {
char* lastError = (char*)(db->lastError().data());
if (strstr (lastError, "Invalid docID"))
PyErr_SetString(PyErr_NewException("errors.InvalidDocId", NULL, NULL), lastError);
else
PyErr_SetString(PyErr_NewException("u1dbqt.QtDatabaseError", NULL, NULL), lastError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *Database_get_doc(PyObject *self, PyObject *args, PyObject* kwd)
{
char *docId = NULL;
static char *kwlist[] = {"self", "doc_id", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwd, "Oz", kwlist,
&self, &docId))
return NULL;
Database* db = static_cast(u1dbqt_get_ptr(self, "u1dbqt.db"));
QVariant doc(db->getDoc(QString(docId)));
/* if (!doc.isValid()) {
const char* lastError = db->lastError().data();
PyErr_SetString(PyExc_ValueError, lastError);
return NULL;
} */
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *Database_repr(PyObject *self, PyObject *args)
{
return PyString_FromString("u1dbqt.Database");
}
static PyMethodDef ModuleMethods[] =
{
{"hello", Module_hello, METH_NOARGS, ""},
{NULL, NULL, 0, NULL}
};
static PyMethodDef DatabaseMethods[] =
{
{"__init__", (PyCFunction)Database_init, METH_VARARGS | METH_KEYWORDS, ""},
{"put_doc", (PyCFunction)Database_put_doc, METH_VARARGS | METH_KEYWORDS, ""},
{"get_doc", (PyCFunction)Database_get_doc, METH_VARARGS | METH_KEYWORDS, ""},
{"__repr__", Database_repr, METH_VARARGS, ""},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initu1dbqt(void)
{
PyObject *module = Py_InitModule("u1dbqt", ModuleMethods);
PyObject *moduleDict = PyModule_GetDict(module);
PyObject *classDict = PyDict_New();
PyObject *className = PyString_FromString("Database");
PyObject *classInstance = PyClass_New(NULL, classDict, className);
PyDict_SetItemString(moduleDict, "Database", classInstance);
Py_DECREF(classDict);
Py_DECREF(className);
Py_DECREF(classInstance);
PyMethodDef *def;
for (def = DatabaseMethods; def->ml_name != NULL; def++) {
PyObject *func = PyCFunction_New(def, NULL);
PyObject *method = PyMethod_New(func, NULL, classInstance);
PyDict_SetItemString(classDict, def->ml_name, method);
Py_DECREF(func);
Py_DECREF(method);
}
}
u1db-qt-0.1.7/tests/strict-qmltestrunner.sh 0000775 0000000 0000000 00000001502 14367477523 0020746 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
#!/usr/bin/env sh
#
# Copyright 2013 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
################################################################################
qmltestrunner $* || exit 1
test 0 -eq $(grep -c qwarn plugintest-xunit.xml) || exit 1
u1db-qt-0.1.7/tests/test-database.cpp 0000664 0000000 0000000 00000011232 14367477523 0017404 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include
#include "database.h"
#include "document.h"
#include "index.h"
#include "query.h"
QT_USE_NAMESPACE_U1DB
class U1DBDatabaseTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase()
{
while(false)
qApp->processEvents();
}
void testCanSetPath()
{
Database db;
QCOMPARE(db.getPath(), QString(""));
QSignalSpy modelReset(&db, SIGNAL(pathChanged(const QString&)));
QTemporaryFile file;
QCOMPARE(file.open(), true);
db.setPath(file.fileName());
QCOMPARE(db.getPath(), file.fileName());
QVERIFY(db.lastError().isEmpty());
}
void testCanSetEmptyPath()
{
Database db;
QCOMPARE(db.getPath(), QString());
QSignalSpy modelReset(&db, SIGNAL(pathChanged(const QString&)));
QTemporaryFile file;
QCOMPARE(file.open(), true);
db.setPath(file.fileName());
QCOMPARE(db.getPath(), file.fileName());
db.setPath("");
QCOMPARE(db.getPath(), QString());
QVERIFY(db.lastError().isEmpty());
}
void testCanSetPathUsingQUrl()
{
Database db;
QCOMPARE(db.getPath(), QString(""));
QSignalSpy modelReset(&db, SIGNAL(pathChanged(const QString&)));
QTemporaryFile file;
QCOMPARE(file.open(), true);
QString url = QUrl::fromLocalFile(file.fileName()).toString();
db.setPath(url);
QCOMPARE(db.getPath(), url);
}
void testNonExistingParentFolder()
{
Database db;
QTemporaryFile file("spamXXXXXX");
file.setAutoRemove(false);
QCOMPARE(file.open(), true);
QString subfolder(file.fileName() + "/eggs");
QFile::remove(file.fileName());
db.setPath(subfolder);
QCOMPARE(db.getPath(), subfolder);
QVERIFY(db.lastError().isEmpty());
}
void testCanSetIndex()
{
Database db;
Index index;
index.setDatabase(&db);
index.setName("py-name-phone");
index.setExpression(QStringList() << "gents.name" << "gents.phone");
}
void testCanSetQuery()
{
Database db;
Index index;
index.setDatabase(&db);
index.setName("by-date");
index.setExpression(QStringList() << "date" << "sports" << "software");
Query query;
query.setIndex(&index);
query.setQuery(QStringList() << "2014*" << "basketball" << "linux");
}
void testSingleDocumentQuery()
{
const char * json = "{\"department\": \"department of redundancy department\"," \
" \"managers\": [" \
" {\"name\": \"Mary\", \"phone_number\": \"12345\"}," \
" {\"name\": \"Katherine\"}," \
" {\"name\": \"Rob\", \"phone_number\": [\"54321\"]}" \
" ]" \
"}";
Database db;
Document doc;
doc.setDocId("department");
doc.setDatabase(&db);
doc.setContents(QJsonDocument::fromJson(QByteArray(json)).toVariant());
Index index;
index.setDatabase(&db);
index.setName("by-phone-number");
index.setExpression(QStringList() << "managers.phone_number");
Query query;
query.setIndex(&index);
QCOMPARE(query.getDocuments().size(), 1);
QCOMPARE(query.getDocuments().front(), QString("department"));
QList expected_numbers;
Q_FOREACH (QVariant manager, doc.getContents().toMap()["managers"].toList())
{
QVariantMap man = manager.toMap();
if (man.keys().contains("phone_number"))
{
man.remove("name");
expected_numbers.append(man);
}
}
QCOMPARE(query.getResults(), expected_numbers);
}
void cleanupTestCase()
{
}
};
QTEST_MAIN(U1DBDatabaseTest)
#include "test-database.moc"
u1db-qt-0.1.7/tests/test-upstream.py 0000775 0000000 0000000 00000006072 14367477523 0017357 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
# Copyright 2013 Canonical Ltd.
#
# This file is part of u1db.
#
# u1db is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# u1db is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with u1db. If not, see .
import os, sys, unittest
try:
from testtools import run
import testscenarios
except:
print('Required modules: python-testtools python-testscenarios')
sys.exit(1)
try:
import u1dbqt
except Exception:
msg = sys.exc_info()[1] # Python 2/3 compatibility
print(msg)
print('u1dbqt Python wrapper not built? Did you run "make"?')
sys.exit(1)
try:
import u1db # Database, SyncTarget, Document, errors
import u1db.tests
from u1db.tests import test_backends
except:
print('python-u1db required, with tests support')
print('An easy way of doing that is getting lp:u1db and setting PYTHONPATH=/path/to/u1db')
sys.exit(1)
# u1db-qt specific test cases
class TestQt(u1db.tests.DatabaseBaseTests):
def setUp(self):
super(TestQt, self).setUp()
def test_sanity(self):
self.assertTrue('Qt' in str(self))
# wrap Qt code in Python classes (via ui1dbqt Python module)
# cf. http://bazaar.launchpad.net/~pedronis/u1db/u1db-js/view/head:/tests/bridged.py
class QtDatabase(u1dbqt.Database):
def __init__(self, replica_uid):
u1dbqt.Database.__init__(self, replica_uid)
def create_doc_from_json(self, json, doc_id=None):
# FIXME create in db
doc = u1db.Document(doc_id=doc_id)
doc.set_json(json)
return doc
def put_doc (self, doc):
u1dbqt.Database.put_doc(self, contents=doc.get_json(), doc_id=doc.doc_id)
def delete_doc (self, doc):
# Deleted means empty contents in the database
self.put_doc(contents=None, doc_id=doc.doc_id)
def get_docs (self):
pass # TODO
def get_all_docs (self):
pass # TODO
def close (self):
pass # TODO
# TODO complete wrappers
def make_database(test, replica_uid):
db = QtDatabase(replica_uid)
def cleanup():
pass # FIXME delete old databases
test.addCleanup(cleanup)
return db
# upstream Python test cases
# cf http://bazaar.launchpad.net/~pedronis/u1db/u1db-js/view/head:/tests/test_bridged.py
SCENARIOS = [("jsbridged", {
"make_database_for_test": make_database,
})]
class BridgedAllDatabaseTests(test_backends.AllDatabaseTests):
scenarios = SCENARIOS
# TODO enable more cases
load_tests = u1db.tests.load_with_scenarios
if __name__ == '__main__':
loader = unittest.TestLoader()
suite = load_tests (loader, loader.loadTestsFromName(__name__), '*')
unittest.TextTestRunner(verbosity=2).run(suite)
u1db-qt-0.1.7/tests/tst_database.qml 0000664 0000000 0000000 00000012114 14367477523 0017330 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import QtTest 1.0
import U1db 1.0 as U1db
Item {
width: 200; height: 200
U1db.Database {
id: myDatabase
path: "aDatabaseB"
property bool first_row_loaded: false
property bool last_row_loaded: false
onDocLoaded: {
if (path == 'aDatabaseC' && docId == 'dl0')
first_row_loaded = true
if (path == 'aDatabaseC' && docId == 'dl99')
last_row_loaded = true
}
}
U1db.Document {
id: myDocument
database: myDatabase
docId: 'qwertzui'
defaults: { "eggs": "spam" }
}
U1db.Document {
id: otherDocument
database: myDatabase
docId: 'shallow'
create: true
defaults: { "eggs": "spam" }
}
ListView {
id: myList
model: myDatabase
width: 200; height: 200
delegate: Text {
x: 66; y: 77
text: "otherDelegate index:%1".arg(index)
}
}
TestCase {
name: "U1dbDatabase"
when: windowShown
function test_0_documentCreate () {
compare(myDatabase.getDoc(otherDocument.docId), otherDocument.defaults)
}
function test_1_databasePopulated () {
spyListCompleted.wait()
compare(myDatabase.putDoc({"animals": ["cat", "dog", "hamster"]}) == '', false)
var myPath = "aDatabaseA"
myDatabase.path = myPath
spyPathChanged.wait()
compare(myDatabase.path, myPath)
compare(myDatabase.putDoc({"spam": "eggs"}) == '', false)
var json = {"foo": "bar"}
compare(myDatabase.putDoc(json, "hijklmn") == '', false)
compare(myDatabase.getDoc("hijklmn"), json)
compare(myDatabase.getDoc("hijklmn"), json)
}
function test_2_databaseError () {
skip("FIXME: unicode in Qt console output doesn't work inside dpkg")
ignoreWarning('u1db: Invalid docID 日本語')
myDatabase.putDoc({"": ""}, "日本語")
spyErrorChanged.wait()
compare(myDatabase.error.indexOf("Invalid docID") > -1, true)
}
function test_3_documentContents () {
var json = {"content": {"notetext": "Lorem ipsum"}}
myDatabase.putDoc(json, "qwertzui")
myDocument.docId = ''
compare(myDocument.contents, undefined)
myDocument.docId = 'qwertzui'
compare(myDocument.contents, json)
compare(myDocument.contents.content.notetext, 'Lorem ipsum')
var path = myDatabase.path
myDatabase.path = ':memory:'
myDatabase.path = path
spyContentsChanged.wait()
}
function test_4_putIndex () {
myDatabase.putIndex("by-phone-number", ["managers.phone_number"])
compare(myDatabase.getIndexExpressions('by-phone-number'), ["managers.phone_number"])
myDatabase.putDoc({ 'managers': [
{ 'name': 'Mary', 'phone_number': '12345' },
{ 'name': 'Rob', 'phone_number': '54321' },
] })
// FIXME compare(myDatabase.getIndexKeys('by-phone-number'), ['12345', '54321'])
}
function test_6_fillDocument () {
skip("FIXME: Final myList.count compare failing")
var path = "aDatabaseC"
myDatabase.path = path
spyPathChanged.wait()
compare(myList.count, 2)
myDatabase.path = ":memory:"
spyPathChanged.wait()
wait()
for (var i = 0; i < 100; i++)
myDatabase.putDoc({'foo': 'bar'} ,'dl' + Number(i).toLocaleString())
wait()
myDatabase.first_row_loaded = false
myDatabase.last_row_loaded = false
myDatabase.path = path
spyPathChanged.wait()
spyContentsChanged.wait()
compare(myList.count, 102)
spyDocLoaded.wait()
// FIXME compare(myDatabase.first_row_loaded, true)
// FIXME compare(myDatabase.last_row_loaded, false)
}
SignalSpy {
id: spyPathChanged
target: myDatabase
signalName: "pathChanged"
}
SignalSpy {
id: spyContentsChanged
target: myDocument
signalName: "contentsChanged"
}
SignalSpy {
id: spyErrorChanged
target: myDatabase
signalName: "errorChanged"
}
SignalSpy {
id: spyListCompleted
target: myDatabase.Component
signalName: "completed"
}
SignalSpy {
id: spyDocLoaded
target: myDatabase
signalName: "docLoaded"
}
} }
u1db-qt-0.1.7/tests/tst_query.qml 0000664 0000000 0000000 00000025074 14367477523 0016742 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Christian Dywan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
import QtQuick 2.0
import QtTest 1.0
import U1db 1.0 as U1db
Item {
width: 200; height: 200
U1db.Database {
id: gents
}
U1db.Document {
database: gents
docId: '1'
contents: { 'gents': [ { 'name': 'Mary', 'phone': 12345 }, { 'name': 'Rob', 'phone': 54321 }, ] }
}
U1db.Document {
database: gents
docId: 'a'
contents: { 'gents': [ { 'name': 'George', 'phone': 'NA' }, { 'name': 'Ivanka', 'phone': 50243 }, ] }
}
U1db.Document {
database: gents
docId: '_'
contents: { 'misc': { 'software': 'linux', 'sports': [ 'basketball', 'hockey' ] }, 'date': '2014-01-01' , 'gents': [ { 'name': 'Ivanka', 'phone': 00321 }, ] }
}
U1db.Document {
database: gents
docId: 'F'
contents: { 'details': { 'name': 'spy', 'type': 'hide', 'colour': 'blue' } }
}
U1db.Document {
database: gents
docId: 'G'
contents: { 'details': { 'name': 'kid', 'type': 'show', 'colour': 'green' } }
}
U1db.Index {
id: byPhone
database: gents
name: 'by-phone'
expression: ['gents.phone']
}
U1db.Index {
id: byNamePhone
database: gents
name: 'by-name-phone'
expression: ['gents.name', 'gents.phone']
}
U1db.Index {
id: byDate
database: gents
name: 'by-date'
expression: ['date', 'sports', 'software']
}
U1db.Query {
id: defaultPhone
index: byPhone
}
U1db.Query {
id: allPhone
index: byPhone
query: '*'
}
U1db.Query {
id: allPhoneList
index: byPhone
query: ['*']
}
U1db.Query {
id: allPhoneKeywords
index: byPhone
query: [ { 'phone': '*' } ]
}
U1db.Query {
id: s12345Phone
index: byPhone
query: '12345'
}
U1db.Query {
id: i12345Phone
index: byPhone
query: [ { 'phone': 12345 } ]
}
U1db.Query {
id: i12345PhoneSimple
index: byPhone
query: 12345
}
U1db.Query {
id: s1wildcardPhone
index: byPhone
query: '1*'
}
U1db.Query {
id: ivankaAllNamePhone
index: byNamePhone
query: [ { name: 'Ivanka', phone: '*' } ]
}
U1db.Query {
id: ivankaAllNamePhoneSimple
index: byNamePhone
query: ['Ivanka', '*']
}
U1db.Query {
id: ivankaAllNamePhoneKeywords
index: byNamePhone
query: [ { 'name': 'Ivanka', 'phone': '*' } ]
}
U1db.Query {
id: toplevelQuery
index: byDate
query: [{ 'date': '2014*', 'sports': 'basketball', 'software': 'linux' }]
}
U1db.Query {
id: toplevelQuerySimple
index: byDate
query: [ '2014*', 'basketball', 'linux' ]
}
U1db.Query {
id: queryOne
index: U1db.Index {
database: gents
name: 'one'
expression: [ 'details.type' ]
}
query: [ 'show' ]
}
U1db.Query {
id: queryBothSimple
index: U1db.Index {
database: gents
name: 'bothSimple'
expression: [ 'details.type', 'details.colour' ]
}
query: [ 'show', '*' ]
}
U1db.Query {
id: queryBoth
index: U1db.Index {
database: gents
name: 'both'
expression: [ 'details.type', 'details.colour' ]
}
query: [ { type: 'show', colour: '*' } ]
}
U1db.Database {
id: tokusatsu
}
U1db.Document {
database: tokusatsu
docId: 'ooo'
contents: { 'series': 'ooo', 'type': 'rider' }
}
U1db.Document {
database: tokusatsu
docId: 'gokaiger'
contents: { 'series': 'gokaiger', 'type': 'sentai' }
}
U1db.Document {
id: tokusatsuDocumentWizard
docId: 'wizard'
contents: { 'series': 'wizard', 'type': 'rider',
'transformations': ['Flame Style','Water Style'] }
}
U1db.Document {
id: tokusatsuDocumentDino
docId: 'dino'
contents: { 'series': 'zyuranger', 'scarf': false, 'type': 'sentai',
'beasts': ['T-Rex', 'Mastodon'] }
}
U1db.Index {
id: bySeries
database: tokusatsu
name: 'by-series'
expression: ['series', 'type']
}
U1db.Query {
id: allHeroesWithType
index: bySeries
query: [{ 'series': '*' }, { 'type': '*' }]
}
U1db.Query {
id: allHeroesSeriesOnly
index: bySeries
query: [{ 'series': '*' }]
}
SignalSpy {
id: spyDocumentsChanged
target: defaultPhone
signalName: "documentsChanged"
}
TestCase {
name: "U1dbDatabase"
when: windowShown
function prettyJson(j) {
var A = JSON.stringify(j)
if (A['0'] && A != '{}') {
var A = '['
for(var i in j)
A += JSON.stringify(j[i]) + ','
A = A.substring(0, A.lastIndexOf(',')) + ']'
}
return A
}
function compareFail(a, b, msg) {
compare(a, b, msg, true)
}
function compare(a, b, msg, willFail) {
/* Override built-in compare to:
Match different JSON for identical values (number hash versus list)
Produce readable output for all JSON values
*/
if (a == b)
return
var A = prettyJson(a), B = prettyJson(b)
if (A != B) {
if (willFail) {
console.log('Expected failure: %1%2 != %3'.arg(msg ? msg + ': ' : '').arg(A).arg(B))
return
}
fail('%5%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b)).arg(msg ? msg + ': ' : ''))
}
if (willFail)
fail('Expected to fail, but passed: %5%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b)).arg(msg ? msg + ': ' : ''))
}
function workaroundQueryAndWait (buggyQuery) {
var realQuery = buggyQuery.query;
spyDocumentsChanged.target = buggyQuery
spyDocumentsChanged.wait();
}
function test_1_defaults () {
// We should get all documents
workaroundQueryAndWait(defaultPhone)
compare(defaultPhone.documents, ['1', '_', 'a'], 'uno')
compare(defaultPhone.results.length, 3, 'dos')
compare(defaultPhone.results.length, defaultPhone.documents.length, 'puntos')
// These queries are functionally equivalent
compare(defaultPhone.documents, allPhone.documents, 'tres')
compare(defaultPhone.documents, allPhoneList.documents, 'quatro')
workaroundQueryAndWait(allPhoneKeywords)
compare(defaultPhone.documents, allPhoneKeywords.documents, 'cinco')
// Results are also equivalent
compare(defaultPhone.results.length, allPhoneKeywords.results.length , 'siete')
compare(defaultPhone.results, allPhoneKeywords.results, 'seis')
// Results are lists of matching index fields with their values
var firstDocId = gents.listDocs()[0]
compare(defaultPhone.documents[0], firstDocId)
var firstContents = gents.getDoc(firstDocId)
compare(defaultPhone.results[0], {"phone": firstContents.gents[0].phone})
}
function test_2_numbers () {
// We should get '1'
compare(s12345Phone.documents, ['1'], 'uno')
// It's okay to mix strings and numerical values
compare(s12345Phone.documents, i12345Phone.documents, 'dos')
compare(i12345PhoneSimple.documents, i12345Phone.documents, 'tres')
}
function test_3_wildcards () {
// Trailing string wildcard
compare(s1wildcardPhone.documents, ['1'], 'uno')
// Last given field can use wildcards
compare(ivankaAllNamePhoneSimple.documents, ['_', 'a'], 'dos')
compare(ivankaAllNamePhone.documents, ['_', 'a'], 'tres')
// These queries are functionally equivalent
workaroundQueryAndWait(ivankaAllNamePhoneKeywords)
workaroundQueryAndWait(ivankaAllNamePhone)
compare(ivankaAllNamePhone.documents, ivankaAllNamePhoneKeywords.documents, 'tres')
compare(toplevelQuery.documents, ['_'])
compare(toplevelQuerySimple.documents, ['_'], 'cinco')
}
function test_4_delete () {
compare(defaultPhone.documents, ['1', '_', 'a'], 'uno')
// Deleted aka empty documents should not be returned
gents.deleteDoc('_')
compare(defaultPhone.documents, ['1', 'a'], 'dos')
}
function test_5_fields () {
compare(queryOne.documents, ['G'], 'one field')
compare(queryBoth.documents, ['G'], 'two fields')
compare(queryBothSimple.documents, ['G'], 'two fields simple')
}
function test_6_definition () {
workaroundQueryAndWait(allHeroesWithType)
compare(allHeroesWithType.documents, ['gokaiger', 'ooo'], 'ichi')
workaroundQueryAndWait(allHeroesSeriesOnly)
compare(allHeroesSeriesOnly.documents, ['gokaiger', 'ooo'], 'ni')
compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'doube-check')
// Add a document with extra fields
tokusatsu.putDoc(tokusatsuDocumentWizard.contents, tokusatsuDocumentWizard.docId)
workaroundQueryAndWait(allHeroesWithType)
compare(allHeroesWithType.documents, ['gokaiger', 'ooo', 'wizard'], 'san')
workaroundQueryAndWait(allHeroesSeriesOnly)
compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'chi')
// Add a document with mixed custom fields
tokusatsu.putDoc(tokusatsuDocumentDino.contents, tokusatsuDocumentDino.docId)
workaroundQueryAndWait(allHeroesWithType)
compare(allHeroesWithType.documents, ['dino', 'gokaiger', 'ooo', 'wizard'], 'go')
compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'roku')
}
} }
u1db-qt-0.1.7/tests/xvfb.sh 0000664 0000000 0000000 00000002015 14367477523 0015457 0 ustar 00root root 0000000 0000000 #!/bin/sh
#
# Copyright 2013-2014 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
# Author: Christian Dywan
echo Running $@ in virtual frame buffer...
xvfb-run -a -s "-screen 0 1280x1024x24" -e xvfb.err "$@" 2>test.err
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo $@ finished successfully...
else
echo $@ in virtual frame buffer failed...
cat test.err >&2
echo Tail of xvfb-run output:
tail xvfb.err >&2
exit $RETVAL
fi