pax_global_header 0000666 0000000 0000000 00000000064 14554502467 0014526 g ustar 00root root 0000000 0000000 52 comment=5afbb36b5040699d3a8f4faf0167fb272353a402
history-service-0.5/ 0000775 0000000 0000000 00000000000 14554502467 0014531 5 ustar 00root root 0000000 0000000 history-service-0.5/.gitignore 0000664 0000000 0000000 00000001750 14554502467 0016524 0 ustar 00root root 0000000 0000000 */*_automoc*
*/*/*_automoc*
*.cbp
CMakeCache.txt
CMakeFiles
*/CMakeFiles
*/cmake_install.cmake
cmake_install.cmake
config.h
coverage*
*/CTestTestfile.cmake
CTestTestfile.cmake
daemon/history-daemon
*/*.desktop
Makefile
*/Makefile
*/*/*.moc
*/*/*/moc_
*/*/moc_*
*/moc_*
plugins/sqlite/*.depends
plugins/sqlite/qrc_*
plugins/sqlite/schema/schema.sql
*/*.service
daemon/historyserviceadaptor.*
src/*.pc
src/libhistoryservice.so*
src/pluginthreadviewadaptor.*
src/plugineventviewadaptor.*
Testing
*/tests/*Test
test_*.xml
tools/*/history-*
*.user
install_manifest.txt
plugins/sqlite/*qrc
plugins/sqlite/schema/version.info
daemon/tests/mock/telepathy-mock*
daemon/tests/mock/mockconnectionadaptor*
daemon/tests/dbus-test-wrapper.sh
tests/*/*/*Test
tests/*/*Test
tests/*/moc_*
tests/*/*/moc_*
tests/*/*.moc*
tests/*/*/*.moc*
tests/*/*automoc*
tests/*/*/*automoc*
tests/common/dbus-services/*service
tests/common/dbus-session.conf
tests/common/mock/telepathy-mock
tests/common/mock/mockconnectionadaptor.*
history-service-0.5/AUTHORS 0000664 0000000 0000000 00000000510 14554502467 0015575 0 ustar 00root root 0000000 0000000 Alberto Mardegan
Alfred Neumayer
Dalton Durst
Dan Chapman
Florian Boucault
Florian Leeber
Guido Berhoerster
Gustavo Pichorim Boiko
Jezek
JEzEk
Ken VanDine
Lionel Duboeuf
Marius
Marius Gripsgard
Mike Gabriel
Ratchanan Srirattanamet
Renato Araujo Oliveira Filho
Roberto Mier Escandon
Robert Tari
Tiago Salem Herrmann
Timo Jyrinki
history-service-0.5/CMakeLists.txt 0000664 0000000 0000000 00000010520 14554502467 0017267 0 ustar 00root root 0000000 0000000 cmake_minimum_required(VERSION 3.5)
project(history-service VERSION 0.5 LANGUAGES CXX)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
# Standard install paths
include(GNUInstallDirs)
# Check for include files
include(CheckIncludeFileCXX)
include(CheckIncludeFile)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
find_package(Qt5Contacts)
find_package(Qt5DBus)
find_package(Qt5Qml)
find_package(Qt5Quick)
find_package(Qt5Test)
find_package(Qt5Network)
find_package(LibPhoneNumber REQUIRED)
include(qt5)
if(NOT CMAKE_CROSSCOMPILING)
find_program(QMAKE_EXECUTABLE qmake)
if(QMAKE_EXECUTABLE STREQUAL "QMAKE_EXECUTABLE-NOTFOUND")
message(FATAL_ERROR "qmake not found")
endif()
execute_process(
COMMAND ${QMAKE_EXECUTABLE} -query QT_INSTALL_QML
RESULT_VARIABLE RESULT
OUTPUT_VARIABLE QT_INSTALL_QML
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT RESULT EQUAL 0)
message(FATAL_ERROR "Failed to determine QT_INSTALL_QML from qmake")
endif()
else()
# qmake isn't multi-arch aware as it installs arch-specific mkspec files
# in to /usr/share, so we can't use it here (we'd need a qmake binary
# for the host arch using data for the target arch)
set(QT_INSTALL_QML "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt5/qml")
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
pkg_check_modules(QTGLIB QtGLib-2.0)
pkg_check_modules(SYSTEMD REQUIRED systemd)
find_program(DBUS_RUNNER dbus-test-runner)
option(TRACE_SQLITE "Print Sqlite commants to the log." off)
if (${TRACE_SQLITE})
add_definitions(-DTRACE_SQLITE)
endif()
add_definitions(-DQT_NO_KEYWORDS)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
)
set(HISTORY_PLUGIN_PATH ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/plugins)
set(TEST_DATA_DIR "${CMAKE_SOURCE_DIR}/tests/data")
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
# generate a macro to make it easier to enable coverage support on targets
function(ENABLE_COVERAGE)
get_directory_property(COVERAGE_TARGETS DIRECTORY ${CMAKE_SOURCE_DIR} COVERAGE_TARGETS)
list(APPEND COVERAGE_TARGETS ${ARGN})
MESSAGE(STATUS "Enabling coverage report for target(s): ${ARGN}")
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY COVERAGE_TARGETS ${COVERAGE_TARGETS})
endfunction()
enable_testing()
add_definitions(-std=c++11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall")
# TODO remove the need for -Wno-unused-variable
# unused-variable currently fails because of public headers includes static char's
# there is also a gcc bug that makes it not possable to rely on diagnostic pragmas
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69967
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-variable")
option(ENABLE_WERROR "Treat all build warnings as errors" ON)
if(ENABLE_WERROR)
add_compile_options(-Werror)
endif()
# Define the version to be used in the library
set(HISTORY_VERSION_MAJOR 0)
set(HISTORY_VERSION_MINOR 0)
set(HISTORY_VERSION_PATCH 0)
set(PACKAGE_VERSION ${HISTORY_VERSION_MAJOR}.${HISTORY_VERSION_MINOR}.${HISTORY_VERSION_PATCH})
add_subdirectory(src)
add_subdirectory(daemon)
add_subdirectory(plugins)
add_subdirectory(tools)
add_subdirectory(Lomiri)
add_subdirectory(tests)
find_package(CoverageReport)
# Coverage
#####################################################################
# Enable code coverage calculation with gcov/gcovr/lcov
# Usage:
# * Switch build type to coverage (use ccmake or cmake-gui)
# * Invoke make, make test, make coverage
# * Find html report in subdir coveragereport
# * Find xml report feasible for jenkins in coverage.xml
#####################################################################
IF(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE])
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs" )
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs" )
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -coverage" )
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -coverage" )
GET_DIRECTORY_PROPERTY(COVERAGE_TARGETS DIRECTORY ${CMAKE_SOURCE_DIR} COVERAGE_TARGETS)
ENABLE_COVERAGE_REPORT(TARGETS ${COVERAGE_TARGETS})
ENDIF(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE])
history-service-0.5/COPYING 0000664 0000000 0000000 00000104513 14554502467 0015570 0 ustar 00root root 0000000 0000000 GNU 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.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
history-service-0.5/ChangeLog 0000664 0000000 0000000 00000415766 14554502467 0016326 0 ustar 00root root 0000000 0000000 2024-01-25 Mike Gabriel
* Release 0.5 (HEAD -> main, tag: 0.5)
2023-11-10 Marius Gripsgard
* Merge branch 'personal/lduboeuf/fix_deadlock' into 'main' (d31262e)
2023-10-18 Lionel Duboeuf
* clickable it (d328120)
2023-10-17 Lionel Duboeuf
* Avoid deadlock while ContactManager being destroyed (e978395)
2023-04-06 Marius Gripsgard
* Merge branch 'personal/lduboeuf/fix_emblemcount' into 'main'
(8dd212b)
2023-04-03 Lionel Duboeuf
* emblem counter: prevent un-pinned app to be shown after boot fixes:
https://gitlab.com/ubports/development/core/messaging-app/-/issues/330
(1dd41db)
2023-03-03 Mike Gabriel
* Merge branch 'personal/lduboeuf/debug_logs' into 'main' (1fb4d61)
2023-03-03 Lionel Duboeuf
* add logs (7bf1a0d)
* create a fallback fileName in case of empty attachment identifier
fixes:
https://gitlab.com/ubports/development/core/history-service/-/issues/12
(4def364)
2023-01-18 Mike Gabriel
* Merge branch 'personal/lduboeuf/fix_zerocounter' into 'main'
(bd0a14d)
2023-01-17 Lionel Duboeuf
* emblemcounter: set the emblem visible before setting count property
when messaging-app/dialer app is not pinned, launcher
service only creates the emblem on countVisible property,
in that case the count is initialized to zero. (c6c9061)
2023-01-13 Guido Berhoerster
* Merge branch 'personal/sunweaver/enable-Werror-CMake-option' into
'main' (77c1b2a)
2023-01-13 Mike Gabriel
* CMakeLists.txt: Add ENABLE_WERROR CMake option, defaulting to ON.
(1370777)
* Release 0.4 (385e179) (tag: 0.4)
2023-01-13 Guido Berhoerster
* Merge branch 'personal/sunweaver/project-name-and-version' into
'main' (c7163fa)
2023-01-13 Mike Gabriel
* CMake: Specify VERSION in project() function, use PROJECT_NAME
variable instead of hard-coded 'history-service', bump to
CMake 3.5 (from 3.4). (9c77b77)
* d/changelog: undo release-like thing in d/changelog (introduced via
2a0f65c1) (178da48)
* .bzr-builddeb/default.conf: Drop file. End-of-bzr. (53b4b3e)
2023-01-12 Mike Gabriel
* Merge branch 'main_-_removeAttachments' into 'main' (3bfd269)
2022-03-31 Lionel Duboeuf
* Remove attachments management Store attachments with their file
name Add MMS tests (2a0f65c)
2023-01-06 Mike Gabriel
* Merge branch 'main_-_testmigration' into 'main' (0c1a702)
2022-11-29 Lionel Duboeuf
* Add ofono accounts migration management The ofono accounts ids may
differ between devices. If a user import his old history
database into a new device, we can have accountIds
mismatch, making messaging-app impracticable. This check
is done when Telepathy registers a new account ( at
startup or when adding a SIM card ) allow us to migrate
old account Ids ( e.g ofono/ofono/account0 to
ofono/ofono/ril_0) in database table (47d75dc)
* Allow to disable triggers when needed (63eb790)
2022-11-26 Mike Gabriel
* Merge branch 'changelog-xenial-to-focal' into 'main' (cfc8286)
2022-01-10 jEzEk
* Update debian/changelog (06ee7ba)
2022-11-26 Mike Gabriel
* Merge branch 'main_-_emblemcounter' into 'main' (ed9eb9a)
2022-04-26 Lionel Duboeuf
* add messaging-app / dialer-app emblem counter management (842fff3)
2022-08-01 Ratchanan Srirattanamet
* Merge branch 'fix-dbus-apparmor-check' into 'main' (cd4d85f)
2022-08-01 Guido Berhoerster
* Allow DBus activation by AppArmor-confined apps (46855a9)
2022-04-25 Ratchanan Srirattanamet
* Merge branch 'personal/peat-psuwit/merge-xenial-2022Apr' into
'main' (a99df26)
2022-04-21 Ratchanan Srirattanamet
* Merge remote-tracking branch 'origin/ubports/xenial' into
personal/peat-psuwit/merge-xenial-2022Apr (e104db5)
2022-02-28 Guido Berhoerster
* Merge branch 'ubports/focal_-_lomiri-telephony-apps' into 'main'
(c5fd484)
2022-02-21 Guido Berhoerster
* Remove unused and hidden desktop file for history-daemon (51f4156)
2022-02-15 Guido Berhoerster
* Convert upstart jobs to DBus activated systemd units (f3a6e76)
2022-01-28 Guido Berhoerster
* Rename SQLite plugin (e1ef85e)
* Rename DBus namespace from com.canonical to com.lomiri (87f1432)
* Rename qtdeclarative5-ubuntu-history0.1 to
qml-module-lomiri-history0.1 (2533159)
2021-12-16 Florian Leeber
* Merge branch 'xenial_-_removeevents' into 'ubports/xenial'
(88201fb)
2021-12-16 Lionel Duboeuf
* Add remove event method by Filter and type (3c57393)
2021-12-15 Dalton Durst
* Merge branch 'personal/fredldotme/mms-to-xenial' into
'ubports/xenial' (ffe0e85)
2021-12-15 jezek
* Failed MMS redownload (f7630d6)
2021-12-15 Alfred Neumayer
* Merge branch 'xenial_-_failed-MMS-redownload' into 'main' (0683655)
2021-12-15 jezek
* Failed MMS redownload (8faf763)
2021-12-06 Guido Berhoerster
* Merge branch 'ubports/focal_-_history-service_armhf_fix' into
'main' (7914ff7)
* Increase test default timeout to 120 s in order to fix armhf build
failures (61570a6)
* Merge branch 'main' into 'main' (68cb187)
* Port to focal (74a5109)
2021-12-04 Marius Gripsgard
* Merge branch 'ubports/xenial' into 'main' (d41485d)
* Merge branch 'ubports/focal' into 'main' (39c579c)
* Merge branch 'main' into 'ubports/focal' (9071f32)
* Merge branch 'personal/usb/move-jenkinsfile' into 'ubports/xenial'
(60e0f00)
2021-12-02 Dalton Durst
* Delete snapcraft.yaml (cc790cd)
* Move bzrignore to gitignore (1422039)
* Move Jenkinsfile to debian/Jenkinsfile (23ba146)
2021-11-24 Marius Gripsgard
* Merge branch 'mr/rename-com-ubuntu-touch-accountsservice-phone'
into 'main' (e3717c4)
* Merge branch 'mr/drop-wextra' into 'main' (c47a493)
2021-11-23 Robert Tari
* CMakeLists.txt: Remove the -Wextra flag (523d770)
2021-11-17 Guido Berhoerster
* Merge branch 'ubports/focal' into 'ubports/focal' (389fc6c)
2021-11-16 Guido Berhoerster
* Do not hardcode dconf-service path (dfbd706)
2021-11-11 Robert Tari
* Rename com.ubuntu.touch.AccountsService.Phone (6aa1706)
2021-05-26 Dalton Durst
* Merge pull request #39 from lduboeuf/xenial_-_upgrade_issue
(17c341e)
2021-05-26 Lionel Duboeuf
* prevent V19.sql from being executed when column already exist
(e3c26ed)
* make sure not to downgrade the db version number (722ca69)
2021-05-25 Lionel Duboeuf
* protect sql update from failing if triggers already exists (#38)
(d9009dc)
2021-05-21 Lionel Duboeuf
* don't update sentTime column on db upgrade. For big history
message, that would lead to query execution timeout and
hsitory daemon not activated. Instead ensure that sentTime
is always here when fetching/writing (34133bd)
2021-05-14 Lionel Duboeuf
* Manage the sent date for sms/mms (#32) (2a94dd4)
2021-01-26 Florian Leeber
* Merge pull request #36 from lduboeuf/xenial_-_updateJenkinsFile
(94cdf95)
2021-01-26 Lionel Duboeuf
* update Jenkinsfile (04ef122)
2020-10-08 Marius Gripsgard
* Use cmake-extras (#33) (23c69ec)
* Clean up code to build with -Wall -Werror -Wextra (#30) (8285a4a)
2020-10-07 Marius Gripsgard
* Replace deprecated QString::null with QString() (#31) (93d628b)
2020-09-30 Marius Gripsgard
* Merge remote-tracking branch
'origin/xenial_-_deprecated-qstringnull' into main
(a6da6a9)
* Merge remote-tracking branch 'origin/xenial_-_cmake-extras' into
main (d5fd3d6)
* Use make -j1 to do testing (bc65158)
* Use cmake-extras (52caf49)
* [plugin/sqlite] Add assert if argc is less than requied (7a45f07)
2020-09-12 Marius Gripsgard
* Fix implicit-fallthrough warning (7d7a07f)
* Fix maybe-uninitialized warning (bb6754b)
* Clean up code to build with -Wall -Werror -Wextra (5051fad)
2020-09-10 Marius Gripsgard
* Make sure to return value (8be02ee)
2020-09-11 Marius Gripsgard
* Replace deprecated QString::null with QString() (d74a07e)
2020-07-11 Florian Leeber
* Merge pull request #27 from lduboeuf/xenial_-_fixsentdate (1aa75ce)
2020-07-11 Lionel Duboeuf
* tab instead of space for rule file (ae5599c)
* test CI (ebaef1f)
* update changelog (3986ce7)
* Revert "use the message sent date instead of the received one"
(40390c4)
2020-07-11 Florian Leeber
* Merge pull request #26 from lduboeuf/xenial_-_updatechangelog
(b3fafeb)
2020-07-09 Lionel Duboeuf
* update changelog (d6f9e44)
2020-03-10 Lionel Duboeuf
* add exclusion filter. This allow to query history db with "Not
Equals" statement (0c7aecb)
2020-07-08 Florian Leeber
* Merge pull request #23 from mardy/tests-debug (f5df67a)
2020-07-06 Alberto Mardegan
* Build: declare history-qml a module (a2bdb93)
2020-07-05 Alberto Mardegan
* Build: do not link to QML plugin, directly use its sources
(a938bf9)
2020-07-06 Alberto Mardegan
* Build: fix duplicate file in Ubuntu.History (0a65e1b)
2020-07-03 Alberto Mardegan
* Revert disabling of tests (cbb2f9a)
2020-06-26 Florian Leeber
* Merge pull request #22 from ubports/xenial_-_disable-tests
(d26cb06)
* Unfortunately test disabling does not work, remove them entirely
(8abbac2)
2020-06-25 Florian Leeber
* disable for real (3913871)
* Disable instable tests (f1cfc1b)
2020-06-18 Florian Leeber
* Merge pull request #13 from lduboeuf/xenial_-_storemessagesentdate
(ed91470)
2020-04-03 Florian Leeber
* Merge pull request #19 from lduboeuf/xenial_-_readme (629165d)
2020-04-03 Lionel Duboeuf
* add readme (8e22380)
2020-04-02 Florian Leeber
* Merge pull request #17 from lduboeuf/xenial (fc2613a)
2020-04-01 Lionel Duboeuf
* update changelog: fix wrong version number (1520757)
* update changelog (18ce6e2)
2020-03-31 Florian Leeber
* Merge pull request #11 from lduboeuf/xenial_-_draftstatus (ef4e513)
2020-03-25 Lionel Duboeuf
* fix tests (4146238)
* use the message sent date instead of the received one (f87f4e5)
2020-02-03 Lionel Duboeuf
* add MessageStatus Draft (9dc221b)
2018-09-18 Alberto Mardegan
* Update changelog (1eeb840)
* ContactMatcher: Use C++11 signal connections (f5933b2)
* Build: allow building with crossbuilder (3a69c76)
2018-09-01 Marius Gripsgard
* Merge pull request #5 from mardy/xenial_-_latestqtpim (f4569c5)
2018-07-25 Alberto Mardegan
* Rebuild against latest QtPim (f0eef3b)
2018-03-06 Marius Gripsgard
* Fix fix changes that got lost in bzr to git merge (6b20f49)
* Remove duplicated function (651a0cd)
* New release (ed9f191)
* Merge remote-tracking branch 'lp-s/master' into xenial (1ca1ee5)
2018-03-06 Marius
* Merge staging (4cc0bcc)
2018-01-11 Dan Chapman
* Imported to UBports (8d31f29)
2017-03-22 Gustavo Pichorim Boiko
* Fix return value of a function that is now asynchronous (77ebca5)
* Fix return value of a function that is now asynchronous (20ce0c6)
* Make it possible to debug sqlite commands. (08fe84a)
* Do not load the participants from threads automatically. If the
client really needs it, it can use the newly added API to
fetch the participants. (df2a42f)
* Use a QLockFile to ensure there will be only one instance of the
daemon per user. As we now delay the registration on dbus,
sometimes we ended up having two instances of the daeon
running (because of dbus activation). This change makes
sure that won't happen. (d78e3ba)
* Reduce the dbus traffic when marking messages and threads as read.
(75df779)
* Allow pass multiple fields on sort clause. (3dda074)
* Mark entire conversations as read. (f812ee2)
* Improve Roles management performance by caching the retrieved data.
(0c91e3d)
* Only start saving information events about contacts joining and
leaving after the self contact is in the local list of
participants. (f4dd83a)
* Improve the notifications of participants changing (38b09ac)
* Adapt to support VOIP accounts. (1380851)
* Remove debugs (db783dc)
2017-03-22 Renato Araujo Oliveira Filho
* Code optimize. (eca54b8)
2017-03-21 Gustavo Pichorim Boiko
* Rebase this branch using the VOIP and IRC changes. (5fc1804)
2017-03-20 Gustavo Pichorim Boiko
* Fix thread ack query (a531e49)
2017-03-15 Gustavo Pichorim Boiko
* Only mark threads as read if it has unread events. (60c6ed5)
2017-03-15 Tiago Salem Herrmann
* Avoid duplicate join and leave events (20edd59)
2017-03-14 Gustavo Pichorim Boiko
* Fix filtering of events emitted in signals. (3cb2802)
2017-03-10 Gustavo Pichorim Boiko
* When extracting properties from text channels, avoid parsing
participants when there is no need for it. (f95720d)
* Merge parent (5396dfb)
2017-03-09 Gustavo Pichorim Boiko
* History-daemon is not a system service, so store a lock somewhere
in the user's home directory to allow running one instance
per user. (6df7f69)
* Cache the requests that didn't match any contact, and fix a wrong
condition. (b459d2e)
* Deliver the threads with the participants filled for the threads we
know will need it. (42a745a)
2017-03-09 Tiago Salem Herrmann
* merge parent branch (3f16f75)
* merge parent branch (f9d59fb)
* revert wrong commit (bb09d82)
2017-03-08 Tiago Salem Herrmann
* merge parent branch (7f12a93)
* merge parent branch (660910a)
* merge parent branch (0466b0c)
2017-03-08 Gustavo Pichorim Boiko
* Do not load the participants from threads automatically. If the
client really needs it, it can use the newly added API to
fetch the participants. (47943dd)
* Make sure tests use different lock files so that they can run
simultaneously (0c95795)
2017-03-03 Gustavo Pichorim Boiko
* Use a QLockFile to ensure there will be only one instance of the
daemon per user. As we now delay the registration on dbus,
sometimes we ended up having two instances of the daemon
running (because of dbus activation). This change makes
sure that won't happen. (d16db0c)
* When threads are removed, make sure the events models get refreshed
accordingly. (74b8851)
2017-03-02 Gustavo Pichorim Boiko
* Update tests (0e9c848)
* Optimize thread removal by deleting the events using a sqlite
trigger instead of manually removing and notifying them.
Also make the thread and event removal asynchronous calls
on dbus level as the result will be notified back to us as
signals. (b0c8a00)
* Stop using the telepathy pending message status to mark messages as
read as that causes performance problems when dealing with
a large number of messages. (b3a7504)
2017-02-23 Tiago Salem Herrmann
* fix build (ca553ea)
2017-02-21 Tiago Salem Herrmann
* merge parent branch (c95f6aa)
* merge parent branch (0105cc9)
* merge parent branch (d4f6674)
* merge parent branch (85b8712)
* merge parent branch (0ffb331)
* only remove participants from irc rooms (8f30e94)
2017-02-17 Gustavo Pichorim Boiko
* Only update the new events (eff554e)
2017-02-16 Gustavo Pichorim Boiko
* Buffer marking threads as read and get rid of duplicate calls.
Also, change the markEventAsRead to not fetch the event
from the daemon. (45fc630)
* Move the mark{Event,Threads}AsRead to HistoryModel so that all
models can use it. (ce708d7)
2017-02-15 Gustavo Pichorim Boiko
* merge parent (8a3a0ea)
* Buffer the emission of Threads{Added,Removed,Modified} and
Events{Added,Removed,Modified} signals on DBus to avoid
unecessary round trips (5180b6f)
2017-02-15 Tiago Salem Herrmann
* merge parent branch (9b6c794)
* merge parent branch (2b41158)
* merge parent branch (38651e4)
* merge parent branch (01a154b)
* merge parent branch (ec27365)
2017-02-14 Gustavo Pichorim Boiko
* Move the status mapping to a separate function (f1ff477)
2017-02-07 Renato Araujo Oliveira Filho
* Keep history model sorted if multiple fields are specified.
(1f19eff)
* Update comments. (7b063e4)
* Create unit test for multiple fields sort query. (d5eab29)
* Allow pass multiple fields on sort clause. (78999a0)
2017-02-07 Tiago Salem Herrmann
* merge parent branch (14b37d1)
* Mark entire conversations as read (befaf5e)
2017-02-06 Tiago Salem Herrmann
* merge trunk (01bd55f)
2017-02-03 Tiago Salem Herrmann
* Improve roles management (1a28cf9)
* merge parent (2ca46d7)
2017-02-03 Gustavo Pichorim Boiko
* Make sure IDs passed to the models are normalized. (baa7e86)
2017-02-02 Gustavo Pichorim Boiko
* Handle missed VOIP calls. (ac1c859)
2017-02-01 Tiago Salem Herrmann
* merge parent (b2982c7)
* remove participants from events (005e83a)
2017-01-30 Gustavo Pichorim Boiko
* Fix method return value. (f5f6284)
2017-01-27 Gustavo Pichorim Boiko
* Avoid using participants in text events, and also avoid fetching
threads when not needed. (48ef078)
2017-01-26 Gustavo Pichorim Boiko
* Only start saving information events about contacts joining and
leaving after the self contact is in the local list of
participants. (88c23fd)
2017-01-25 Tiago Salem Herrmann
* Improve performance (4d47d0f)
2017-01-06 Gustavo Pichorim Boiko
* Handle contact match for SIP accounts (cb54981)
2017-01-04 Gustavo Pichorim Boiko
* Merge trunk. (84bda40)
2016-11-30 Bileto Bot
* Releasing 0.1+17.04.20161130-0ubuntu1 (cfbae89)
* Releasing 0.1+17.04.20161130-0ubuntu1 (012ce33)
2016-11-30 Gustavo Pichorim Boiko
* Improve group chat support. (2f3272c)
* Improve group chat support. (bd71ad5)
2016-11-24 Bileto Bot
* Releasing 0.1+17.04.20161124.1-0ubuntu1 (455eeb3)
* Releasing 0.1+17.04.20161124.1-0ubuntu1 (6e1eac9)
2016-11-24 Renato Araujo Oliveira Filho
* Append "SNAP" prefix into the path to the plugins dir if none is
set. (80d4f68)
* Append "SNAP" prefix into the path to the plugins dir if none is
set. (a00eee8)
2016-11-24 Gustavo Pichorim Boiko
* Simplify the filtering of participants. (c278f65)
* Simplify the filtering of participants. (c275d17)
* Remove obsolete comment (53c2b98)
* Remove obsolete comment (fb12c4d)
* Use a more complete time format to generate the hash. (a143e41)
* Use a more complete time format to generate the hash. (e091846)
* Use compareIds() (179686f)
* Use compareIds() (a2657c9)
2016-11-23 Gustavo Pichorim Boiko
* Remove debug prints. (f8d7206)
* Remove debug prints. (cc7a003)
* And one more loop. (b6b2522)
* And one more loop. (cc53746)
* Simplify one more iteration (357ca44)
* Simplify one more iteration (1fa7137)
* Simplify the filtering of participants. (72ef8e4)
* Simplify the filtering of participants. (9159b54)
2016-11-21 Renato Araujo Oliveira Filho
* Does not use "CLICK_MODE" build flag. (c7b63e4)
* Does not use "CLICK_MODE" build flag. (5a4f27e)
* Created snap package. (af24479)
* Created snap package. (f60fb9f)
* Append "SNAP" prefix into the path to the plugins dir if none is
set. (f5f1caa)
* Append "SNAP" prefix into the path to the plugins dir if none is
set. (ec9500e)
2016-11-17 Gustavo Pichorim Boiko
* - Fix broken tests with latest changes. - Set ChatType correctly
when using createThreadForParticipants() (73ff5e3)
* - Fix broken tests with latest changes. - Set ChatType correctly
when using createThreadForParticipants() (4be7024)
2016-11-17 Tiago Salem Herrmann
* Set ChatType correctly when using createThreadForParticipants()
(5ff316a)
* Set ChatType correctly when using createThreadForParticipants()
(c486b07)
2016-11-17 Gustavo Pichorim Boiko
* - Create hash for threadId of broadcast messages - Avoid grouping
chats with different chatType's (bf6a784)
* - Create hash for threadId of broadcast messages - Avoid grouping
chats with different chatType's (b6b8c41)
2016-11-16 Tiago Salem Herrmann
* - Create hash for threadId of broadcast messages - Avoid grouping
chats with different chatType's (8eec940)
* - Create hash for threadId of broadcast messages - Avoid grouping
chats with different chatType's (fd7c37a)
2016-11-09 Gustavo Pichorim Boiko
* Update existing chats to Room or None based on the MMS option in
Accounts Service. (8aecf37)
* Update existing chats to Room or None based on the MMS option in
Accounts Service. (6e7a97d)
* Allow applications to insert different kind of information events.
(65fa732)
* Allow applications to insert different kind of information events.
(9fb930a)
2016-11-09 Tiago Salem Herrmann
* Allow applications to insert different kind of information events
(c25f3e7)
* Allow applications to insert different kind of information events
(5c33e85)
2016-11-08 Tiago Salem Herrmann
* Address comments (11587b0)
* Address comments (20b0ad2)
* Update existing chats to Room or None based on the mms option in
Accounts Service (f7a5c46)
* Update existing chats to Room or None based on the mms option in
Accounts Service (79df8ad)
2016-11-03 Gustavo Pichorim Boiko
* Leave the mock call channel opened for a bit longer to make sure
the last state change propagates correctly. (2c12f2c)
* Leave the mock call channel opened for a bit longer to make sure
the last state change propagates correctly. (98de322)
* Leave the mock call channel opened for a bit longer to make sure
the last state change propagates correctly. (0ebab07)
* Leave the mock call channel opened for a bit longer to make sure
the last state change propagates correctly. (c244d0a)
2016-11-02 Gustavo Pichorim Boiko
* Fix tests on latest tp-qt. (c715962)
* Fix tests on latest tp-qt. (3a283fa)
* Fix building with latest tp-qt. (177da86)
* Fix building with latest tp-qt. (14d3957)
2016-10-28 Gustavo Pichorim Boiko
* Skip self join notification in conversation when account is a ofono
one (84aa6c7)
* Skip self join notification in conversation when account is a ofono
one (8e8b2f1)
2016-10-28 Roberto Mier Escandon
* avoid showing self join message when account is a ofono one
(4d315fc)
* avoid showing self join message when account is a ofono one
(3a58f11)
2016-10-27 Gustavo Pichorim Boiko
* Adapt the registration of objects and services to the way QtDBus
works from 5.6.x on. (d221109)
* Adapt the registration of objects and services to the way QtDBus
works from 5.6.x on. (781fcb9)
* Re-enable DaemonTests. (bc5ce1c)
* Re-enable DaemonTests. (59f646a)
2016-10-20 Gustavo Pichorim Boiko
* Fix destroying threadviews by not leaving queries opened. (fb3b3b9)
* Fix destroying threadviews by not leaving queries opened. (332ea69)
* RolesClientInterface implementation to access roles interface
features Received events when roles changes write roles
event information only when received updates for roles
(isolating roles updates from members updates) added db
plugin method to update roles for members (08b08e8)
* RolesClientInterface implementation to access roles interface
features Received events when roles changes write roles
event information only when received updates for roles
(isolating roles updates from members updates) added db
plugin method to update roles for members (8cd9aeb)
* Added event info for group dissolved (7c85263)
* Added event info for group dissolved (78f9196)
2016-10-20 Roberto Mier Escandon
* resolved conflicts (d184032)
* resolved conflicts (cea906f)
* removed not needed local rules configuration (97e69b1)
* removed not needed local rules configuration (2e17c34)
2016-10-20 Gustavo Pichorim Boiko
* - added sender as parameter for info events just in case event
needs two actors (source and destination of the action) -
added subjectAsAlias event model role to translate contact
id<->alias before showing, to avoid having id some
milliseconds before showing the alias (358d60f)
* - added sender as parameter for info events just in case event
needs two actors (source and destination of the action) -
added subjectAsAlias event model role to translate contact
id<->alias before showing, to avoid having id some
milliseconds before showing the alias (ac5f4e5)
* Adds information events in history service for invited people
(remote pending) Second and next times same contact is
invited any new info event is added, since it was already
previously invited (a9adc13)
* Adds information events in history service for invited people
(remote pending) Second and next times same contact is
invited any new info event is added, since it was already
previously invited (8d3bc1f)
* Use subject2 telepathy interface instead of roomConfig in order to
have actor when updated the title (6f4d99d)
* Use subject2 telepathy interface instead of roomConfig in order to
have actor when updated the title (7de8e1a)
* Improve information events handling. Now all strings have to be
translated on the app side. (ada712b)
* Improve information events handling. Now all strings have to be
translated on the app side. (cae49fa)
* Show events in conversation when group modifications happen
(members updates, title, etc..) (49d19a7)
* Show events in conversation when group modifications happen
(members updates, title, etc..) (d1d31e4)
2016-10-20 Roberto Mier Escandon
* change 'You' by 'self' when referring to myself (2b45e87)
* change 'You' by 'self' when referring to myself (06f869b)
* removed not needed comments (bca1893)
* removed not needed comments (7a84b23)
* addressed comments (dfc767f)
* addressed comments (900b172)
2016-10-20 Gustavo Pichorim Boiko
* Remove obsolete comments (2e64af6)
* Remove obsolete comments (fe0e0b4)
2016-10-19 Gustavo Pichorim Boiko
* Trying to get in history daemon the event of group cancelled to
insert a new event in related thread, to be seen in UI.
(0db49f1)
* Trying to get in history daemon the event of group cancelled to
insert a new event in related thread, to be seen in UI.
(134bb07)
* Initial group chat support. (4a019a6)
* Initial group chat support. (67a7dd1)
2016-10-19 Tiago Salem Herrmann
* we have to also group broadcast messages (334160a)
* we have to also group broadcast messages (a0c009a)
2016-10-19 Gustavo Pichorim Boiko
* Add comments on things that need fixing (6102632)
* Add comments on things that need fixing (473f571)
2016-10-18 Gustavo Pichorim Boiko
* Fix destroying threadviews by not leaving queries opened. (301f85f)
* Fix destroying threadviews by not leaving queries opened. (a651c98)
2016-10-06 Tiago Salem Herrmann
* merge parent branch (7f515f9)
* merge parent branch (8520097)
* merge parent branch (393cb9a)
* merge parent branch (dda8340)
* merge parent branch (86ddf10)
* merge parent branch (44285f6)
* merge parent branch (d8636b4)
* merge parent branch (09862b9)
* merge parent branch (2168484)
* merge parent branch (0248f24)
* merge parent branch (5e03161)
* merge parent branch (418a4b5)
* merge parent branch (869218b)
* merge parent branch (c12b99a)
* merge parent branch (010d0b5)
* merge parent branch (08a5f3c)
* merge parent branch (e20d668)
* merge parent branch (7cbbc4d)
2016-09-28 Gustavo Pichorim Boiko
* Fix the crash in one more place. (c170873)
* Fix the crash in one more place. (de6b80b)
* Do not try to access the roles interface when not available
(df9f925)
* Do not try to access the roles interface when not available
(fa6c392)
2016-09-26 Roberto Mier Escandon
* removed traces (29af378)
* removed traces (6f4290c)
2016-09-22 Roberto Mier Escandon
* added copyright for new files (34a97e3)
* added copyright for new files (2d06b84)
2016-09-21 Roberto Mier Escandon
* updated plugin to have independant roles management (3fdcf0e)
* updated plugin to have independant roles management (1dc69fb)
* updated interface to get properties syncronously (298bc56)
* updated interface to get properties syncronously (dfde7b9)
* first success (fc824e2)
* first success (e6211d2)
2016-09-20 Roberto Mier Escandon
* tracing properties and event (6d9c254)
* tracing properties and event (8870925)
* merged prereq lp:~phablet-team/history-service/end-group-info-event
(8fb7a94)
* merged prereq lp:~phablet-team/history-service/end-group-info-event
(31cf656)
2016-09-19 Roberto Mier Escandon
* implemented roles interface client (59df643)
* implemented roles interface client (f25858e)
2016-09-19 Gustavo Pichorim Boiko
* Adapt the registration of objects and services to the way QtDBus
works from 5.6.x on. (b8f7b0e)
* Adapt the registration of objects and services to the way QtDBus
works from 5.6.x on. (a23a6e7)
* Merge parent branch (e4b2658)
* Merge parent branch (31dbc7f)
2016-09-19 Roberto Mier Escandon
* fixed (c79e6d5)
* fixed (6516b35)
2016-09-16 Roberto Mier Escandon
* move LastEventRole to be the last one in the enum (16ac747)
* move LastEventRole to be the last one in the enum (7822e98)
* added subjectAsAlias event model role to translate contact
id<->alias before showing, to avoid having id some
milliseconds before showing the alias added sender as
parameter for info events just in case event needs two
actors (source and destination of the action) (1374ecb)
* added subjectAsAlias event model role to translate contact
id<->alias before showing, to avoid having id some
milliseconds before showing the alias added sender as
parameter for info events just in case event needs two
actors (source and destination of the action) (5cbf7ca)
2016-09-15 Roberto Mier Escandon
* implemented event information for invited people (9d71238)
* implemented event information for invited people (58d903d)
2016-09-14 Roberto Mier Escandon
* merged parent branch (6d14842)
* merged parent branch (5b97f8b)
* differenciate self leaving from self kicked (28c448c)
* differenciate self leaving from self kicked (b66eb99)
* merged prereq branch
lp:~phablet-team/history-service/improve_information_events
(f4d6b1e)
* merged prereq branch
lp:~phablet-team/history-service/improve_information_events
(d79021c)
2016-09-09 Tiago Salem Herrmann
* export flags and fix missing properties (393763b)
* export flags and fix missing properties (c0c648a)
* Change information event types (5b75966)
* Change information event types (b938c50)
2016-09-09 Gustavo Pichorim Boiko
* Re-enable DaemonTests (82b597b)
* Re-enable DaemonTests (39e1dee)
2016-09-09 Bileto Bot
* Releasing 0.1+16.10.20160909.1-0ubuntu1 (15044fd)
* Releasing 0.1+16.10.20160909.1-0ubuntu1 (a499313)
2016-09-09 Gustavo Pichorim Boiko
* Temporarily disable DaemonTest until we get QtDBus fixed. (919fba0)
* Temporarily disable DaemonTest until we get QtDBus fixed. (350a94a)
* Temporarily disable DaemonTest until we get QtDBus fixed. (c70091f)
* Temporarily disable DaemonTest until we get QtDBus fixed. (d581f4e)
2016-09-06 Tiago Salem Herrmann
* merge parent branch (418669f)
* merge parent branch (912bfeb)
2016-09-06 Roberto Mier Escandon
* use subject interface instead of roomconfig one to manage the title
(61f2f0d)
* use subject interface instead of roomconfig one to manage the title
(1ac7d65)
* fix update schema sentences (1fbc93b)
* fix update schema sentences (0b2df63)
* added schema changes (6709c8d)
* added schema changes (dd8eb48)
2016-09-01 Roberto Mier Escandon
* managed roles to write admin ownership event information (037ad9d)
* managed roles to write admin ownership event information (268dd11)
* added self roles field to chatRoomInfo (bc34ad0)
* added self roles field to chatRoomInfo (c4afa1e)
* added information event for group change (273a48a)
* added information event for group change (7aa4455)
* finished imple and tested members fluctuation (59881d2)
* finished imple and tested members fluctuation (4117e90)
* added some comments (d3dd899)
* added some comments (a2046bb)
* show join event notification only when really joining, not when
creating the group or the thread (1260aa8)
* show join event notification only when really joining, not when
creating the group or the thread (ecaa8fc)
2016-08-31 Roberto Mier Escandon
* initial code for members fluctuation messages (13f53cd)
* initial code for members fluctuation messages (d37aa3b)
2016-08-29 Tiago Salem Herrmann
* merge parent branch (8f45aed)
* merge parent branch (95e735b)
* skip update if no properties are found (d6ab1b0)
* skip update if no properties are found (0970652)
2016-08-26 Tiago Salem Herrmann
* merge parent branch (5d46ce9)
* merge parent branch (fb3148a)
* remove pending members from participants (27458e3)
* remove pending members from participants (9a96822)
2016-08-26 Roberto Mier Escandon
* changed 'not' to ! (b9cf2b3)
* changed 'not' to ! (757c469)
* ?? (bded82e)
* ?? (b495b7e)
* check that thread is not empty (6b2a105)
* check that thread is not empty (526fc6d)
* check that thread is not empty (b169c6d)
* check that thread is not empty (bd5518d)
* rolledback not needed changes (a5a7736)
* rolledback not needed changes (3f5f31c)
* simplified solution (9ce1e94)
* simplified solution (eae9d0c)
2016-08-25 Tiago Salem Herrmann
* set state as well (425074d)
* set state as well (2df190a)
2016-08-26 Roberto Mier Escandon
* logical try to get the close event in history daemon in order to
write related event (da86164)
* logical try to get the close event in history daemon in order to
write related event (5acfa3b)
2016-08-25 Tiago Salem Herrmann
* Export Roles to qml (ef2d915)
* Export Roles to qml (c0d1037)
* add support for contact roles (66f854c)
* add support for contact roles (1e202f8)
2016-08-23 Tiago Salem Herrmann
* add state to participants (4b8a7da)
* add state to participants (7254ec2)
2016-08-18 Tiago Salem Herrmann
* avoid adding invalid values into the map (4bcfcac)
* avoid adding invalid values into the map (4eaf15a)
2016-08-17 Tiago Salem Herrmann
* set ChatRoomInfo to new threads (3da6699)
* set ChatRoomInfo to new threads (841e7a8)
2016-08-16 Tiago Salem Herrmann
* set Requested = true so other clients know if the channel is new
and requested or not (c41a889)
* set Requested = true so other clients know if the channel is new
and requested or not (598c640)
* compile agains new qt (5d43531)
* compile agains new qt (9b831e3)
2016-07-11 Gustavo Pichorim Boiko
* Merge trunk (f490612)
* Merge trunk (fe68c01)
* Remove unwanted debug (ddf500c)
* Remove unwanted debug (8f5234f)
* Make sure empty threads have a reasonable timestamp and show in the
right position on the list. (5b0de86)
* Make sure empty threads have a reasonable timestamp and show in the
right position on the list. (fc7737f)
* Fix packaging for crossbuilding. (e88488a)
* Fix packaging for crossbuilding. (2b6d8d6)
* Make sure new threads get a good timestamp. (9fdb0e7)
* Make sure new threads get a good timestamp. (b11c869)
* Make sure we only insert the information event once in the thread
when joining a group chat. (6d13d51)
* Make sure we only insert the information event once in the thread
when joining a group chat. (ab4a44c)
2016-07-09 Tiago Salem Herrmann
* Avoid reverting status of messages (7b55229)
* Avoid reverting status of messages (db5deea)
2016-07-08 Gustavo Pichorim Boiko
* Update the room properties when we get the channel for it.
(ebae119)
* Update the room properties when we get the channel for it.
(a74cfab)
* As a temporary fix, insert an event telling the user he joined a
group. (f9d7518)
* As a temporary fix, insert an event telling the user he joined a
group. (a7f2c76)
* Do not wait for the DBus async calls to finish (doing
processEvents() in between). It causes inconsistencies and
crashes in history-daemon. Use
QDBusAbstractInterface::call instead. (3e2422a)
* Do not wait for the DBus async calls to finish (doing
processEvents() in between). It causes inconsistencies and
crashes in history-daemon. Use
QDBusAbstractInterface::call instead. (9ba9441)
2016-07-06 Gustavo Pichorim Boiko
* Fix returning threads with no participants. (ff11889)
* Fix returning threads with no participants. (3a0f4f0)
2016-07-05 Tiago Salem Herrmann
* use macros and fill pending participants list correctly (f9c069e)
* use macros and fill pending participants list correctly (9bf27ce)
2016-07-05 Florian Boucault
* Fix packaging for crossbuilding. (1f7609d)
* Fix packaging for crossbuilding. (30c6bf0)
2016-07-04 Tiago Salem Herrmann
* Rename types (03c92d9)
* Rename types (6bab4a1)
* add support for local and remote pending member lists (e3e64f2)
* add support for local and remote pending member lists (b4f31ec)
2016-06-28 Tiago Salem Herrmann
* merge trunk (3d9f2da)
* merge trunk (940e333)
2016-06-27 Gustavo Pichorim Boiko
* Fix tests. (884fbb8)
* Fix tests. (452f50d)
2016-06-17 Gustavo Pichorim Boiko
* Add option sqlite command tracing (13f1cb7)
* Handle waiting of asyncronous interface properties correctly to
avoid crashes. (ec3ee93)
* Handle waiting of asyncronous interface properties correctly to
avoid crashes. (99ee3e4)
* Add missing specs. (6319544)
* Add missing specs. (78e5649)
* Add one missing rollback. (8ed8580)
* Add one missing rollback. (0987316)
* Make sure related queries are run in a transaction. (6ed1e39)
* Make sure related queries are run in a transaction. (b4fb90c)
* Update copyright headers (ce629a2)
* Update copyright headers (90488cc)
2016-06-15 Gustavo Pichorim Boiko
* Get the interfaces' properties using the class methods instead of
calling dbus directly. (7ada560)
* Get the interfaces' properties using the class methods instead of
calling dbus directly. (c6eb7aa)
2016-05-30 Tiago Salem Herrmann
* fix member change signaling (fb90c31)
* fix member change signaling (610b3ad)
* Force chatType for legacy method calls (9eeddd3)
* Force chatType for legacy method calls (9800ffa)
2016-05-30 Gustavo Pichorim Boiko
* Fix build. (06962a4)
* Fix build. (8c88c8c)
* When checking which threads to group, discard the ones we know
should not be grouped. (494ec5b)
* When checking which threads to group, discard the ones we know
should not be grouped. (e587cdd)
* Update copyright header (e940acf)
* Update copyright header (3f4cb80)
* Fix the condition for grouping multimedia accounts. (b82d76c)
* Fix the condition for grouping multimedia accounts. (4dae67f)
2016-05-30 Tiago Salem Herrmann
* set chatType to 1 (Contact) for existing ofono 1-1 chats. Leave mms
group chats as 0 (None). (0157bee)
* set chatType to 1 (Contact) for existing ofono 1-1 chats. Leave mms
group chats as 0 (None). (ce62634)
2016-05-27 Gustavo Pichorim Boiko
* Use another condition to determine when to group multimedia
threads. (ceda08a)
* Use another condition to determine when to group multimedia
threads. (56f2338)
* Make sure we don't group threads of chat rooms with one member
(4db77b5)
* Make sure we don't group threads of chat rooms with one member
(9ddd682)
* Fix selecting participants (5146ad8)
* Fix selecting participants (00d86d7)
2016-05-26 Gustavo Pichorim Boiko
* Make sure we don't return chat rooms in threadForParticipants()
(86c571f)
* Make sure we don't return chat rooms in threadForParticipants()
(b1be399)
2016-05-23 Gustavo Pichorim Boiko
* Remove messages that were superseded. (1975bef)
* Remove messages that were superseded. (d007e74)
2016-05-23 Tiago Salem Herrmann
* update thread participants (455c6dd)
* update thread participants (d7b2b84)
2016-05-19 Tiago Salem Herrmann
* do not allow inserting into chat_room_info if threadId or accountId
are empty (a55a1f1)
* do not allow inserting into chat_room_info if threadId or accountId
are empty (43a562e)
2016-05-18 Tiago Salem Herrmann
* remove chat_room_info when thread is removed (848c51e)
* remove chat_room_info when thread is removed (aa838ae)
* do not update room info if no accountId or threadId is provided
(9872bf4)
* do not update room info if no accountId or threadId is provided
(d58c4b6)
2016-05-13 Gustavo Pichorim Boiko
* Expose the chat type to QML. (2af7700)
* Expose the chat type to QML. (28724fd)
2016-05-06 Tiago Salem Herrmann
* do not group multimedia group chats (177250f)
* do not group multimedia group chats (275e855)
2016-04-27 Tiago Salem Herrmann
* use participantIds instead of participants (0f65c38)
* use participantIds instead of participants (211d5a5)
* add FieldParticipantIds (9febf1c)
* add FieldParticipantIds (76f969f)
2016-04-25 Tiago Salem Herrmann
* convert qvariant to qstringlist (cb66ca4)
* convert qvariant to qstringlist (eb05845)
2016-04-25 CI Train Bot
* Releasing 0.1+16.04.20160425-0ubuntu1 (d7fdf20)
* Releasing 0.1+16.04.20160425-0ubuntu1 (c351757)
2016-04-25 Gustavo Pichorim Boiko
* Make sure Telepathy types are always initialized.
Fixes: #1563050
Approved by: PS Jenkins bot (07dc46b)
* Make sure Telepathy types are always initialized.
Fixes: #1563050
Approved by: PS Jenkins bot (3a3ad17)
2016-04-20 Tiago Salem Herrmann
* Expose alias to qml (d72bbf0)
* Expose alias to qml (acf6b42)
2016-04-18 Tiago Salem Herrmann
* remove debug (c9849d5)
* remove debug (4397a6f)
* check if interfaces are available before using them (5592d55)
* check if interfaces are available before using them (9c9d533)
* fix expose chatRoomInfo to qml (11dc206)
* fix expose chatRoomInfo to qml (0f3160e)
* Add chatType to model (942c35d)
* Add chatType to model (8747f7f)
2016-04-15 Tiago Salem Herrmann
* Initial chat room support (ce99296)
* Initial chat room support (284a42a)
2016-03-30 Gustavo Pichorim Boiko
* Add unit test. (7ccc1ca)
* Add unit test. (cea96c5)
* Make sure Telepathy types are always initialized. (ddcdf72)
* Make sure Telepathy types are always initialized. (87909ba)
2016-01-04 CI Train Bot
* Releasing 0.1+16.04.20160104-0ubuntu1 (65669e8)
* Releasing 0.1+16.04.20160104-0ubuntu1 (c3f2340)
2016-01-04 Tiago Salem Herrmann
* Do proper dbus demarshalling of detailProperties.
Fixes: #1510655
(abe2e90)
* Do proper dbus demarshalling of detailProperties.
Fixes: #1510655
(049827d)
* do proper dbus demarshalling of detailProperties (48c654a)
* do proper dbus demarshalling of detailProperties (c64598e)
2015-12-07 CI Train Bot
* Releasing 0.1+16.04.20151207-0ubuntu1 (71dd011)
* Releasing 0.1+16.04.20151207-0ubuntu1 (35fbc65)
2015-12-07 Tiago Salem Herrmann
* Fix build with new qt on xenial-proposed. (7f3f7d5)
* Fix build with new qt on xenial-proposed. (28e0d75)
* Mark messages as read on onMessageRead().
Fixes: #1373059 Approved
by: Gustavo Pichorim Boiko (a882aa0)
* Mark messages as read on onMessageRead().
Fixes: #1373059 Approved
by: Gustavo Pichorim Boiko (d44acb6)
* Allow removing empty threads
Fixes: #1517602 Approved by: PS
Jenkins bot, Gustavo Pichorim Boiko (963c8c6)
* Allow removing empty threads
Fixes: #1517602 Approved by: PS
Jenkins bot, Gustavo Pichorim Boiko (491e242)
2015-12-03 Tiago Salem Herrmann
* fix variable name (cf421b0)
* fix variable name (887901c)
2015-11-20 Tiago Salem Herrmann
* merge parent branch (5e575c3)
* merge parent branch (fe2ca24)
* fix broken test (89aad9a)
* fix broken test (86dadfa)
* merge fix-1517602 branch (b962be8)
* merge fix-1517602 branch (7ad47bb)
* use the right token (87d4617)
* use the right token (5986a32)
* Mark messages as read on onMessageRead() (867423f)
* Mark messages as read on onMessageRead() (56e7693)
* make sure FieldNewEvent is always bool (f775e98)
* make sure FieldNewEvent is always bool (6a6b7f5)
2015-11-19 Tiago Salem Herrmann
* Allow removing empty threads (2ec4acd)
* Allow removing empty threads (b2e6f51)
2015-11-03 CI Train Bot
* Releasing 0.1+16.04.20151103-0ubuntu1 (3f3309f)
* Releasing 0.1+16.04.20151103-0ubuntu1 (09c6bc6)
2015-11-03 Tiago Salem Herrmann
* Enable cross compiling. Approved by: PS Jenkins bot (ea3d677)
* Enable cross compiling. Approved by: PS Jenkins bot (2e83c96)
* merge trunk (f4a4900)
* merge trunk (18bff2d)
2015-10-20 CI Train Bot
* Releasing 0.1+15.10.20151020.1-0ubuntu1 (d656105)
* Releasing 0.1+15.10.20151020.1-0ubuntu1 (bcc80ab)
2015-10-20 Gustavo Pichorim Boiko
* Store threads' timestamps in UTC in the cache, and convert only
when returning to the client, so that it has the most
up-to-date local time. Approved by: PS Jenkins bot
(65e2678)
* Store threads' timestamps in UTC in the cache, and convert only
when returning to the client, so that it has the most
up-to-date local time. Approved by: PS Jenkins bot
(e4689d0)
* Move the classes from historyprivate static library to
libhistoryservice itself and just keep their header files
private. Approved by: Tiago Salem Herrmann, PS Jenkins bot
(4eaacc3)
* Move the classes from historyprivate static library to
libhistoryservice itself and just keep their header files
private. Approved by: Tiago Salem Herrmann, PS Jenkins bot
(306a0e1)
* Request contact information for all known participants on
history-daemon initialization, and use this cached
information on the models. Approved by: Tiago Salem
Herrmann, PS Jenkins bot (abc6d56)
* Request contact information for all known participants on
history-daemon initialization, and use this cached
information on the models. Approved by: Tiago Salem
Herrmann, PS Jenkins bot (77e6598)
2015-10-20 Tiago Salem Herrmann
* Initial cache implementation for grouped conversations. Approved
by: PS Jenkins bot, Gustavo Pichorim Boiko (d4ebdde)
* Initial cache implementation for grouped conversations. Approved
by: PS Jenkins bot, Gustavo Pichorim Boiko (2897a92)
* - Set max count hint - Don't use fallback to tel to avoid queries
to the address-book-service with null filters Approved by:
PS Jenkins bot, Gustavo Pichorim Boiko (ad59781)
* - Set max count hint - Don't use fallback to tel to avoid queries
to the address-book-service with null filters Approved by:
PS Jenkins bot, Gustavo Pichorim Boiko (ee6580c)
2015-10-20 Gustavo Pichorim Boiko
* Optimize the thread matching by avoiding some phone number
formatting and validating.
Fixes: #1488988 Approved by:
Tiago Salem Herrmann, PS Jenkins bot (5f5b407)
* Optimize the thread matching by avoiding some phone number
formatting and validating.
Fixes: #1488988 Approved by:
Tiago Salem Herrmann, PS Jenkins bot (78e8e05)
* Make it possible to use the custom functions defined by the sqlite
plugin in the schema files themselves. Approved by: Tiago
Salem Herrmann, PS Jenkins bot (074dc63)
* Make it possible to use the custom functions defined by the sqlite
plugin in the schema files themselves. Approved by: Tiago
Salem Herrmann, PS Jenkins bot (45d9cf7)
* Store threads' timestamps in UTC in the cache, and convert only
when returning to the client, so that it has the most
up-to-date local time. (053db50)
* Store threads' timestamps in UTC in the cache, and convert only
when returning to the client, so that it has the most
up-to-date local time. (36b3bf7)
2015-10-13 Gustavo Pichorim Boiko
* Remove unused include statement. (57a02d5)
* Remove unused include statement. (857cddb)
* Merge parent. (cb0f0fa)
* Merge parent. (bae4b6c)
* Fix grouping events. (66c1e6f)
* Fix grouping events. (b46875b)
2015-10-13 Tiago Salem Herrmann
* file not needed (042f81e)
* file not needed (6c49b7c)
* Enable cross compiling (2b68014)
* Enable cross compiling (7a1ad65)
2015-10-09 Gustavo Pichorim Boiko
* Merge parent branch (c0d418e)
* Merge parent branch (1b90ebe)
* Add a comment explaining why the upstart configuration is
activating history-daemon via dbus (de5813b)
* Add a comment explaining why the upstart configuration is
activating history-daemon via dbus (f2c12e0)
2015-10-08 Gustavo Pichorim Boiko
* Merge parent changes (caaaf03)
* Merge parent changes (06d1573)
* Use QVariantMap directly. (fda004c)
* Use QVariantMap directly. (6baa324)
* Merge latest changes from parent. (d3667c2)
* Merge latest changes from parent. (90f2215)
* Merge parent branch (e88930b)
* Merge parent branch (2527475)
* Merge latest changes from parent branch. (bc8fda6)
* Merge latest changes from parent branch. (484fe38)
* Make it possible to fetch threads from QML. (98d9679)
* Make it possible to fetch threads from QML. (0553c55)
2015-10-08 Tiago Salem Herrmann
* replace QList by History::Threads (f5e157e)
* replace QList by History::Threads (6b321f8)
* change "lastEventTimestamp" by History::FieldLastEventTimestamp
(1130afb)
* change "lastEventTimestamp" by History::FieldLastEventTimestamp
(6e61bdb)
* - overload generateThreadMapKey(QString,QString) - remove unused
Q_DECLARE_METATYPE (d297b9f)
* - overload generateThreadMapKey(QString,QString) - remove unused
Q_DECLARE_METATYPE (87c0c6b)
* add fixme (a4ecf44)
* add fixme (f414a36)
* create History::FieldGroupingProperty and use as applicable
(1adf934)
* create History::FieldGroupingProperty and use as applicable
(abed7f3)
2015-10-07 Gustavo Pichorim Boiko
* Merge changes from parent branch. (cb39a11)
* Merge changes from parent branch. (c60b864)
* Merge changes from parent branch. (08e473c)
* Merge changes from parent branch. (13f7419)
2015-10-07 Tiago Salem Herrmann
* Use QVariantList instead of QList (144542b)
* Use QVariantList instead of QList (1f1c344)
* check if FieldGroupedThreads is present before iterating threads
(95f0189)
* check if FieldGroupedThreads is present before iterating threads
(9db91fd)
2015-10-07 Gustavo Pichorim Boiko
* Merge latest changes from parent branch. (bc87518)
* Merge latest changes from parent branch. (2e97ef1)
* Check if the map entries have a contactId before checking the value
to avoid inserting null QVariant values in it. (1a12030)
* Check if the map entries have a contactId before checking the value
to avoid inserting null QVariant values in it. (d282e96)
2015-10-06 Gustavo Pichorim Boiko
* Move ChannelObserver to History namespace. (a80d853)
* Move ChannelObserver to History namespace. (be90395)
* Move ContactMatcher to History namespace. (16f6ce1)
* Move ContactMatcher to History namespace. (b37427a)
* Move PhoneUtils to History namespace. (1fea5fa)
* Move PhoneUtils to History namespace. (9236c21)
* Move TelepathyHelper to the History namespace. (3028b4f)
* Move TelepathyHelper to the History namespace. (0547ea0)
2015-10-05 Gustavo Pichorim Boiko
* Merge changes from parent. (5b29d3f)
* Merge changes from parent. (929fe41)
* Merge latest changes from parent. (fb351b1)
* Merge latest changes from parent. (0400b9c)
2015-10-05 Tiago Salem Herrmann
* fix comment (60c1f46)
* fix comment (1cbf550)
* Fix empty thread removal and improve tests (9f10267)
* Fix empty thread removal and improve tests (c5c3274)
2015-10-05 Gustavo Pichorim Boiko
* Merge parent branch. (c56bf29)
* Merge parent branch. (84c9248)
* Merge changes from parent branch. (9c96f31)
* Merge changes from parent branch. (196eb8b)
* Add tests for participants. (cad7c7f)
* Add tests for participants. (f31279b)
2015-10-05 Tiago Salem Herrmann
* Add tests (2b7706c)
* Add tests (a92cb74)
* improve performance a bit (1c2c576)
* improve performance a bit (45beb22)
2015-10-02 Gustavo Pichorim Boiko
* Merge parent branch. (7c2b128)
* Merge parent branch. (1d4fe57)
* Test the new code added to contactmatcher. (9f35f79)
* Test the new code added to contactmatcher. (0454bb5)
* Merge parent branch (7dc71f1)
* Merge parent branch (8eb56bc)
* Re-enable tests. (a8f8705)
* Re-enable tests. (86e7c1a)
* Merge parent branch. (dd356b7)
* Merge parent branch. (316ee68)
* Remove some code that would cause a wrong contact match on new
contacts added. (b585b92)
* Remove some code that would cause a wrong contact match on new
contacts added. (e911e07)
* Merge latest changes from parent. (f829106)
* Merge latest changes from parent. (5535595)
* Merge latest changes from parent. (56dee99)
* Merge latest changes from parent. (89f222b)
2015-10-02 Tiago Salem Herrmann
* merge parent branch (a812255)
* merge parent branch (29e8cdc)
* merge parent branch (7ee6bee)
* merge parent branch (751e72e)
2015-10-02 Gustavo Pichorim Boiko
* Change the way we store the normalized ID when creating new
threads. (f0342db)
* Change the way we store the normalized ID when creating new
threads. (a23c6b2)
* Merge latest changes from parent. (31a547b)
* Merge latest changes from parent. (2ee1037)
* Ignore events that don't have a threadId or an eventId. (fe6c0ef)
* Ignore events that don't have a threadId or an eventId. (45c0fa1)
* Merge latest changes from parent. (c3c6103)
* Merge latest changes from parent. (c8c9ce6)
* Fix some tests. (4f21357)
* Fix some tests. (311e129)
2015-10-02 Tiago Salem Herrmann
* Skip empty threadIds Make a copy of conversationKey to avoid
crashes (f8c3de9)
* Skip empty threadIds Make a copy of conversationKey to avoid
crashes (1fa9008)
2015-10-01 Gustavo Pichorim Boiko
* Merge latest changes from parent branch. (05aa896)
* Merge latest changes from parent branch. (dfaa1d7)
* Make sure the views don't get invalid content when the service gets
restarted. (a640f36)
* Make sure the views don't get invalid content when the service gets
restarted. (b180d08)
* Merge latest changes from parent branch. (3a34e3c)
* Merge latest changes from parent branch. (23c564f)
* Revert the previous change, keeping the senderId role pointing to
just the ID, and add one extra "sender" role to have the
full contact info. (479941f)
* Revert the previous change, keeping the senderId role pointing to
just the ID, and add one extra "sender" role to have the
full contact info. (dcba497)
* Send the contact info for the sender too. (52fd319)
* Send the contact info for the sender too. (e57fb59)
* Merge latest changes from parent branch. (a085cb2)
* Merge latest changes from parent branch. (b0c37bb)
* There is no need to wait for the backend to be initialised anymore,
the DBus interface is only exposed after the cache is
ready. (4816c54)
* There is no need to wait for the backend to be initialised anymore,
the DBus interface is only exposed after the cache is
ready. (39b932a)
2015-09-30 Gustavo Pichorim Boiko
* Register the DBus interface only after the cache is already
generated. (c6285d6)
* Register the DBus interface only after the cache is already
generated. (ea00747)
* Return just the ID for the remote participant. We don't need the
full contact info there. (5793202)
* Return just the ID for the remote participant. We don't need the
full contact info there. (1a9c4be)
* Merge latest changes from parent branch. (6f7a05e)
* Merge latest changes from parent branch. (53c9b1e)
* Merge latest changes from parent branch. (39511bc)
* Merge latest changes from parent branch. (c6b0d75)
2015-09-30 Tiago Salem Herrmann
* update cache when events are removed as well (54ee165)
* update cache when events are removed as well (7f21afb)
2015-09-30 Gustavo Pichorim Boiko
* Add some debug to check cache generation time. (5de95b8)
* Add some debug to check cache generation time. (771c9a2)
* Fix detecting cache entries that have contact matches already.
(3881fa7)
* Fix detecting cache entries that have contact matches already.
(dfe38c4)
* Merge parent branch. (1362b0c)
* Merge parent branch. (d49974c)
* Merge parent branch. (ed96108)
* Merge parent branch. (4f185fd)
2015-09-30 Tiago Salem Herrmann
* Test all threads, as one participant might be in another as a group
chat participant (1447242)
* Test all threads, as one participant might be in another as a group
chat participant (f35d8fc)
2015-09-30 Gustavo Pichorim Boiko
* Merge latest changes from parent branch. (6dcbf39)
* Merge latest changes from parent branch. (6e2111b)
* Merge latest changes from parent branch. (bb226db)
* Merge latest changes from parent branch. (f115cfe)
2015-09-29 Tiago Salem Herrmann
* use own thread to compare when there are no grouped threads
(b0d84ca)
* use own thread to compare when there are no grouped threads
(5e94dfa)
2015-09-29 Gustavo Pichorim Boiko
* Make sure history-service gets autostarted after
address-book-service. As there is the risk of it getting
dbus-activated before the address-book-service is started
(in case an SMS comes in when you boot the phone), make
sure that the contact info cache gets regenerated when
address-book-service starts/stops (6ad9d59)
* Make sure history-service gets autostarted after
address-book-service. As there is the risk of it getting
dbus-activated before the address-book-service is started
(in case an SMS comes in when you boot the phone), make
sure that the contact info cache gets regenerated when
address-book-service starts/stops (631cf7e)
* Return the participants list correctly when creating new threads.
(d7c3e75)
* Return the participants list correctly when creating new threads.
(4623443)
* Merge latest changes from parent branch. (8feb154)
* Merge latest changes from parent branch. (758fb12)
* Merge more changes from parent branch. (67b33fe)
* Merge more changes from parent branch. (a599ad6)
* Merge latest changes from parent branch. (91a76c4)
* Merge latest changes from parent branch. (209b840)
2015-09-29 Tiago Salem Herrmann
* compare using normalized ids (ac1b37f)
* compare using normalized ids (9a1d72b)
* update cache properly when threads are removed (4c51036)
* update cache properly when threads are removed (5f0582c)
* remove unused method (4d1e44e)
* remove unused method (fd024b4)
* keep accountId and threadId in memory. (0640de4)
* keep accountId and threadId in memory. (3766e81)
* remove old code (8b78e0d)
* remove old code (8975198)
2015-09-28 Gustavo Pichorim Boiko
* Merge latest changes from parent branch. (7e9c45b)
* Merge latest changes from parent branch. (4a96deb)
* Change Event and derived classes to use History::Participants
instead of QStringList. (0b90ccb)
* Change Event and derived classes to use History::Participants
instead of QStringList. (6cebe57)
* Wait for the plugin to report itself as initialised before
processing queries. (6b00130)
* Wait for the plugin to report itself as initialised before
processing queries. (2b24b51)
* Re-enable the code that watches for contact changes in the models.
(def1a07)
* Re-enable the code that watches for contact changes in the models.
(41312c7)
* Make it possible to store existent contact info when asking
ContactMatcher to watch for an identifier. (cc80019)
* Make it possible to store existent contact info when asking
ContactMatcher to watch for an identifier. (2d571b3)
* Merge latest changes from parent branch. (cf50561)
* Merge latest changes from parent branch. (8035cfd)
* Merge latest changes from parent branch. (192afa5)
* Merge latest changes from parent branch. (729bc6c)
2015-09-28 Tiago Salem Herrmann
* - use cache for getSingleThread when grouped - keep reverse map to
avoid comparing the entire list (3625899)
* - use cache for getSingleThread when grouped - keep reverse map to
avoid comparing the entire list (9ebb56e)
2015-09-28 Gustavo Pichorim Boiko
* Merge latest changes from parent branch. (30e7b38)
* Merge latest changes from parent branch. (619edcc)
* Store all identifiers, even if they belong to the same phone number
to speed up cache lookups. (4b1abf3)
* Store all identifiers, even if they belong to the same phone number
to speed up cache lookups. (e6c72c4)
* Expose the contact detail properties. (e995aef)
* Expose the contact detail properties. (fffe5ad)
* Do not do phone comparisons when we know there was a match.
(9cd236f)
* Do not do phone comparisons when we know there was a match.
(039e566)
* Move the classes from historyprivate static library to
libhistoryservice itself and just keep their header files
private. (40847f8)
* Move the classes from historyprivate static library to
libhistoryservice itself and just keep their header files
private. (8f0ecbe)
2015-09-25 Gustavo Pichorim Boiko
* Fix building. (a0da0eb)
* Fix building. (75dfe0d)
* Merge latest changes from parent branch (bda2813)
* Merge latest changes from parent branch (4a86a19)
2015-09-25 Tiago Salem Herrmann
* Remove debugs (a464e6d)
* Remove debugs (391fa0d)
* remove debugs update cache properly (d93ff94)
* remove debugs update cache properly (ec9561f)
* use the right property (4e6b15a)
* use the right property (efc990d)
2015-09-25 Gustavo Pichorim Boiko
* Add missing copyright header. (6c96aab)
* Add missing copyright header. (835be75)
2015-09-25 Tiago Salem Herrmann
* use the same schema as participants (d8a9b80)
* use the same schema as participants (11615b2)
2015-09-25 Gustavo Pichorim Boiko
* Disable tests for now. (ccee1b4)
* Disable tests for now. (25dd5a1)
* Fix the demarshalling from QVariantList (the internal element is a
variant, not the map itself). (8d85129)
* Fix the demarshalling from QVariantList (the internal element is a
variant, not the map itself). (77b7426)
* De-marshall QDBusArguments to retrieve the participants list.
(40bc1e9)
* De-marshall QDBusArguments to retrieve the participants list.
(181e373)
* Only generate the thread cache after matching the contacts. Also
remove duplicate participants from the result set before
asking for contact information. (d6b5d44)
* Only generate the thread cache after matching the contacts. Also
remove duplicate participants from the result set before
asking for contact information. (bf03ea8)
2015-09-24 Gustavo Pichorim Boiko
* Merge latest changes from parent branch (c564be4)
* Merge latest changes from parent branch (fb547e5)
* Add a message saying the failure output is expected during schema
generation. (bd058ef)
* Add a message saying the failure output is expected during schema
generation. (e81ab90)
* If the database is up-to-date, don't try to run an empty list of
statements. (bfd85b6)
* If the database is up-to-date, don't try to run an empty list of
statements. (ae0d782)
* Merge latest changes from parent branch (e0f67e9)
* Merge latest changes from parent branch (9f78876)
* Generate the cache only after telepathy is ready. (2a50b69)
* Generate the cache only after telepathy is ready. (adbeb0d)
2015-09-24 Tiago Salem Herrmann
* try dbus cast and then normal demarshling (92ac0e5)
* try dbus cast and then normal demarshling (07db693)
2015-09-23 Gustavo Pichorim Boiko
* Fix some more participants usage. (a65d4b0)
* Fix some more participants usage. (23c4aa4)
* Merge latest changes from parent branch. (c87c4d0)
* Merge latest changes from parent branch. (140c687)
* Quickly hack the history model so that it always use contact data
from the server for testing. (930aa0c)
* Quickly hack the history model so that it always use contact data
from the server for testing. (99ab7fd)
2015-09-23 Tiago Salem Herrmann
* Update cache and displayed thread (d955ffd)
* Update cache and displayed thread (467e111)
* also fill map with last event properties (a38f189)
* also fill map with last event properties (c755438)
2015-09-23 Gustavo Pichorim Boiko
* Start implementing contact matching/caching on the daemon side.
(7a2762e)
* Start implementing contact matching/caching on the daemon side.
(0af8b66)
2015-09-23 Tiago Salem Herrmann
* initial refactor of the model to use cache from service side
(95c579b)
* initial refactor of the model to use cache from service side
(a96ea4d)
* convert to properties before sending to dbus (5e3f08f)
* convert to properties before sending to dbus (1763d26)
* update historythreadmodel to the new groupedThreads property
(0f78b31)
* update historythreadmodel to the new groupedThreads property
(236ad95)
* Make getSingleThread return grouped threads as well (7deae81)
* Make getSingleThread return grouped threads as well (c3457ca)
* Return Thread object instead of QVariantMap (dfaf8fe)
* Return Thread object instead of QVariantMap (58d79a7)
2015-09-21 Tiago Salem Herrmann
* reenable tests (a2b0b9f)
* reenable tests (ae7ebce)
* move code that fills cache to a separate method (ff79a50)
* move code that fills cache to a separate method (cb9b52b)
* Use matchFlags to decide if phone comparison is needed (0526f6c)
* Use matchFlags to decide if phone comparison is needed (9a251c2)
* Use matchFlags to determine grouping (24be8aa)
* Use matchFlags to determine grouping (f1e7ecb)
* Pass a qvariantmap instead of a bool to be more flexible (7b59c72)
* Pass a qvariantmap instead of a bool to be more flexible (4794b3d)
* Avoid property name collision (38c4718)
* Avoid property name collision (00243a5)
* add shouldGroupAccount() (f42e996)
* add shouldGroupAccount() (2fa38b6)
2015-09-18 Tiago Salem Herrmann
* Add groupedThreads property to model/views (df07082)
* Add groupedThreads property to model/views (6612d02)
2015-09-17 Tiago Salem Herrmann
* Use descending order to create the cache (a132f9c)
* Use descending order to create the cache (a5ab742)
* initial cache implementation for optimization (2a91fce)
* initial cache implementation for optimization (a357544)
2015-09-14 Tiago Salem Herrmann
* merge parent branch (8d81464)
* merge parent branch (3678a05)
2015-09-10 Tiago Salem Herrmann
* Set max count hint and don't use fallback to tel to avoid queries
to the address-book-service with null filters (ad54198)
* Set max count hint and don't use fallback to tel to avoid queries
to the address-book-service with null filters (e5db4ed)
2015-09-03 Gustavo Pichorim Boiko
* Try a phone number that matches brazilian format. (d64f897)
* Try a phone number that matches brazilian format. (ad71b43)
* Add missing copyright header. (1bbdb6d)
* Add missing copyright header. (459bb71)
2015-09-02 Gustavo Pichorim Boiko
* Verify that the thread returned is not null on tests. (d425832)
* Verify that the thread returned is not null on tests. (5f0c9f8)
* Add missing copyright. (9c0b63a)
* Add missing copyright. (81d0b8c)
* Adjust a test to the new behavior. (6f2e976)
* Adjust a test to the new behavior. (cb2d0b5)
* Fix the normalization function. (66d75c1)
* Fix the normalization function. (81b36b4)
* Merge schema generation fixes. (87cff0d)
* Merge schema generation fixes. (ee85cd0)
* Make it possible to use the custom functions defined by the sqlite
plugin in the schema files themselves. (256abe0)
* Make it possible to use the custom functions defined by the sqlite
plugin in the schema files themselves. (a7c4bcb)
2015-08-28 Gustavo Pichorim Boiko
* Avoid useless copying of stringlists. (81147e9)
* Avoid useless copying of stringlists. (ebbab40)
* Clear the normalizedParticipants list before repopulating it.
(3179e4c)
* Clear the normalizedParticipants list before repopulating it.
(4cb6e7b)
* If the two numbers are the same, do not forward the query to
libphonenumber, just return true. (84bbd7f)
* If the two numbers are the same, do not forward the query to
libphonenumber, just return true. (3caebe1)
2015-08-28 CI Train Bot
* Releasing 0.1+15.10.20150828.1-0ubuntu1 (d49c9de)
* Releasing 0.1+15.10.20150828.1-0ubuntu1 (93d9dee)
2015-08-28 Gustavo Pichorim Boiko
* Do not override the build type. Also remove a block of unused code
from debian/rules. (f2a4b5e)
* Do not override the build type. Also remove a block of unused code
from debian/rules. (64a5b46)
* Prevent the history-daemon from crashing in the event of an ended
call not having any remote member.
Fixes: #1458990
Approved by: PS Jenkins bot, Tiago Salem Herrmann
(ac56333)
* Prevent the history-daemon from crashing in the event of an ended
call not having any remote member.
Fixes: #1458990
Approved by: PS Jenkins bot, Tiago Salem Herrmann
(406cb50)
* Fix flags. Approved by: PS Jenkins bot, Tiago Salem Herrmann
(fc83b4b)
* Fix flags. Approved by: PS Jenkins bot, Tiago Salem Herrmann
(33b94fa)
2015-08-28 Tiago Salem Herrmann
* Correctly set mCanFetchMore in the HistoryGroupedThreadsModel.
Approved by: PS Jenkins bot, Gustavo Pichorim Boiko
(638c480)
* Correctly set mCanFetchMore in the HistoryGroupedThreadsModel.
Approved by: PS Jenkins bot, Gustavo Pichorim Boiko
(de73a9a)
* Manually add self id to participants list if needed.
Fixes:
#1486187 Approved by: PS Jenkins bot, Gustavo Pichorim
Boiko (4317a3b)
* Manually add self id to participants list if needed.
Fixes:
#1486187 Approved by: PS Jenkins bot, Gustavo Pichorim
Boiko (b8ad820)
* - Generate eventId when there is none - Set status to "Accepted" if
the channel does not support delivery reports Approved by:
PS Jenkins bot, Gustavo Pichorim Boiko (0a00d18)
* - Generate eventId when there is none - Set status to "Accepted" if
the channel does not support delivery reports Approved by:
PS Jenkins bot, Gustavo Pichorim Boiko (66a8988)
2015-08-28 Gustavo Pichorim Boiko
* Merge trunk. (ea697a1)
* Merge trunk. (59b9e0f)
* Merge trunk. (71bce3f)
* Merge trunk. (c961168)
2015-08-27 Gustavo Pichorim Boiko
* Store the normalized ID when creating new threads. (8076404)
* Store the normalized ID when creating new threads. (deb68e3)
* Update copyright headers. (a2e6d13)
* Update copyright headers. (35334ac)
* Optimize the thread matching by avoiding some phone number
formatting and validating. (67eb40f)
* Optimize the thread matching by avoiding some phone number
formatting and validating. (0a2924c)
* Do not override the build type. Also remove a block of unused code
from debian/rules. (1c20c7e)
* Do not override the build type. Also remove a block of unused code
from debian/rules. (cd9ef68)
2015-08-19 CI Train Bot
* Releasing 0.1+15.10.20150819.2-0ubuntu1 (fbe3156)
* Releasing 0.1+15.10.20150819.2-0ubuntu1 (149db80)
2015-08-19 Gustavo Pichorim Boiko
* Fix tests on vivid. (2c99308)
* Fix tests on vivid. (269c2f2)
2015-08-19 Tiago Salem Herrmann
* Wait telepathy to be ready before querying address-book-service.
Fixes: #1485005 (ff441df)
* Wait telepathy to be ready before querying address-book-service.
Fixes: #1485005 (75b2cdb)
2015-08-19 Gustavo Pichorim Boiko
* Tweak the phone numbers used in tests in an attempt to make the
tests pass on vivid. (d9e51cc)
* Tweak the phone numbers used in tests in an attempt to make the
tests pass on vivid. (2882042)
* Attempt to fix tests on vivid. (42f9639)
* Attempt to fix tests on vivid. (2544302)
2015-08-18 Tiago Salem Herrmann
* wait telepathy to be ready before querying address-book-service
(7726a4b)
* wait telepathy to be ready before querying address-book-service
(47cb7fd)
2015-08-18 Gustavo Pichorim Boiko
* Merge trunk. (3cbe907)
* Merge trunk. (8c388d0)
2015-08-10 CI Train Bot
* Releasing 0.1+15.10.20150810-0ubuntu1 (946413b)
* Releasing 0.1+15.10.20150810-0ubuntu1 (b6b770d)
2015-08-10 Tiago Salem Herrmann
* Use libphonenumber for phone number validation, normalization and
comparison.
Fixes: #1471545, #1473028 Approved by: PS
Jenkins bot (b083390)
* Use libphonenumber for phone number validation, normalization and
comparison.
Fixes: #1471545, #1473028 Approved by: PS
Jenkins bot (dfe0cf0)
2015-07-31 Gustavo Pichorim Boiko
* Add missing gcc5 rebuild changelog. (f751874)
* Add missing gcc5 rebuild changelog. (295f1a9)
2015-07-31 Tiago Salem Herrmann
* Use libphonenumber for comparison only for numbers with more than 6
digits (78ca050)
* Use libphonenumber for comparison only for numbers with more than 6
digits (1766d28)
2015-07-17 Tiago Salem Herrmann
* Provide a fallback to country code if none is provided (314af6a)
* Provide a fallback to country code if none is provided (37b2f23)
2015-07-16 Tiago Salem Herrmann
* merge generate-eventId branch (24f30c8)
* merge generate-eventId branch (7398946)
2015-07-15 Tiago Salem Herrmann
* add libphonenumber as a dependency (c3c907c)
* add libphonenumber as a dependency (4030ec8)
* Use libphonenumber for phone comparison and normalization (368a1c4)
* Use libphonenumber for phone comparison and normalization (2c1cb93)
2015-07-13 Tiago Salem Herrmann
* make method static (a0863bf)
* make method static (b2d6618)
* move code to a separate method (127a491)
* move code to a separate method (cc2b511)
* Manually add self id to participants list if needed. (253a733)
* Manually add self id to participants list if needed. (6b69ccc)
2015-07-01 CI Train Bot
* Releasing 0.1+15.10.20150701-0ubuntu1 (8bb8e5a)
* Releasing 0.1+15.10.20150701-0ubuntu1 (658fec3)
2015-07-01 Tiago Salem Herrmann
* Update to telepathy-qt 0.9.6.1. (c709189)
* Update to telepathy-qt 0.9.6.1. (3408f8c)
2015-06-29 Tiago Salem Herrmann
* check if the received message belongs to the self contact (83e7573)
* check if the received message belongs to the self contact (000c22d)
2015-06-16 Tiago Salem Herrmann
* update to telepathy-qt 0.9.6.1 (dcea3b0)
* update to telepathy-qt 0.9.6.1 (9527573)
2015-05-27 Gustavo Pichorim Boiko
* Prevent the history-daemon from crashing in the event of an ended
call not having any remote member. (d04aa87)
* Prevent the history-daemon from crashing in the event of an ended
call not having any remote member. (72f31f4)
2015-05-19 Tiago Salem Herrmann
* add xvfb to qml tests (dcef4ea)
* add xvfb to qml tests (8de036c)
2015-05-18 Tiago Salem Herrmann
* use dbus (0682389)
* use dbus (561689f)
* remove unused modules (1ac49df)
* remove unused modules (cc69e59)
* test canFetchMore() (eee8a90)
* test canFetchMore() (d8e7ceb)
* use isEmpty() (e41a10b)
* use isEmpty() (2ab0f8d)
* Correctly set mCanFetchMore in the HistoryGroupedThreadsModel
(a9f8e0c)
* Correctly set mCanFetchMore in the HistoryGroupedThreadsModel
(79d7fe0)
2015-05-15 Gustavo Pichorim Boiko
* Fix flags. (9115efd)
* Fix flags. (fba8f8e)
2015-05-05 Tiago Salem Herrmann
* Add tests (ed57e6c)
* Add tests (ed8c696)
2015-05-01 Tiago Salem Herrmann
* Generate eventId when there is none Set status to "Accepted" if the
channel does not support delivery reports (9dc6cbb)
* Generate eventId when there is none Set status to "Accepted" if the
channel does not support delivery reports (0a4eb1c)
2015-04-28 CI Train Bot
* Releasing 0.1+15.04.20150428.1-0ubuntu1 (c4172b1)
* Releasing 0.1+15.04.20150428.1-0ubuntu1 (2aaad27)
2015-04-28 Gustavo Pichorim Boiko
* Fix a crash that was happening when matching new contacts. Also add
a unit test to make sure it doesn't happen again.
Fixes:
#1449662 Approved by: PS Jenkins bot (def3c29)
* Fix a crash that was happening when matching new contacts. Also add
a unit test to make sure it doesn't happen again.
Fixes:
#1449662 Approved by: PS Jenkins bot (a39824e)
* Fix contact removal info clearing too. (c555c9e)
* Fix contact removal info clearing too. (3fff870)
* Fix a crash that was happening when matching new contacts. Also add
a unit test to make sure it doesn't happen again.
(aeedc34)
* Fix a crash that was happening when matching new contacts. Also add
a unit test to make sure it doesn't happen again.
(aa8651f)
2015-04-09 CI Train Bot
* Releasing 0.1+15.04.20150409-0ubuntu1 (c2ad86d)
* Releasing 0.1+15.04.20150409-0ubuntu1 (8d763a6)
2015-04-09 Gustavo Pichorim Boiko
* Change the tests to use the same infrastructure as the one used in
telephony-service, and add some tests for the contact
matching changes. Approved by: PS Jenkins bot (8544319)
* Change the tests to use the same infrastructure as the one used in
telephony-service, and add some tests for the contact
matching changes. Approved by: PS Jenkins bot (4d16b25)
* Improve contact matching by accepting other addressable fields than
just phone numbers. Approved by: PS Jenkins bot (f3550c2)
* Fix contactmanager creation. (84195d6)
* Fix contactmanager creation. (0e80fe3)
* Get the correct field for the account protocol. (064554a)
2015-04-08 Gustavo Pichorim Boiko
* Fix compilation when srcdir != builddir (e543c11)
* Fix compilation when srcdir != builddir (9bbd408)
* Add some tests to the contact matcher. Still not much is covered.
(ec094c6)
* Add some tests to the contact matcher. Still not much is covered.
(8aa3d74)
* Fix the non-passing tests. (5d45e5d)
* Fix the non-passing tests. (f59e71f)
2015-04-07 Gustavo Pichorim Boiko
* Update history-service to use the same tests infrastructure as
telephony-service. (913b80d)
* Update history-service to use the same tests infrastructure as
telephony-service. (710f765)
2015-04-01 Gustavo Pichorim Boiko
* Initial round of changes to support accounts not based on phone
numbers. (bc328f1)
2015-03-30 Gustavo Pichorim Boiko
* Move the telepathy helper to a static library as it will now be
used in multiple places. (120af81)
2015-02-10 CI Train Bot
* Releasing 0.1+15.04.20150210-0ubuntu1 (b7a5cb6)
2015-02-10 Tiago Salem Herrmann
* - Add support for writing events from qml. - Iterate over
attachments when qdbus_cast fails.
Fixes: #1417353
Approved by: PS Jenkins bot (80972cf)
2015-02-09 Tiago Salem Herrmann
* check if qdbus_cast fails and try to demarshal the attachments by
hand (aaf195c)
2015-02-06 CI Train Bot
* Releasing 0.1+15.04.20150206.1-0ubuntu1 (d339db8)
2015-02-06 Tiago Salem Herrmann
* Add tools to populate the history database. (fb5ad44)
* update VoiceEvent signature (9f181da)
* merge trunk (3c8930a)
2015-02-05 Tiago Salem Herrmann
* add support for writing events from qml (da07fc4)
2015-01-28 CI Train Bot
* Releasing 0.1+15.04.20150128-0ubuntu1 (66341ed)
2015-01-28 Gustavo Pichorim Boiko
* Use QSqlQuery::bindValue() to pass filter arguments to the query to
prevent errors. (ab492ad)
* Store the number that was used to call a given voice event.
Fixes:
#1410500 Approved by: PS Jenkins bot (eeda018)
* Use QSqlQuery::bindValue() to pass filter arguments to the query to
prevent errors. (1b148b5)
2015-01-27 Gustavo Pichorim Boiko
* Merge latest changes from trunk (12d650b)
2015-01-25 CI Train Bot
* Releasing 0.1+15.04.20150125-0ubuntu1 (07c54d4)
2015-01-25 Gustavo Pichorim Boiko
* Make sure string filters are correctly escaped. Approved by: PS
Jenkins bot (02c4040)
* Use single quotes for string literals and escape the characters
properly. (7ad9fe7)
2015-01-24 Gustavo Pichorim Boiko
* Also escape partial matches. (79785d6)
* Make sure string filters are correctly escaped. (21c78b2)
2015-01-20 CI Train Bot
* Releasing 0.1+15.04.20150120-0ubuntu1 (15102df)
2015-01-20 Gustavo Pichorim Boiko
* Convert the filter to a string in the plugin itself and add support
for the MatchContains match flag.
Fixes: #1376793 Approved
by: PS Jenkins bot (2c0a7fa)
2015-01-16 Gustavo Pichorim Boiko
* Store the number that was used to call a given voice event.
(fe4fad1)
2015-01-08 Gustavo Pichorim Boiko
* Fix partial string matching. (fcc7021)
2015-01-07 Gustavo Pichorim Boiko
* Convert the filter to a string in the plugin itself and add support
for the MatchContains match flag. (fdc1f5c)
2015-01-06 CI Train Bot
* Releasing 0.1+15.04.20150106-0ubuntu1 (c75879c)
2015-01-06 Gustavo Pichorim Boiko
* Make it possible to delete multiple entries from QML.
Fixes:
#1404286 Approved by: PS Jenkins bot (482d146)
2015-01-05 Gustavo Pichorim Boiko
* Make it possible to delete multiple entries from QML. (cb700cb)
2014-11-10 CI bot
* Releasing 0.1+15.04.20141110-0ubuntu1 (9cb8633)
2014-11-10 Gustavo Pichorim Boiko
* Remove the tools and their dependencies: they are obsolete and not
useful anymore. Approved by: PS Jenkins bot (3d9daff)
* Save timestamps in UTC.
Fixes: 1379018 Approved by: PS Jenkins bot
(867c369)
2014-10-30 Tiago Salem Herrmann
* add tools to populate the history database (08116ee)
* merge remove_tools branch (331bb69)
2014-10-30 Gustavo Pichorim Boiko
* Re-add the tools directory, as it might be useful in the future,
just remove the tpl-import tool instead. (1f8ae60)
* Remove the tools and their dependencies: they are obsolete and not
useful anymore. (aef0dd8)
2014-10-22 Gustavo Pichorim Boiko
* Fix tests. (6874725)
2014-10-20 Gustavo Pichorim Boiko
* Update the existing timestamps to UTC. (1018fb3)
2014-10-17 Gustavo Pichorim Boiko
* Save new event timestamps in UTC. (78c70fe)
2014-10-09 Timo Jyrinki
* Manually merge 0.1+14.10.20141003-0ubuntu1 (af51e99)
2014-10-03 CI bot
* Releasing 0.1+14.10.20141003-0ubuntu1 (f1707f6)
2014-10-03 Tiago Salem Herrmann
* Add support for a new message Type: MessageTypeInformation
Fixes:
1356950 Approved by: Gustavo Pichorim Boiko (26685d1)
2014-09-25 Tiago Salem Herrmann
* fix broken test (d3790d6)
2014-09-24 Tiago Salem Herrmann
* remove unused method expose enum for MessageType to qml (aa217b1)
* add method to get item by eventId (13af6fd)
2014-09-23 Tiago Salem Herrmann
* convert time to string including miliseconds (dc212d1)
2014-09-22 Tiago Salem Herrmann
* use toHex() to convert to string (12c04d9)
* fix typo (ac1950b)
* initial support for information messageType (9749211)
2014-09-12 CI bot
* Releasing 0.1+14.10.20140912-0ubuntu1 (5ccf39a)
2014-09-12 Gustavo Pichorim Boiko
* If the models are used from QML, update the query right after the
component setup is finished. Approved by: PS Jenkins bot,
Tiago Salem Herrmann (0a90ef5)
* Keep the models sorted all the time, even when new events arrive.
Also replace the thread grouping proxy model by a real
model that groups threads. (439783a)
* Add support for matching contact info in the data models.
Fixes:
1362387 Approved by: Renato Araujo Oliveira Filho
(d5ce278)
2014-09-12 Tiago Salem Herrmann
* Skip messages with the "skip-storage" flag set
Fixes: 1340255
Approved by: Gustavo Pichorim Boiko, PS Jenkins bot
(d66cb8e)
* Create temporary tables in memory Approved by: Gustavo Pichorim
Boiko, PS Jenkins bot (3f7d519)
2014-09-12 Gustavo Pichorim Boiko
* Merge parent. (5f294c8)
* Revert the change to debian/control. (31ae263)
* Properly delete stuff on destruction. (14174f8)
* Use the predefined participants string. (f2e1d3f)
* Merge parent branch. (db845c2)
* Keep versioning number consistent. (7a33fc3)
* Remove leftover comment line. (d7fae77)
* Create the singleton using static memory to make sure it is
properly destroyed on app finishing, and make its
destructor private to prevent other places from removing
it. (96bae1f)
* Fix typo. (26290af)
* Invalidate the cache when the manager changes. (8057855)
2014-09-10 Gustavo Pichorim Boiko
* If the models are used from QML, update the query right after the
component setup is finished. (5cc9b97)
2014-09-10 Tiago Salem Herrmann
* skip messages with the "skip-storage" flag set (3c58569)
2014-09-09 Gustavo Pichorim Boiko
* Remove the sort proxy model. It is not needed anymore. (e07b4be)
* Turn the HistoryThreadGroupingProxyModel into a real model
operating directly on top of History::Threads. (b40fb85)
* Insert new events and threads sorted. (82b61b3)
* Return the shared roles in the grouped events model too. (9aba416)
* Move the positioning functions to the base class so that they can
be used by all models. (12504ad)
* Refactory the common code between the Thread and Event model into a
HistoryModel base class. (f122798)
* Fetch only the required data. (8be584a)
2014-09-08 Gustavo Pichorim Boiko
* Break long line. (abe759d)
* Add support for matching contact info in the data models. (5047436)
2014-09-03 Tiago Salem Herrmann
* use memory to create temporary tables (b5d4d09)
2014-08-21 CI bot
* Releasing 0.1+14.10.20140821.1-0ubuntu1 (708e0ea)
2014-08-21 Gustavo Pichorim Boiko
* Optimize the history-service by delaying the event and thread views
on the model until the properties are all set. Approved
by: PS Jenkins bot (edad673)
* Add a model that groups events that have happened in a contiguous
way. Approved by: PS Jenkins bot (468f4fd)
* Merge latest changes from parent. (b0df4c0)
* Check the upper bound too before accessing the QList. (b61e9e7)
* merge latest changes from parent. (fc7824d)
2014-08-20 Gustavo Pichorim Boiko
* Keep the grouped events list sorted. (a00da43)
2014-08-18 Gustavo Pichorim Boiko
* Merge latest changes from parent. (92c60e8)
* Merge latest changes from trunk. (caa1449)
2014-08-16 Gustavo Pichorim Boiko
* Merge latest changes from parent branch. (621fb3e)
* Make it possible to group by multiple properties at the same time.
(5a7424a)
2014-08-13 CI bot
* Releasing 0.1+14.10.20140813-0ubuntu1 (17f39d0)
2014-08-13 Renato Araujo Oliveira Filho
* Added "count" property for sortproxymodel; Added "get" function for
sortproxymodel; Approved by: Gustavo Pichorim Boiko, PS
Jenkins bot (0841e1b)
2014-08-13 Tiago Salem Herrmann
* Export canFetchMore to qml Approved by: Gustavo Pichorim Boiko, PS
Jenkins bot (4503a65)
2014-08-13 Gustavo Pichorim Boiko
* Optimize the history-service by delaying the event and thread views
on the model until the properties are all set. (3748a95)
2014-08-12 Gustavo Pichorim Boiko
* Handle events being added/modified/removed. (fd2038f)
* Add a model that displays the events grouped by a defined role
(650b444)
2014-08-07 Tiago Salem Herrmann
* export canFetchMore to qml (2f5df6d)
2014-08-06 Renato Araujo Oliveira Filho
* Added "count" property for sortproxymodel; Added "get" function for
sortproxymodel; (16bc653)
2014-07-30 CI bot
* Releasing 0.1+14.10.20140730-0ubuntu1 (982858c)
2014-07-30 Tiago Salem Herrmann
* Fix unreadCount update. Approved by: Gustavo Pichorim Boiko, PS
Jenkins bot (755dda7)
* also update voice events (e03981d)
2014-07-29 Tiago Salem Herrmann
* fix unreadCount update in triggers (3ad66a3)
2014-07-25 CI bot
* Releasing 0.1+14.10.20140725.1-0ubuntu1 (667b781)
2014-07-25 Tiago Salem Herrmann
* - fix attachments on thread queries - don't query the database for
null filters. Apps should use an empty filter if they want
to query the whole database - avoid performing queries
when the filter is null (7e5ec40)
* dont try to access the view if it is null (db7d717)
* remove debug (e5e0667)
* fix attachments on thread queries (babd3a7)
* don't query the database for null filters. apps should use an empty
filter if they wish to query the whole database (0e3b6d7)
* avoid performing queries when the filter is null (d03db5e)
2014-07-24 CI bot
* Releasing 0.1+14.10.20140724-0ubuntu1 (fd4b274)
2014-07-24 Tiago Salem Herrmann
* Multiple fixes to HistoryThreadGroupingProxyModel: - Update
grouping also on onDataChanged() - use
rowsAboutToBeRemoved() instead of rowsRemoved() to avoid
crashes - Do not emit dataChanged for removed indexes. -
Set participants on groupForEntry() so phone comparison
works Approved by: Gustavo Pichorim Boiko, PS Jenkins bot
(7ca44c0)
2014-07-22 Tiago Salem Herrmann
* remove debug (69e171d)
* do not setSourceModel() (7f3f7f7)
* more fixes (65bad5d)
* use rowsAboutToBeRemoved() instead of rowsRemoved() (c4679f4)
2014-07-21 Tiago Salem Herrmann
* more fixes (8563f59)
* remove unused code (c727643)
* use value from properties instead of method argument (96ed7a9)
2014-07-18 Tiago Salem Herrmann
* set participants or phone comparison will fail (4806e28)
* update grouping also on onDataChanged(), and the text event may not
be received at the same time as the thread (9f91b2c)
2014-07-17 CI bot
* Releasing 0.1+14.10.20140717.1-0ubuntu1 (06bb13d)
2014-07-17 Gustavo Pichorim Boiko
* Add a proxy model to allow grouping different threads into one.
Approved by: PS Jenkins bot, Tiago Salem Herrmann
(df5774b)
2014-07-15 Gustavo Pichorim Boiko
* Expose the threads to QML. (4deeb4d)
2014-07-14 Gustavo Pichorim Boiko
* Add missing include. (8124297)
* Add a proxy model to group threads from different accounts.
(064defb)
2014-07-01 CI bot
* Releasing 0.1+14.10.20140701-0ubuntu1 (bb7922e)
2014-07-01 Tiago Salem Herrmann
* Implement MMS sending support. (e0b4b1b)
2014-06-27 CI bot
* Releasing 0.1+14.10.20140627-0ubuntu1 (54ebbe3)
2014-06-27 Renato Araujo Oliveira Filho
* Export HistoryEventModel.[canFetchMore | fetchMore] to QML
(eab5bea)
2014-06-25 Tiago Salem Herrmann
* fix typo (0bbbaa8)
2014-06-24 Tiago Salem Herrmann
* merge trunk (764bef8)
2014-06-23 Renato Araujo Oliveira Filho
* Export HistoryEventModel.[canFetchMore | fetchMore] to QML
(8ec6553)
2014-06-19 CI bot
* Releasing 0.1+14.10.20140619-0ubuntu1 (3dea3eb)
2014-06-19 Renato Araujo Oliveira Filho
* Export property count and get to QML. (dddcbbd)
2014-06-19 Ken VanDine
* Added count and at functions to HistoryEventModel to simplify
getting single events from the model. (8ba7138)
* Renamed the at method to get and forward signals for countChanged
(f2de32e)
* simplied the "at" method as well as the countChanged signal
(d22d408)
2014-06-18 Renato Araujo Oliveira Filho
* use mThreads[row].properties(); into the get property. (727dd9b)
* return a QVariantMap with all thread data for "get" function.
(5091bcf)
* Export property count and get to QML. (c457d5b)
2014-06-10 Ken VanDine
* Added count and at functions to HistoryEventModel (7c54115)
2014-05-23 Tiago Salem Herrmann
* add support for sending mms's (845a836)
2014-05-22 CI bot
* Releasing 0.1+14.10.20140522-0ubuntu1 (b8c25a4)
2014-05-22 Tiago Salem Herrmann
* - add support for removing event attachments - fix dbus
demarshaling for attachments so they don't get deleted
when the event is marked as read. (1e2bf28)
* save attachments on outgoing messages (4c9396c)
2014-05-05 Tiago Salem Herrmann
* add support for removing event sttachments (7c7bfe1)
2014-04-23 Tiago Salem Herrmann
* fix dbus demarshaling for attachments (17eca14)
2014-04-07 CI bot
* Releasing 0.1+14.04.20140407-0ubuntu1 (d30b1ab)
2014-04-07 Tiago Salem Herrmann
* Change observer filter to only receive non flash sms's. (c251aff)
* remove filter check if the SMS interface exists manually (beba73d)
2014-04-03 Tiago Salem Herrmann
* add tests back (25731f6)
* merge trunk (f61fb25)
2014-03-26 CI bot
* Releasing 0.1+14.04.20140326-0ubuntu1 (87e056d)
2014-03-26 Gustavo Pichorim Boiko
* Delay the loading of model data until after the model properties
are set. (61a6da3)
2014-03-25 Gustavo Pichorim Boiko
* Delay the loading of model data until after the model properties
are set. (11059b4)
2014-03-19 CI bot
* Releasing 0.1+14.04.20140319-0ubuntu1 (cc8e201)
2014-03-19 Gustavo Pichorim Boiko
* Make sure to only propagate events and threads of the correct type
on views, even when the filter is null. (217829f)
2014-03-18 Gustavo Pichorim Boiko
* Make sure to only return threads and events of the correct type
when the filter is null. (ac1d56b)
* Update to build with latest telepathy-qt5. (bad5b84)
2014-03-06 Tiago Salem Herrmann
* fix tests only receive non flash sms's (b4085bb)
2014-03-05 CI bot
* Releasing 0.1+14.04.20140305-0ubuntu1 (574525e)
* No change rebuild against Qt 5.2.1. (71c59f6)
2014-02-28 CI bot
* Releasing 0.1+14.04.20140228-0ubuntu1 (14464d1)
2014-02-28 Tiago Salem Herrmann
* Fix broken test with qt5.2.
Fixes: 1285007 (cc9e00a)
2014-02-27 Tiago Salem Herrmann
* fix broken test with qt5.2 (e6c0bf3)
2014-02-17 CI bot
* Releasing 0.1+14.04.20140217-0ubuntu1 (9b0ca24)
2014-02-17 Tiago Salem Herrmann
* - History needs to also observe channels with TargetHandleType = 0
for group chat. - Don't iterate if the amount of
participants is different (5040aaf)
* fix createChannel signature (957eae7)
2014-02-10 CI bot
* Releasing 0.1+14.04.20140210-0ubuntu1 (8ce7ae1)
2014-02-10 Tiago Salem Herrmann
* Check if the model is already empty before removing items in order
to avoid an assert() in qt 5.2.
Fixes: 1275835 (0eb142f)
2014-02-04 Tiago Salem Herrmann
* fix assert on qt 5.2 (4f47d5d)
2014-01-30 CI bot
* Releasing 0.1+14.04.20140130-0ubuntu1 (ccc0b39)
* Release history-service trunk in CITrain (c227ee2)
2014-01-30 Tiago Salem Herrmann
* History needs to also observe channels with TargetHandleType = 0
for group chat. (9c0259c)
2014-01-24 Tiago Salem Herrmann
* don't iterate if the amount of participants is different (082e7b4)
2014-01-21 Gustavo Pichorim Boiko
* Do not create threads if they are not already there when a delivery
report arrives. (a14a849)
* Do not create threads if they are not already there when a delivery
report arrives. (486c506)
2014-01-10 Automatic PS uploader
* Releasing 0.1+14.04.20140110-0ubuntu1 (revision 125 from
lp:history-service). (36d0ae4)
* Releasing 0.1+14.04.20140110-0ubuntu1, based on r125 (2b91d02)
2014-01-08 Tiago Salem Herrmann
* - Declare delivery report enums to be used from QML - Update all
existing text message status to "accepted". (8d69b49)
* - Declare delivery report enums to be used from QML - update all
existing text message status to "accepted" (479d6a6)
2013-12-13 Gustavo Pichorim Boiko
* Handle the delivery reports and use the data to update the message
status. (8fddea3)
* Enable error reporting on failed tests. (d9eafac)
* Test the delivery report handling. (54d3b68)
* Add tests for the Telepathy related code in history-service.
(1604409)
* Merge the telepathy tests. (529c222)
* Add tests for calls. (e21586a)
2013-12-12 Gustavo Pichorim Boiko
* Add missing include dir. (4229e38)
* Add missing dependencies. (d0e153d)
* Re-enable accidentally disabled tests. (aef41de)
* Add tests for sending and receiving messages. (3f971e4)
2013-12-11 Gustavo Pichorim Boiko
* Start implementing the mock CM to test the telepathy bits on
history-service. (6879e3a)
2013-12-11 Automatic PS uploader
* Releasing 0.1+14.04.20131209-0ubuntu1 (revision 120 from
lp:history-service). (b4bad82)
2013-12-10 Gustavo Pichorim Boiko
* Update the message status using information from the delivery
reports. (ecb96f8)
* Rename the messageFlags field to messageStatus to reflect its real
purpose. (fefd28d)
2013-12-09 Gustavo Pichorim Boiko
* Rename the field from messageFlags to messageStatus to reflect its
real purpose. (61eba2a)
2013-12-09 Automatic PS uploader
* Releasing 0.1+14.04.20131209-0ubuntu1, based on r120 (c87a948)
2013-12-05 Gustavo Pichorim Boiko
* Add an initial set of tests for the thread and event views.
(4843f15)
* Add tests for the History::Manager class. (768cee0)
2013-12-04 Gustavo Pichorim Boiko
* Add an initial set of tests for the thread and event views.
(87d49de)
2013-12-03 Gustavo Pichorim Boiko
* Test remove threads. (cbd6358)
2013-12-02 Gustavo Pichorim Boiko
* Test getting a single event. (c74e410)
* Update bzrignore file. (7388255)
* Test events removal and fix a bug in the logic of thread removal
notification. (a2d83d7)
2013-11-29 Gustavo Pichorim Boiko
* Get the correct events to be modified. (46c096e)
* Add more tests for the Manager class. (36743c7)
* Fix notifying the threads that were modified by the writing of
events. (e6603d2)
2013-11-28 Gustavo Pichorim Boiko
* Remove files that are generaged automatically at build time.
(3233bc7)
* Really add the test file. (3782088)
* Fix loading the plugin from the build dir. (7fbbd96)
2013-11-27 Gustavo Pichorim Boiko
* Merge latest changes from trunk. (767b29f)
* Add the infrastructure to run dbus based tests. (8e54ebe)
* Make it possible to load plugins from the build dir. (ce0233b)
* Add tests for the sqlite plugin. (ec02f53)
2013-11-20 Gustavo Pichorim Boiko
* Add missing dependencies. (f2bad3f)
2013-11-19 Gustavo Pichorim Boiko
* Add tests for the SqliteEventView class. (28ffc64)
* Remove leftover debug print. (6678f51)
* Really add the file. (8510e32)
* Add tests for the SqliteHistoryThreadView class and fix some bugs
found while writing the tests. (7c03629)
2013-11-17 Tiago Salem Herrmann
* Accept non numeric id's. (f89a3bc)
2013-11-14 Gustavo Pichorim Boiko
* Add the remaining tests of the plugin class. (377bcb1)
2013-11-13 Gustavo Pichorim Boiko
* Test the removal of voice and text events. (f1dce1b)
* Test writing voice events too. (cdd1a5e)
* Test writing new text events. (5a7d7e7)
* Test the query* methods. (3b46ac8)
2013-11-12 Gustavo Pichorim Boiko
* Add more tests. (b8b17f6)
2013-11-11 Gustavo Pichorim Boiko
* Make it possible to use a different database path, and implement
the first test of the sqlite plugin. (5dbbdad)
2013-11-11 Tiago Salem Herrmann
* revert back to comparePhoneNumbers() (1aad6f3)
2013-11-08 Tiago Salem Herrmann
* fix copyright (cc5e936)
* use the same PhoneUtils tests from telephony-service (71131b8)
* use the same PhoneUtils implementation as telephony-service
(184c096)
2013-11-04 Tiago Salem Herrmann
* perform phone number comparison only if both senderId's are phone
numbers (097ae56)
2013-11-04 Gustavo Pichorim Boiko
* Fix calling History::Filter::toString() when the value is a boolean
or a number. (09a1b17)
2013-11-01 Gustavo Pichorim Boiko
* Use 1 and 0 for true and false values. (2b1fcd5)
2013-10-31 Gustavo Pichorim Boiko
* Fix calling History::Filter::toString() when the value is a boolean
or a number. (e50c1a7)
2013-10-29 Gustavo Pichorim Boiko
* Add a pkgconfig file. (aff95c7)
* Fix the lib name. (187d36a)
* Add a pkgconfig file. (d466e33)
* Pass filters in a way that they can be recreated at the service
end. (ea1930a)
2013-10-25 Gustavo Pichorim Boiko
* Merge latest changes from trunk. (7a461c8)
* Fix the demarshalling of the filters when they travel via dbus.
(bec3ceb)
* Update the existing unit tests to improve the code coverage a bit.
(6ca2ab0)
2013-10-24 Gustavo Pichorim Boiko
* Fix calling the query methods. (7c1a400)
2013-10-23 Gustavo Pichorim Boiko
* And finally, pass the filter as a QVariantMap on dbus. (9c4e69e)
* Implement properties() and fromProperties() on union and
intersection filters as well. (20113f3)
* Add properties() and fromProperties() methods to the filter class.
(78ef718)
2013-10-22 Gustavo Pichorim Boiko
* Update the intersection and union filter tests. (ab9f78f)
2013-10-17 Gustavo Pichorim Boiko
* Update filter tests. (1e00173)
* Update thread tests. (80f688c)
* Update the sort tests and rename the sort field enums to be
consistent with the others. (93b3555)
* Update the VoiceEvent tests. (f73cb72)
* Update the text event tests. (ece0e93)
2013-10-16 Automatic PS uploader
* Releasing 0.1+13.10.20131016-0ubuntu1 (revision 111 from
lp:history-service). (4e09d0f)
* Releasing 0.1+13.10.20131016-0ubuntu1, based on r111 (f12f215)
2013-10-15 Gustavo Pichorim Boiko
* Fix the duration saving on new call entries. They were being saved
as QTime, but they should be actually saved as just the
duration in seconds. (6a379df)
* Make sure we save the duration as seconds and not timestamp.
(383606a)
2013-10-11 Automatic PS uploader
* Releasing 0.1+13.10.20131011-0ubuntu1 (revision 109 from
lp:history-service). (d1b01af)
* Releasing 0.1+13.10.20131011-0ubuntu1, based on r109 (bfb1962)
2013-10-09 Gustavo Pichorim Boiko
* Fix passing the call duration via dbus. (e354ed6)
2013-10-08 Gustavo Pichorim Boiko
* Fix passing the call duration via dbus. (c2789c4)
2013-10-08 Automatic PS uploader
* Releasing 0.1+13.10.20131008.1-0ubuntu1 (revision 107 from
lp:history-service). (1403c78)
* Releasing 0.1+13.10.20131008.1-0ubuntu1, based on r107 (1ef6b40)
2013-10-04 Gustavo Pichorim Boiko
* Make sure the ThreadsModified signal is emitted with the threads
up-to-date.
Fixes:
https://bugs.launchpad.net/bugs/1234611. (85b4f9e)
2013-10-03 Gustavo Pichorim Boiko
* Make sure the ThreadsModified signal is emitted with the threads
up-to-date. (81a750d)
2013-10-01 Automatic PS uploader
* Releasing 0.1+13.10.20131001.4-0ubuntu1 (revision 105 from
lp:history-service). (f831d75)
* Releasing 0.1+13.10.20131001.4-0ubuntu1, based on r105 (27c5fc9)
2013-09-30 Gustavo Pichorim Boiko
* Make sure the events emitted on signals contain the participants
field. (64c9e34)
* Make sure the events emitted on signals contain the participants
field. (68a2eae)
2013-09-27 Automatic PS uploader
* Releasing 0.1+13.10.20130927-0ubuntu1 (revision 103 from
lp:history-service). (ff6ac06)
* Releasing 0.1+13.10.20130927-0ubuntu1, based on r103 (91c23de)
2013-09-26 Gustavo Pichorim Boiko
* Add a participants field on event to avoid having to query threads
for each and every event just to discover the
participants. (2ceb07e)
* Add a participants field on event to avoid having to query threads
for each and every event just to discover the
participants. (8c25dbf)
2013-09-25 Gustavo Pichorim Boiko
* Cache the threads to optimize the performance a bit when displaying
events. (0692b17)
* Cache the threads to optimize the performance a bit when displaying
events. (cce633f)
2013-09-25 Automatic PS uploader
* Releasing 0.1+13.10.20130925-0ubuntu1 (revision 100 from
lp:history-service). (27790f4)
* Releasing 0.1+13.10.20130925-0ubuntu1, based on r100 (d2c781a)
2013-09-23 Gustavo Pichorim Boiko
* Clear the inconsistencies between thread_participants and threads
on existing databases to make sure the service continues
to work properly.
Fixes:
https://bugs.launchpad.net/bugs/1228446. (7b4f843)
* Set the Recover property on the telepathy client file to make sure
that if the history daemon crashes it will get restarted
by telepathy mission control.
Fixes:
https://bugs.launchpad.net/bugs/1228446. (428dd79)
* Clear the inconsistencies between thread_participants and threads
on existing databases to make sure the service continues
to work properly. (da7f516)
* Set the Recover property on the telepathy client file to make sure
that if the history daemon crashes it will get restarted
by telepathy mission control. (6b22536)
* Make it possible to modify events. (ca3e476)
2013-09-20 Gustavo Pichorim Boiko
* Reset the timer every time a new item arrives (this helps improving
the performance while scrolling the lists). (209eb40)
* Return the correct value when writing text events. (6c06e38)
* Make sure we don't duplicate the event on the model. (8594a67)
2013-09-19 Automatic PS uploader
* Releasing 0.1+13.10.20130919.3-0ubuntu1 (revision 96 from
lp:history-service). (5da2ccf)
2013-09-19 Gustavo Pichorim Boiko
* Add support for modifying events. (cba9041)
2013-09-19 Automatic PS uploader
* Releasing 0.1+13.10.20130919.3-0ubuntu1, based on r96 (bd2da84)
2013-09-18 Gustavo Pichorim Boiko
* Do not use shared pointers for events, threads, filters and sort.
They were causing too much trouble for little benefit.
(9abe442)
* Add some more tests to the text event attachment. (2234aec)
2013-09-18 Automatic PS uploader
* Releasing 0.1+13.10.20130918.1-0ubuntu1 (revision 94 from
lp:history-service). (8424ea9)
2013-09-18 Gustavo Pichorim Boiko
* Do not use shared pointers for text event attachments. (01f43b5)
2013-09-18 Automatic PS uploader
* Releasing 0.1+13.10.20130918.1-0ubuntu1, based on r94 (7698247)
2013-09-17 Gustavo Pichorim Boiko
* Merge latest changes from trunk. (0d93568)
* Use Filters instead of QList for clarity. (e8511be)
* Do not use shared pointers for threads. (6b93662)
* Do not use shared pointers for the events. (3e1253b)
* Use dbus for all the communication between the history service and
its clients. Clients no longer access the sqlite database
directly. (ca9d9a7)
* Do not use pointers for the sort either. (d2f1956)
* Merge latest changes from trunk. (89f6f21)
* Remove the use of shared pointers for filters. (58ef0c7)
* Use the predefined property names in the tests too. (13d0a4d)
* Fix the read timestamp reading and writing and replace some more
hardcoded strings by predefined ones. (2f3da36)
* Remove spurious file. (d92a3b2)
2013-09-17 Automatic PS uploader
* Releasing 0.1+13.10.20130917-0ubuntu1 (revision 92 from
lp:history-service). (f1d8502)
2013-09-17 Gustavo Pichorim Boiko
* Do not allow for multiple instances of history-service. (8b3d999)
2013-09-17 Automatic PS uploader
* Releasing 0.1+13.10.20130917-0ubuntu1, based on r92 (8864adc)
2013-09-16 Gustavo Pichorim Boiko
* Fix timestamp displaying. (bd1876d)
* Use the predefined strings instead of the hardcoded ones. (8fb4a41)
* Implement the threadForParticipants() method in a way more
consistent with the rest of the code. (a80d902)
* ... and reimplement also saving the attachments. (784b672)
* Reimplement the support for attachments. (5502d35)
* Fix packaging. (989f13c)
* Add dbus activation. (578f3ba)
* Set the event types properly when writing new events from
Telepathy. Thanks Tiago Salem Herrmann for the patch.
(ec63f58)
* Notify the threads modified. (a8bb6da)
* Change the implementation of thread removal. (cf03ec3)
* Merge latest changes from trunk. (f8e277d)
* Implement thread removal. (412d1f1)
* Connect the signal to the correct slot (e7a29be)
* Call the functions from the dbus. (bc34427)
* Implement the writer part of the dbus things. (5308e72)
2013-09-13 Gustavo Pichorim Boiko
* Fix passing dates via DBus (patch by Tiago Salem Herrmann).
(c61fa3b)
* Implement the getSingle* methods. Change the code to be able to
reuse some parts and avoid duplication. (ff1b627)
* Remove leftover definition. (6893959)
* Add missing copyright. (d349dbf)
* Add support for server-side event views. (48c4fb0)
2013-09-13 Tiago Salem Herrmann
* - Fix threadIdForParticipants() argument. matchFlags was not
correctly being set. - Expose the "create" argument to qml
so apps can create threads. (7ef48ec)
2013-09-13 Gustavo Pichorim Boiko
* Update .bzrignore. (d2003ab)
* Fix the thread view. (21f67b5)
* Do not use shared pointers for the views. (5df4e6d)
* Fix build when builddir != srcdir (48334e7)
* Implement the thread view via dbus. (86a8bf6)
* Merge latest changes from trunk. (3cfc560)
2013-09-13 Tiago Salem Herrmann
* also update EventModel (5344326)
2013-09-13 Gustavo Pichorim Boiko
* Start creating the server-side thread view. (26064c3)
2013-09-13 Tiago Salem Herrmann
* expose the "create" argument to qml so apps can create threads
(d383d15)
* fix threadIdForParticipants() argument. matchFlags was not being
correctly set. (b7d4db7)
2013-09-13 Gustavo Pichorim Boiko
* Remove the Reader and Writer classes. All methods are implemented
in the Plugin class directly to make it simpler. (dc4823c)
* Add a missing build dependency on sqlite3 (required to generate the
schema file). (71ebd7e)
* Add a missing build dependency on sqlite3 (required to generate the
schema file). (d6df84f)
2013-09-12 Gustavo Pichorim Boiko
* Start implementing the server side of the service. (6b5e2b7)
* Remove the Reader and Writer classes. All methods are implemented
in the Plugin class directly to make it simpler. (adb45ee)
* Implement the client side of history-service to go via dbus.
(0a9c0a1)
2013-09-12 Tiago Salem Herrmann
* Remove data from thread_participants when deleting threads.
(e6fe174)
* change 'from' to 'FROM' (f28560e)
* remove schema.sql and add it to .bzrignore (fbfd4ea)
2013-09-11 Tiago Salem Herrmann
* add trigger to remove items from the thread_participants table
(c96f0ab)
* revert previous commit (139fc6e)
2013-09-11 Gustavo Pichorim Boiko
* Add more method templates. (ac79b38)
2013-09-11 Tiago Salem Herrmann
* remove data from thread_participants when deleting threads
(7ab5eab)
2013-09-11 Gustavo Pichorim Boiko
* Start implement the communication via DBus. (27bdfcc)
2013-08-27 Automatic PS uploader
* Releasing 0.1+13.10.20130827-0ubuntu1 (revision 87 from
lp:history-service). (31ef7ff)
* Releasing 0.1+13.10.20130827-0ubuntu1, based on r87 (5327033)
2013-08-26 Automatic PS uploader
* Releasing 0.1+13.10.20130826.1-0ubuntu1 (revision 86 from
lp:history-service). (db57f10)
* Releasing 0.1+13.10.20130826.1-0ubuntu1, based on r86 (439db56)
2013-08-26 Timo Jyrinki
* Packaging fixes. Multi-arch, remove debug package (available after
archive upload), QML plugin rename and other fixes.
(cb85403)
* Really small fixes (2f9729c)
* Add comment about team memberships to control. (16f5f55)
* add upstream-name/source to debian/copyright (de84db2)
* Improve package descriptions. (07582a6)
* Rename QML plugin (bd60852)
* bootstrap, remove debug package, add shlibs:depends (0509883)
* Remove redundant Section lines (6f20a32)
* wrap-and-sort -a -t (3db14b7)
* Multi-arch (29b23a5)
2013-08-22 Gustavo Pichorim Boiko
* Make it possible to do phone number matching for the accounts that
use phone numbers as IDs. (287b63e)
* Add missing dependency on sqlite3. (c641d50)
2013-08-21 Gustavo Pichorim Boiko
* Make it possible to do phone number matching for the accounts that
use phone numbers as IDs. (1d46bf0)
* Add an invalidated() signal to the views so that they can notify
their users about that. (9c7a5c5)
* Add an initial set of unit tests for the classes in
history-service. (cd6fb16)
* Merge latest changes from trunk. (0e477ad)
* Merge latest changes from trunk. (9544783)
2013-08-20 Tiago Salem Herrmann
* Add initial mms support. (a771234)
* fix sql upgrade script remove qml wapper instances on updateQuery()
(4a3ca0c)
* simplify code (c728e92)
* no need to create another instance (9f5bd1f)
2013-08-20 Gustavo Pichorim Boiko
* Add tests for the Sort class. (2b4cb51)
2013-08-20 Tiago Salem Herrmann
* add doxygen comments to the TextEventAttachment class (982f8a4)
* add new database schema (f7268e2)
* merge trunk (3ea9e76)
* revert schema file (ec79d02)
2013-08-20 Gustavo Pichorim Boiko
* Make database upgrades easier by allowing to have sql files that
update from one version to another. (f66f1ac)
2013-08-19 Gustavo Pichorim Boiko
* Make sure the scripts for updating the schema work when the srcdir
!= builddir. (6f32f55)
* Remove the IF NOT EXISTS from the schema sql files. (37c5bf0)
2013-08-19 Tiago Salem Herrmann
* fix wrong column name (7da5422)
2013-08-19 Gustavo Pichorim Boiko
* Add tests for the filter classes. (7916c9c)
* Improve the schema upgrade. Now the schema.sql file is generated
automatically based on all the version update scripts
(v1.sql, v2.sql, etc). The schema version info and the
resource file (historysqliteplugin.qrc) are also generated
automatically to contain up-to-date information based on
the contents of the plugins/sqlite/schema directory.
(dfffa5b)
2013-08-16 Gustavo Pichorim Boiko
* Add support for automatic updating the schema file based on all the
version update scripts. (33c9b7c)
2013-08-16 Tiago Salem Herrmann
* do not remove attachments. We will remove them using sql triggers
(65cbab0)
* use numbers instead of column names to improve performance
(251487b)
* add subject property to TextEvent and status to TextEventAttachment
(839501b)
2013-08-15 Gustavo Pichorim Boiko
* Make database upgrades easier by allowing to have sql files that
update from one version to another. (6b150f3)
2013-08-15 Tiago Salem Herrmann
* add qml side of mms changes (ee4343c)
* fix sql query (462171f)
2013-08-14 Tiago Salem Herrmann
* add mms support to sql plugin (bad9966)
2013-08-14 Gustavo Pichorim Boiko
* Add tests for the Thread and ItemFactory classes. (45b9ede)
2013-08-14 Tiago Salem Herrmann
* merge trunk (8e30c6a)
* add initial mms support (820df45)
2013-08-14 Gustavo Pichorim Boiko
* Remove leftover code. (ed86842)
* Merge changes from trunk. (055eb0c)
* Add tests for the Event derived classes. (679b862)
* Remove empty constructor. (1d0f65e)
* Add ignore rules. (e674965)
* Remove some empty unused constructors. (05cef4d)
* And one more. (e3d5250)
* Remove some empty unused constructors. (fd9da59)
2013-08-06 Gustavo Pichorim Boiko
* Add support for removing events and threads from the storage.
(ee80d5c)
* Fix the notification of removed threads. (d6891d7)
* Add support for removing events and threads from the QML models.
(223a688)
* Fix the triggers executed when removing items. (09b6d4c)
2013-08-05 Gustavo Pichorim Boiko
* Implement removing events and threads from the model. (0c42a17)
* Add support for updating the database schema for existing files.
(4756cac)
* Add support for updating the database schema for existing files.
(606f274)
2013-07-31 Gustavo Pichorim Boiko
* Do not use cache when updating the threads. (7f30659)
* Do not use cache when updating the threads. (1be6448)
* Add an invalidated() signal to the views so that they can notify
their users about that. (e90f0c5)
* In order to avoid leaving queries opened, but still have a static
result set, the views now create temporary tables with the
results they use, fetch results from there, and close the
query after fetching each page. (10dab99)
2013-07-30 Gustavo Pichorim Boiko
* In order to avoid leaving queries opened, but still have a static
result set, the views now create temporary tables with the
results they use, fetch results from there, and close the
query after fetching each page. (0117229)
2013-07-26 Gustavo Pichorim Boiko
* Ignore filters that have empty values too. (7d0cbf0)
* Ignore filters that have empty values too. (6433d65)
2013-07-25 Gustavo Pichorim Boiko
* Add a "participants" role in the QML events model so that views
that don't use threads can access this information. Also
make sure that the cached items are used whenever possible
to avoid extra database queries. (e701792)
* Rename the QML plugin package to
qtdeclarative5-ubuntu-history-plugin. (84fc422)
* Make it possible to get the threadId for a list of participants
from QML. (2cab1e4)
* Add a "participants" role in the QML events model so that views
that don't use threads can access this information. Also
make sure that the cached items are used whenever possible
to avoid extra database queries. (aae3a44)
* Add a role that returns only the date for a given timestamp.
(457e8d6)
* Rename the QML plugin package to
qtdeclarative5-ubuntu-history-plugin. (4618c15)
* Add a role that returns only the date for a given timestamp.
(9f42774)
2013-07-24 Gustavo Pichorim Boiko
* Implement very basic sorting capabilities. (6bda5dd)
* Make it possible to get the threadId for a list of participants
from QML. (8459140)
* Remove leftover debug print. (1095e81)
* Fix the sorting of threads. (f1b6921)
* Implement very basic sorting capabilities. (0e636eb)
2013-07-24 Tiago Salem Herrmann
* add proxy model to sort items. (3fd36dd)
* remove unused signal (1e3ee26)
2013-07-23 Tiago Salem Herrmann
* remove unused methods (85597ea)
* add proxy model to sort items (7b56d96)
2013-07-23 Gustavo Pichorim Boiko
* Propagate changes in the history storage to all running clients via
DBus. (24ec01a)
* Use the currentDateTime for the sent messages. (ed3e864)
* Fix the demarshalling of QDateTime parameters. (832ab74)
* Ignore delivery reports, scrollback and rescued messages. (ecc536c)
* Fix the property name loaded from the map. Thanks Tiago Salem for
finding that. (72c7818)
2013-07-22 Gustavo Pichorim Boiko
* Remove some debug and update the sample client. (87afbd2)
* Notify when threads change and handle that in the model. (49306c6)
* Fix the compilation. (7a93ab2)
* Merge latest changes from trunk. (b31b071)
* Make better use of memory by making sure there is only one instance
of each event and thread in memory at any time. (088af4d)
* Reduce the verbosity by removing some debug prints. (7ed9cc4)
* Only append the "." when the property prefix is set. (69f9831)
* Make sure there is only one existing entry in memory for each event
or thread. (e09a1ea)
* Add the build dir to the include directories. (3b9461b)
* Add basic handling for new events in the QML plugin. (f94d7b7)
* Properly emit and listen for evens on DBus (4b5bf1b)
2013-07-19 Gustavo Pichorim Boiko
* Watch for events on dbus to update all clients. (e752064)
* Move the write functions to the History::Manager so that it is the
only single place where plugin management is required.
(6e5e6f8)
* And also add signals to handle updates in the EventView. (b503961)
* Add support for update notification in the thread view. (1e68ee9)
* Rename the Event::sender property to Event::senderId to be more
consistent. Also add some signals to the view classes to
handle changes in the data. (3e4b8b1)
* Add a match() function that returns true if it matches a given set
of properties. (7eb55bb)
* Use typedef for defining the list of pointers. (70806d2)
* Install the Telepathy Logger import tool. (ccc303b)
2013-07-18 Gustavo Pichorim Boiko
* Add one missing file. (58d1a8b)
* Install the Telepathy Logger import tool. (4ef133c)
2013-07-16 Gustavo Pichorim Boiko
* Add debian packaging files. (975b9fa)
2013-07-15 Gustavo Pichorim Boiko
* Remove unused modules from CMakeLists.txt. (6fb3f37)
* Add copyright headers and a COPYING file. (94c7e38)
* Change the Architectures to be 'any'. (91b06e3)
* Add one missing copyright header. (658213c)
* Add the split deb bzr rule. (9745b6c)
2013-07-12 Gustavo Pichorim Boiko
* Add debian packaging files. (39cbf66)
* Set the library version and soname. (e8dd561)
* Set the library version and soname. (88a0927)
* Add a COPYING file and copyright headers to all source files.
(6e43560)
2013-07-11 Gustavo Pichorim Boiko
* Add some telepathy service files to make sure the daemon is started
automatically and install some extra needed files.
(e1cf454)
* Add one more QML sample. (c6479cc)
* Set the threads as forwardOnly to save some memory. (c178ff8)
* Make the output of the reader tool a little prettier. (e9c8710)
* Add transaction support, and use it both for creating the database
and for importing Telepathy Logger items. (817b135)
* Replace some more references to item by event. (faa3efa)
* Wrap all classes in a namespace, and rename some classes to better
represent their purpose. (d115eb6)
2013-07-10 Gustavo Pichorim Boiko
* Use pointers for the filters and sorting. (cb00ef9)
* Add a tool to import entries from telepathy-logger. (91f57ca)
* Fix the item query. (be138bb)
* Get the last item from the threads in the same SQL query used to
get the threads. (7b138e8)
* Change the item retrieval to use the HistoryItemView object.
(3877f9d)
2013-07-09 Gustavo Pichorim Boiko
* Update the classes to use the newly created HistoryThreadView.
(93e6d14)
* Add the base class for the HistoryThreadView. (47f3ca8)
* Make HistorySort use shared data. (cf9ad7b)
* Fix the matching of boolean values in the queries (patch created by
Tiago Salem Herrmann) (a67d899)
* Create a model to load history items. (c9e56e4)
* Remove unused class. (5982ff7)
* Remove extra comma from the SQL command. (1e9044e)
* Load the last item from the thread. (33c02cc)
2013-07-08 Gustavo Pichorim Boiko
* Add a sample QML client. (595336c)
* Add the thread related roles to the model. The item related ones
are still missing. (1a4066e)
* Add QML wrappers for the filter classes and start implementing the
threads model and the QML plugin. (9566d40)
* Add a operator= to HistoryFilter. (6b503de)
* Remove implemented bit from the FIXME (1795eb0)
* Use QStandardPaths::GenericDataLocation so that QML applications
using qmlscene get the correct path too. (3e3cf6f)
2013-07-03 Gustavo Pichorim Boiko
* Add support for paginated results in the sqlite plugin. (29e5ba6)
2013-07-02 Gustavo Pichorim Boiko
* Wrap the strings in the test program using qPrintable to have a
cleaner output. (34358f7)
* Add the basic implementation of a union filter. (da14eba)
* Add a basic implementation of the intersection filter. (4cb45eb)
2013-07-01 Gustavo Pichorim Boiko
* Add basic output for items in the test program. (574b9f1)
* Implement basic thread and item reading from the database.
(16037e4)
* Add a sample client to load content from the history. (c06e9fa)
* Fix the database location. (360eddd)
* Add basic skeleton for the HistoryReader. (2552b54)
2013-06-28 Gustavo Pichorim Boiko
* Add the base skeleton for the HistoryManager class. (396b718)
* Add the implementation for HistorySort. (5d4ac92)
* Add the implementation of HistoryFilter. (968f97d)
* Save the unread (newItem) status of items in the database, and
create triggers to update counters and last item of
threads automatically. (09c8b93)
2013-06-27 Gustavo Pichorim Boiko
* Save also text messages. (103fece)
* Save the duration in seconds. (ae2be1b)
* Rename the library to libcommhistory and make it shared. Also
implement a missing destructor. (fb910b1)
* Add missing cmake modules directory. (a24be68)
* Add proper code to save the voice and text items. (8479c52)
* Add more tables to the schema. (1699ff1)
* Add a call channel observer to watch for changes in the currently
running calls. (45ee725)
* Create the database structure from an external schema file.
(13532e2)
* Fix the SQL statements and how they are called from QSqlQuery.
(a5e24a9)
2013-06-26 Gustavo Pichorim Boiko
* Add some debug. (99f1f2e)
2013-06-25 Gustavo Pichorim Boiko
* Add code to write the thread for new events. (50b76cd)
* Add a basic SQLite plugin. The code is not complete yet though.
(6870edf)
* Add a class to load and manage plugins. (31a7ac5)
2013-06-20 Gustavo Pichorim Boiko
* Add some more pretty headers to CMakeLists.txt (26fd76f)
* Implement the HistoryThread class. (a0e906f)
2013-06-19 Gustavo Pichorim Boiko
* Add missing method implementation. (3f8bc0c)
* Add a sample code to write voice entries in the daemon. The code is
not yet functional. (eb8312e)
* Uncomment the history plugin classes. (f305edc)
* Implement the VoiceItem class. (90a985d)
* Implement the text item and add the missing history item
implementation. (67709c3)
* Implement the HistoryItem class. (ccefa9f)
* Initialize TpQt types before using them, and track sent messages
too. (79cffca)
2013-06-18 Gustavo Pichorim Boiko
* Initial source code for the telepathy-logger replacement. (35a2a53)
history-service-0.5/Lomiri/ 0000775 0000000 0000000 00000000000 14554502467 0015764 5 ustar 00root root 0000000 0000000 history-service-0.5/Lomiri/CMakeLists.txt 0000664 0000000 0000000 00000000032 14554502467 0020517 0 ustar 00root root 0000000 0000000 add_subdirectory(History)
history-service-0.5/Lomiri/History/ 0000775 0000000 0000000 00000000000 14554502467 0017425 5 ustar 00root root 0000000 0000000 history-service-0.5/Lomiri/History/CMakeLists.txt 0000664 0000000 0000000 00000002121 14554502467 0022161 0 ustar 00root root 0000000 0000000 # QML plugin
set(plugin_SRCS
historyeventmodel.cpp
historygroupedeventsmodel.cpp
historygroupedthreadsmodel.cpp
historymanager.cpp
historymodel.cpp
historyqmlfilter.cpp
historyqmlintersectionfilter.cpp
historyqmlplugin.cpp
historyqmlsort.cpp
historyqmltexteventattachment.cpp
historyqmlunionfilter.cpp
historythreadmodel.cpp
)
set(plugin_HDRS
historyeventmodel.h
historygroupedeventsmodel.h
historygroupedthreadsmodel.h
historymanager.h
historymodel.h
historyqmlfilter.h
historyqmlintersectionfilter.h
historyqmlplugin.h
historyqmlsort.h
historyqmltexteventattachment.h
historyqmlunionfilter.h
historythreadmodel.h
)
include_directories(
${CMAKE_SOURCE_DIR}/src
)
add_library(history-qml MODULE ${plugin_SRCS} ${plugin_HDRS})
qt5_use_modules(history-qml Contacts Core Qml Quick)
target_link_libraries(history-qml
historyservice
)
set(PLUGIN_DIR ${QT_INSTALL_QML}/Lomiri/History)
install(TARGETS history-qml DESTINATION ${PLUGIN_DIR})
install(FILES qmldir DESTINATION ${PLUGIN_DIR})
history-service-0.5/Lomiri/History/historyeventmodel.cpp 0000664 0000000 0000000 00000035420 14554502467 0023721 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2017 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historyeventmodel.h"
#include "eventview.h"
#include "historyqmltexteventattachment.h"
#include "manager.h"
#include "contactmatcher_p.h"
#include
#include
#include
HistoryEventModel::HistoryEventModel(QObject *parent) :
HistoryModel(parent), mCanFetchMore(true)
{
// configure the roles
mRoles = HistoryModel::roleNames();
mRoles[EventIdRole] = "eventId";
mRoles[SenderIdRole] = "senderId";
mRoles[SenderRole] = "sender";
mRoles[TimestampRole] = "timestamp";
mRoles[SentTimeRole] = "sentTime";
mRoles[DateRole] = "date";
mRoles[NewEventRole] = "newEvent";
mRoles[TextMessageRole] = "textMessage";
mRoles[TextMessageTypeRole] = "textMessageType";
mRoles[TextMessageStatusRole] = "textMessageStatus";
mRoles[TextMessageAttachmentsRole] = "textMessageAttachments";
mRoles[TextReadTimestampRole] = "textReadTimestamp";
mRoles[TextReadSubjectRole] = "textSubject";
mRoles[TextInformationTypeRole] = "textInformationType";
mRoles[CallMissedRole] = "callMissed";
mRoles[CallDurationRole] = "callDuration";
mRoles[RemoteParticipantRole] = "remoteParticipant";
mRoles[SubjectAsAliasRole] = "subjectAsAlias";
connect(this, SIGNAL(countChanged()), this, SIGNAL(totalCountChanged()));
}
int HistoryEventModel::totalCount() const
{
if (mView.isNull()) {
qWarning() << "component not ready";
return 0;
}
return mView->getTotalCount();
}
int HistoryEventModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return mEvents.count();
}
QVariant HistoryEventModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= mEvents.count()) {
return QVariant();
}
QVariant result = eventData(mEvents[index.row()], role);
if (result.isNull()) {
result = HistoryModel::data(index, role);
}
return result;
}
QVariant HistoryEventModel::eventData(const History::Event &event, int role) const
{
History::TextEvent textEvent;
History::VoiceEvent voiceEvent;
switch (event.type()) {
case History::EventTypeText:
textEvent = event;
break;
case History::EventTypeVoice:
voiceEvent = event;
break;
case History::EventTypeNull:
qWarning("HistoryEventModel::eventData: Got EventTypeNull, ignoring this event!");
break;
}
QVariant result;
switch (role) {
case EventIdRole:
result = event.eventId();
break;
case SenderIdRole:
result = History::ContactMatcher::normalizeId(event.senderId());
break;
case SenderRole:
if (mMatchContacts) {
result = History::ContactMatcher::instance()->contactInfo(event.accountId(), event.senderId());
} else {
QVariantMap map;
map[History::FieldIdentifier] = event.senderId();
map[History::FieldAccountId] = event.accountId();
result = map;
}
break;
case TimestampRole:
result = event.timestamp();
break;
case SentTimeRole:
if (!textEvent.isNull()) {
result = textEvent.sentTime();
}
break;
case DateRole:
result = event.timestamp().date();
break;
case NewEventRole:
result = event.newEvent();
break;
case PropertiesRole:
result = event.properties();
break;
case TextMessageRole:
if (!textEvent.isNull()) {
result = textEvent.message();
}
break;
case TextMessageTypeRole:
if (!textEvent.isNull()) {
result = (int)textEvent.messageType();
}
break;
case TextMessageStatusRole:
if (!textEvent.isNull()) {
result = (int)textEvent.messageStatus();
}
break;
case TextReadTimestampRole:
if (!textEvent.isNull()) {
result = textEvent.readTimestamp();
}
break;
case TextReadSubjectRole:
if (!textEvent.isNull()) {
result = textEvent.subject();
}
break;
case TextInformationTypeRole:
if (!textEvent.isNull()) {
result = (int)textEvent.informationType();
}
break;
case TextMessageAttachmentsRole:
if (!textEvent.isNull()) {
if (mAttachmentCache.contains(textEvent)) {
result = mAttachmentCache.value(textEvent);
} else {
QList attachments;
Q_FOREACH(const History::TextEventAttachment &attachment, textEvent.attachments()) {
attachments << QVariant::fromValue(new HistoryQmlTextEventAttachment(attachment, const_cast(this)));
}
mAttachmentCache[textEvent] = attachments;
result = attachments;
}
}
break;
case CallMissedRole:
if (!voiceEvent.isNull()) {
result = voiceEvent.missed();
}
break;
case CallDurationRole:
if (!voiceEvent.isNull()) {
result = voiceEvent.duration();
}
break;
case RemoteParticipantRole:
if (!voiceEvent.isNull()) {
result = History::ContactMatcher::normalizeId(voiceEvent.remoteParticipant());
}
break;
case SubjectAsAliasRole:
if (!textEvent.isNull()) {
if (mMatchContacts) {
QVariantMap contactInfo = History::ContactMatcher::instance()->contactInfo(event.accountId(), textEvent.subject());
QString returnValue = contactInfo[History::FieldAlias].toString();
if (returnValue.isEmpty()) {
returnValue = contactInfo[History::FieldIdentifier].toString();
}
return returnValue;
}
return textEvent.subject();
}
break;
}
return result;
}
bool HistoryEventModel::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid() || !mFilter || mView.isNull()) {
return false;
}
return mCanFetchMore;
}
void HistoryEventModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid() || !mFilter || mView.isNull()) {
return;
}
History::Events events = fetchNextPage();
if (events.isEmpty()) {
mCanFetchMore = false;
Q_EMIT canFetchMoreChanged();
} else {
Q_FOREACH(const History::Event &event, events) {
// watch for contact changes for the given identifiers
Q_FOREACH(const History::Participant &participant, event.participants()) {
watchContactInfo(event.accountId(), participant.identifier(), participant.properties());
}
}
beginInsertRows(QModelIndex(), mEvents.count(), mEvents.count() + events.count() - 1);
mEvents << events;
endInsertRows();
}
}
QHash HistoryEventModel::roleNames() const
{
return mRoles;
}
bool HistoryEventModel::removeEvents(const QVariantList &eventsProperties)
{
History::Events events;
Q_FOREACH(const QVariant &entry, eventsProperties) {
QVariantMap eventProperties = entry.toMap();
History::Event event;
switch (eventProperties[History::FieldType].toInt()) {
case History::EventTypeText:
event = History::TextEvent::fromProperties(eventProperties);
break;
case History::EventTypeVoice:
event = History::VoiceEvent::fromProperties(eventProperties);
break;
}
if (!event.isNull()) {
events << event;
}
}
if (events.isEmpty()) {
return false;
}
return History::Manager::instance()->removeEvents(events);
}
bool HistoryEventModel::writeEvents(const QVariantList &eventsProperties)
{
History::Events events;
Q_FOREACH(const QVariant &entry, eventsProperties) {
QVariantMap eventProperties = entry.toMap();
History::Event event;
switch (eventProperties[History::FieldType].toInt()) {
case History::EventTypeText:
event = History::TextEvent::fromProperties(eventProperties);
break;
case History::EventTypeVoice:
event = History::VoiceEvent::fromProperties(eventProperties);
break;
}
if (!event.isNull()) {
events << event;
}
}
if (events.isEmpty()) {
return false;
}
return History::Manager::instance()->writeEvents(events);
}
bool HistoryEventModel::removeEventAttachment(const QString &accountId, const QString &threadId, const QString &eventId, int eventType, const QString &attachmentId)
{
History::TextEvent textEvent;
History::Event event = History::Manager::instance()->getSingleEvent((History::EventType)eventType, accountId, threadId, eventId);
if (event.type() != History::EventTypeText) {
qWarning() << "Trying to remove an attachment from a non text event";
return false;
}
QVariantMap properties = event.properties();
QList attachmentProperties = qdbus_cast >(properties[History::FieldAttachments]);
QList newAttachmentProperties;
int count = 0;
Q_FOREACH(const QVariantMap &map, attachmentProperties) {
if (map[History::FieldAttachmentId] != attachmentId) {
count++;
newAttachmentProperties << map;
}
}
if (count == attachmentProperties.size()) {
qWarning() << "No attachment found for id " << attachmentId;
return false;
}
properties[History::FieldAttachments] = QVariant::fromValue(newAttachmentProperties);
textEvent = History::TextEvent::fromProperties(properties);
return History::Manager::instance()->writeEvents(History::Events() << textEvent);
}
void HistoryEventModel::updateQuery()
{
// remove all events from the model
if (!mEvents.isEmpty()) {
beginRemoveRows(QModelIndex(), 0, mEvents.count() - 1);
mEvents.clear();
endRemoveRows();
}
// and create the view again
History::Filter queryFilter;
History::Sort querySort;
if (!mView.isNull()) {
mView->disconnect(this);
}
if (mFilter && mFilter->filter().isValid()) {
queryFilter = mFilter->filter();
} else {
// we should not return anything if there is no filter
return;
}
if (mSort) {
querySort = mSort->sort();
}
mView = History::Manager::instance()->queryEvents((History::EventType)mType, querySort, queryFilter);
connect(mView.data(),
SIGNAL(eventsAdded(History::Events)),
SLOT(onEventsAdded(History::Events)));
connect(mView.data(),
SIGNAL(eventsModified(History::Events)),
SLOT(onEventsModified(History::Events)));
connect(mView.data(),
SIGNAL(eventsRemoved(History::Events)),
SLOT(onEventsRemoved(History::Events)));
connect(mView.data(),
SIGNAL(threadsRemoved(History::Threads)),
SLOT(onThreadsRemoved(History::Threads)));
connect(mView.data(),
SIGNAL(invalidated()),
SLOT(triggerQueryUpdate()));
mCanFetchMore = true;
Q_EMIT canFetchMoreChanged();
Q_FOREACH(const QVariant &attachment, mAttachmentCache) {
HistoryQmlTextEventAttachment *qmlAttachment = attachment.value();
if(qmlAttachment) {
qmlAttachment->deleteLater();
}
}
mAttachmentCache.clear();
fetchMore(QModelIndex());
}
void HistoryEventModel::onEventsAdded(const History::Events &events)
{
if (!events.count()) {
return;
}
Q_FOREACH(const History::Event &event, events) {
// if the event is already on the model, skip it
if (mEvents.contains(event)) {
continue;
}
int pos = positionForItem(event.properties());
beginInsertRows(QModelIndex(), pos, pos);
mEvents.insert(pos, event);
endInsertRows();
}
}
void HistoryEventModel::onEventsModified(const History::Events &events)
{
History::Events newEvents;
Q_FOREACH(const History::Event &event, events) {
int pos = mEvents.indexOf(event);
if (pos >= 0) {
mEvents[pos] = event;
QModelIndex idx = index(pos);
if (event.type() == History::EventTypeText) {
History::TextEvent textEvent = event;
mAttachmentCache.remove(textEvent);
}
Q_EMIT dataChanged(idx, idx);
} else {
newEvents << event;
}
}
// append the events that were not yet on the model
if (!newEvents.isEmpty()) {
onEventsAdded(newEvents);
}
}
void HistoryEventModel::onEventsRemoved(const History::Events &events)
{
Q_FOREACH(const History::Event &event, events) {
int pos = mEvents.indexOf(event);
if (pos >= 0) {
beginRemoveRows(QModelIndex(), pos, pos);
mEvents.removeAt(pos);
endRemoveRows();
}
}
// FIXME: there is a corner case here: if an event was not loaded yet, but was already
// removed by another client, it will still show up when a new page is requested. Maybe it
// should be handle internally in History::EventView?
}
void HistoryEventModel::onThreadsRemoved(const History::Threads &threads)
{
// When a thread is removed we don't get event removed signals,
// so we compare and find if we have an event matching that thread.
// in case we find it, we invalidate the whole view as there might be
// out of date cached data on the daemon side
int count = rowCount();
Q_FOREACH(const History::Thread &thread, threads) {
for (int i = 0; i < count; ++i) {
QModelIndex idx = index(i);
if (idx.data(AccountIdRole).toString() == thread.accountId() &&
idx.data(ThreadIdRole).toString() == thread.threadId()) {
triggerQueryUpdate();
return;
}
}
}
}
History::Events HistoryEventModel::fetchNextPage()
{
return mView->nextPage();
}
history-service-0.5/Lomiri/History/historyeventmodel.h 0000664 0000000 0000000 00000006010 14554502467 0023357 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2017 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYEVENTMODEL_H
#define HISTORYEVENTMODEL_H
#include "historymodel.h"
#include "textevent.h"
#include "voiceevent.h"
#include
class HistoryEventModel : public HistoryModel
{
Q_OBJECT
Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged)
Q_ENUMS(EventRole)
public:
enum EventRole {
EventIdRole = HistoryModel::LastRole,
SenderIdRole,
SenderRole,
TimestampRole,
DateRole,
NewEventRole,
TextMessageRole,
TextMessageTypeRole,
TextMessageStatusRole,
TextReadTimestampRole,
TextReadSubjectRole,
TextInformationTypeRole,
TextMessageAttachmentsRole,
CallMissedRole,
CallDurationRole,
RemoteParticipantRole,
SubjectAsAliasRole,
LastEventRole
};
explicit HistoryEventModel(QObject *parent = 0);
int totalCount() const;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role) const;
QVariant eventData(const History::Event &event, int role) const;
Q_INVOKABLE virtual bool canFetchMore(const QModelIndex &parent = QModelIndex()) const;
Q_INVOKABLE virtual void fetchMore(const QModelIndex &parent = QModelIndex());
virtual QHash roleNames() const;
Q_INVOKABLE bool removeEvents(const QVariantList &eventsProperties);
Q_INVOKABLE bool writeEvents(const QVariantList &eventsProperties);
Q_INVOKABLE bool removeEventAttachment(const QString &accountId, const QString &threadId, const QString &eventId, int eventType, const QString &attachmentId);
Q_SIGNALS:
void totalCountChanged();
protected Q_SLOTS:
virtual void updateQuery();
virtual void onEventsAdded(const History::Events &events);
virtual void onEventsModified(const History::Events &events);
virtual void onEventsRemoved(const History::Events &events);
virtual void onThreadsRemoved(const History::Threads &threads);
protected:
History::Events fetchNextPage();
private:
History::EventViewPtr mView;
History::Events mEvents;
bool mCanFetchMore;
QHash mRoles;
mutable QMap > mAttachmentCache;
};
#endif // HISTORYEVENTMODEL_H
history-service-0.5/Lomiri/History/historygroupedeventsmodel.cpp 0000664 0000000 0000000 00000023070 14554502467 0025470 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historygroupedeventsmodel.h"
#include "utils_p.h"
#include "phoneutils_p.h"
#include "sort.h"
#include "historyqmlsort.h"
#include "participant.h"
HistoryGroupedEventsModel::HistoryGroupedEventsModel(QObject *parent) :
HistoryEventModel(parent)
{
}
int HistoryGroupedEventsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return mEventGroups.count();
}
QVariant HistoryGroupedEventsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= mEventGroups.count()) {
return QVariant();
}
HistoryEventGroup group = mEventGroups[index.row()];
QVariant result;
QVariantList events;
switch (role) {
case EventsRole:
Q_FOREACH(const History::Event &event, group.events) {
events << event.properties();
}
result = events;
break;
case EventCountRole:
result = group.events.count();
break;
default:
result = eventData(group.displayedEvent, role);
break;
}
if (result.isNull()) {
// for the shared roles
result = HistoryModel::data(index, role);
}
return result;
}
void HistoryGroupedEventsModel::fetchMore(const QModelIndex &parent)
{
if (!canFetchMore(parent)) {
return;
}
History::Events events = fetchNextPage();
// History already deliver us the events in the right order
// but we might have added new entries in the added, removed, modified events.
// still, it is less expensive to do a sequential search starting from the bottom
// than to do a binary search for each event, as it is very likely that the entries
// belong to the bottom part of the model.
Q_FOREACH(const History::Event event, events) {
// watch for contact changes for the given identifiers
Q_FOREACH(const History::Participant &participant, event.participants()) {
watchContactInfo(event.accountId(), participant.identifier(), participant.properties());
}
bool found = false;
int pos = mEventGroups.count() -1;
for (; pos >= 0; pos--) {
HistoryEventGroup &group = mEventGroups[pos];
if (areOfSameGroup(event, group.displayedEvent)) {
found = true;
addEventToGroup(event, group, pos);
break;
} else if (isAscending() ? lessThan(group.displayedEvent.properties(), event.properties()) :
lessThan(event.properties(), group.displayedEvent.properties())) {
break;
}
}
if (!found) {
// the item goes into a new group right after the position found above
pos++;
HistoryEventGroup group;
group.displayedEvent = event;
group.events << event;
beginInsertRows(QModelIndex(), pos, pos);
mEventGroups.insert(pos, group);
endInsertRows();
}
}
}
QHash HistoryGroupedEventsModel::roleNames() const
{
QHash roles = HistoryEventModel::roleNames();
roles[EventsRole] = "events";
roles[EventCountRole] = "eventCount";
return roles;
}
void HistoryGroupedEventsModel::updateQuery()
{
// remove all event groups from the model
if (!mEventGroups.isEmpty()) {
beginRemoveRows(QModelIndex(), 0, mEventGroups.count() - 1);
mEventGroups.clear();
endRemoveRows();
}
// and ask HistoryEventModel to update the query and fetch items again
HistoryEventModel::updateQuery();
}
void HistoryGroupedEventsModel::onEventsAdded(const History::Events &events)
{
if (!events.count()) {
return;
}
Q_FOREACH(const History::Event &event, events) {
int pos = positionForItem(event.properties());
// check if the event belongs to the group at the position
if (pos >= 0 && pos < mEventGroups.count()) {
HistoryEventGroup &group = mEventGroups[pos];
if (areOfSameGroup(event, group.displayedEvent)) {
addEventToGroup(event, group, pos);
continue;
}
}
// else, we just create a new group
beginInsertRows(QModelIndex(), pos, pos);
HistoryEventGroup group;
group.displayedEvent = event;
group.events << event;
mEventGroups.insert(pos, group);
endInsertRows();
}
}
void HistoryGroupedEventsModel::onEventsModified(const History::Events &events)
{
// FIXME: we are not yet handling events changing the property used for sorting
// so for now the behavior is to find the item and check if it needs inserting or
// updating in the group, which is exactly what onEventsAdded() does, so:
onEventsAdded(events);
}
void HistoryGroupedEventsModel::onEventsRemoved(const History::Events &events)
{
Q_FOREACH(const History::Event &event, events) {
int pos = positionForItem(event.properties());
if (pos < 0 || pos >= rowCount()) {
continue;
}
HistoryEventGroup &group = mEventGroups[pos];
if (!group.events.contains(event)) {
continue;
}
removeEventFromGroup(event, group, pos);
}
}
bool HistoryGroupedEventsModel::areOfSameGroup(const History::Event &event1, const History::Event &event2)
{
QVariantMap props1 = event1.properties();
QVariantMap props2 = event2.properties();
Q_FOREACH(const QString &property, mGroupingProperties) {
// first check if the property exists in the maps
if (!props1.contains(property) || !props2.contains(property)) {
return false;
}
// get one of the account ids to use for comparing
QString accountId = props1[History::FieldAccountId].toString();
// now check if the values are the same
if (property == History::FieldParticipants) {
if (!History::Utils::compareParticipants(event1.participants().identifiers(),
event2.participants().identifiers(),
History::Utils::matchFlagsForAccount(accountId))) {
return false;
}
} else if (props1[property] != props2[property]) {
return false;
}
}
// if it didn't fail before, the events are indeed of the same group
return true;
}
void HistoryGroupedEventsModel::addEventToGroup(const History::Event &event, HistoryEventGroup &group, int row)
{
if (!group.events.contains(event)) {
// insert the event in the correct position according to the sort criteria
bool append = true;
for (int i = 0; i < group.events.count(); ++i) {
History::Event &otherEvent = group.events[i];
if (isAscending() ? lessThan(event.properties(), otherEvent.properties()) :
lessThan(otherEvent.properties(), event.properties())) {
group.events.insert(i, event);
append = false;
break;
}
}
// if it is not above any item, just append it
if (append) {
group.events.append(event);
}
}
// now check if the displayed event should be updated
History::Event &firstEvent = group.events.first();
if (group.displayedEvent != firstEvent) {
group.displayedEvent = firstEvent;
QModelIndex idx(index(row));
Q_EMIT dataChanged(idx, idx);
}
}
void HistoryGroupedEventsModel::removeEventFromGroup(const History::Event &event, HistoryEventGroup &group, int row)
{
if (group.events.contains(event)) {
group.events.removeOne(event);
}
if (group.events.isEmpty()) {
beginRemoveRows(QModelIndex(), row, row);
mEventGroups.removeAt(row);
endRemoveRows();
return;
}
if (group.displayedEvent == event) {
// check what is the event that should be displayed
group.displayedEvent = group.events.first();
Q_FOREACH(const History::Event &other, group.events) {
if (isAscending() ? lessThan(other.properties(), group.displayedEvent.properties()) :
lessThan(group.displayedEvent.properties(), other.properties())) {
group.displayedEvent = other;
}
}
}
QModelIndex idx = index(row);
Q_EMIT dataChanged(idx, idx);
}
QVariant HistoryGroupedEventsModel::get(int row) const
{
if (row >= rowCount() || row < 0) {
return QVariant();
}
return data(index(row), EventsRole);
}
QStringList HistoryGroupedEventsModel::groupingProperties() const
{
return mGroupingProperties;
}
void HistoryGroupedEventsModel::setGroupingProperties(const QStringList &properties)
{
mGroupingProperties = properties;
Q_EMIT groupingPropertiesChanged();
triggerQueryUpdate();
}
history-service-0.5/Lomiri/History/historygroupedeventsmodel.h 0000664 0000000 0000000 00000004753 14554502467 0025144 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYGROUPEDEVENTSMODEL_H
#define HISTORYGROUPEDEVENTSMODEL_H
#include "historyeventmodel.h"
typedef struct {
History::Events events;
History::Event displayedEvent;
} HistoryEventGroup;
class HistoryGroupedEventsModel : public HistoryEventModel
{
Q_OBJECT
Q_PROPERTY(QStringList groupingProperties
READ groupingProperties
WRITE setGroupingProperties
NOTIFY groupingPropertiesChanged)
Q_ENUMS(GroupedRole)
public:
enum GroupedRole {
EventsRole = HistoryEventModel::LastEventRole,
EventCountRole
};
explicit HistoryGroupedEventsModel(QObject *parent = 0);
// reimplemented from HistoryEventModel
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
Q_INVOKABLE void fetchMore(const QModelIndex &parent = QModelIndex());
QHash roleNames() const;
Q_INVOKABLE QVariant get(int row) const;
QStringList groupingProperties() const;
void setGroupingProperties(const QStringList &properties);
Q_SIGNALS:
void groupingPropertiesChanged();
protected Q_SLOTS:
void updateQuery();
void onEventsAdded(const History::Events &events);
void onEventsModified(const History::Events &events);
void onEventsRemoved(const History::Events &events);
protected:
bool areOfSameGroup(const History::Event &event1, const History::Event &event2);
void addEventToGroup(const History::Event &event, HistoryEventGroup &group, int row);
void removeEventFromGroup(const History::Event &event, HistoryEventGroup &group, int row);
private:
QStringList mGroupingProperties;
QList mEventGroups;
};
#endif // HISTORYGROUPEDEVENTSMODEL_H
history-service-0.5/Lomiri/History/historygroupedthreadsmodel.cpp 0000664 0000000 0000000 00000030070 14554502467 0025614 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2015 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historygroupedthreadsmodel.h"
#include "utils_p.h"
#include "manager.h"
#include "phoneutils_p.h"
#include
#include
#include
HistoryGroupedThreadsModel::HistoryGroupedThreadsModel(QObject *parent) :
HistoryThreadModel(parent)
{
qDBusRegisterMetaType >();
qRegisterMetaType >();
mGroupThreads = true;
mRoles = HistoryThreadModel::roleNames();
mRoles[ThreadsRole] = "threads";
}
QVariant HistoryGroupedThreadsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
const HistoryThreadGroup &group = mGroups[index.row()];
// get the data from the latest thread, and overwrite if necessary
QVariant result = threadData(group.displayedThread, role);
switch (role) {
case HistoryThreadModel::CountRole: {
int count = 0;
Q_FOREACH(const History::Thread &thread, group.threads) {
count += thread.count();
}
result = count;
break;
}
case HistoryThreadModel::UnreadCountRole: {
int count = 0;
Q_FOREACH(const History::Thread &thread, group.threads) {
count += thread.unreadCount();
}
result = count;
break;
}
case ThreadsRole: {
QVariantList threads;
Q_FOREACH(const History::Thread &thread, group.threads) {
threads << thread.properties();
}
result = threads;
break;
}
}
if (result.isNull()) {
// get the shared roles
result = HistoryModel::data(index, role);
}
return result;
}
void HistoryGroupedThreadsModel::fetchMore(const QModelIndex &parent)
{
if (!canFetchMore(parent)) {
return;
}
const History::Threads &threads = fetchNextPage();
Q_FOREACH(const History::Thread &thread, threads) {
processThreadGrouping(thread);
// insert the identifiers in the contact map
Q_FOREACH(const History::Participant &participant, thread.participants()) {
watchContactInfo(thread.accountId(), participant.identifier(), participant.properties());
}
}
notifyDataChanged();
if (threads.isEmpty()) {
mCanFetchMore = false;
Q_EMIT canFetchMoreChanged();
}
}
QHash HistoryGroupedThreadsModel::roleNames() const
{
return mRoles;
}
QVariant HistoryGroupedThreadsModel::get(int row) const
{
if (row >= rowCount() || row < 0) {
return QVariant();
}
return data(index(row), ThreadsRole);
}
int HistoryGroupedThreadsModel::existingPositionForEntry(const History::Thread &thread) const
{
int pos = -1;
if (mGroupingProperty == History::FieldParticipants) {
for (int i = 0; i < mGroups.count(); ++i) {
const HistoryThreadGroup &group = mGroups[i];
Q_FOREACH(const History::Thread &groupedThread, group.threads) {
History::Threads threads;
// when removing threads, we cant get the grouped threads from history
if (thread.groupedThreads().size() == 0) {
threads << thread;
} else {
threads = thread.groupedThreads();
}
Q_FOREACH(const History::Thread &groupedThread2, threads) {
if (groupedThread == groupedThread2) {
return i;
}
}
}
}
return pos;
}
for (int i = 0; i < mGroups.count(); ++i) {
const HistoryThreadGroup &group = mGroups[i];
if (thread.properties()[mGroupingProperty] == group.displayedThread.properties()[mGroupingProperty]) {
pos = i;
break;
}
}
return pos;
}
void HistoryGroupedThreadsModel::removeGroup(const HistoryThreadGroup &group)
{
int pos = mGroups.indexOf(group);
if (pos >= 0){
beginRemoveRows(QModelIndex(), pos, pos);
mGroups.removeAt(pos);
endRemoveRows();
}
}
void HistoryGroupedThreadsModel::updateDisplayedThread(HistoryThreadGroup &group)
{
int pos = mGroups.indexOf(group);
if (pos < 0) {
qWarning() << "Group not found!!";
return;
}
History::Thread displayedThread = group.threads.first();
QVariantMap displayedProperties = displayedThread.properties();
Q_FOREACH(const History::Thread &other, group.threads) {
if (isAscending() ? lessThan(other.properties(), displayedProperties) :
lessThan(displayedProperties, other.properties())) {
displayedThread = other;
displayedProperties = displayedThread.properties();
}
}
// check if we need to update the order
int newPos = positionForItem(displayedProperties);
// NOTE: only set the new displayedThread AFTER calling positionForItem
group.displayedThread = displayedThread;
// the positionForItem function might return the pos+1 value for the current item as it considers
// this to be the position for a new insertion
if (newPos != pos && newPos != pos+1) {
beginMoveRows(QModelIndex(), pos, pos, QModelIndex(), newPos);
// QList::move() behaves in a different way than the QAbstractItemModel moving functions
// that's why the delta was added
mGroups.move(pos, newPos > pos ? newPos-1 : newPos);
endMoveRows();
}
}
History::Threads HistoryGroupedThreadsModel::restoreParticipants(const History::Threads &oldThreads, const History::Threads &newThreads)
{
History::Threads updated = newThreads;
for(History::Thread &thread : updated) {
if (!thread.participants().isEmpty()) {
continue;
}
int i = oldThreads.indexOf(thread);
if (i >=0) {
thread.addParticipants(oldThreads[i].participants());
}
}
return updated;
}
void HistoryGroupedThreadsModel::updateQuery()
{
// remove all entries and call the query update
if (!mGroups.isEmpty()) {
beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
mGroups.clear();
endRemoveRows();
}
HistoryThreadModel::updateQuery();
}
void HistoryGroupedThreadsModel::onThreadsAdded(const History::Threads &threads)
{
Q_FOREACH(const History::Thread &thread, threads) {
processThreadGrouping(thread);
}
fetchParticipantsIfNeeded(threads);
notifyDataChanged();
}
void HistoryGroupedThreadsModel::onThreadsModified(const History::Threads &threads)
{
Q_FOREACH(const History::Thread &thread, threads) {
processThreadGrouping(thread);
}
fetchParticipantsIfNeeded(threads);
notifyDataChanged();
}
void HistoryGroupedThreadsModel::onThreadsRemoved(const History::Threads &threads)
{
Q_FOREACH(const History::Thread &thread, threads) {
removeThreadFromGroup(thread);
}
notifyDataChanged();
}
void HistoryGroupedThreadsModel::onThreadParticipantsChanged(const History::Thread &thread, const History::Participants &added, const History::Participants &removed, const History::Participants &modified)
{
int pos = existingPositionForEntry(thread);
if (pos >= 0) {
HistoryThreadGroup &group = mGroups[pos];
if (group.displayedThread == thread) {
group.displayedThread.removeParticipants(removed);
group.displayedThread.removeParticipants(modified);
group.displayedThread.addParticipants(added);
group.displayedThread.addParticipants(modified);
}
Q_FOREACH(const History::Thread &existingThread, group.threads) {
if (existingThread == thread) {
History::Thread modifiedThread = existingThread;
group.threads.removeOne(existingThread);
modifiedThread.removeParticipants(removed);
modifiedThread.removeParticipants(modified);
modifiedThread.addParticipants(added);
modifiedThread.addParticipants(modified);
group.threads.append(modifiedThread);
}
}
QModelIndex idx = index(pos);
Q_EMIT dataChanged(idx, idx);
}
// watch the contact info for the received participants
Q_FOREACH(const History::Participant &participant, added) {
watchContactInfo(thread.accountId(), participant.identifier(), participant.properties());
}
Q_FOREACH(const History::Participant &participant, modified) {
watchContactInfo(thread.accountId(), participant.identifier(), participant.properties());
}
}
void HistoryGroupedThreadsModel::processThreadGrouping(const History::Thread &thread)
{
QVariantMap queryProperties;
queryProperties[History::FieldGroupingProperty] = mGroupingProperty;
History::Thread groupedThread = History::Manager::instance()->getSingleThread((History::EventType)mType, thread.accountId(), thread.threadId(), queryProperties);
if (groupedThread.properties().isEmpty()) {
removeThreadFromGroup(thread);
return;
}
int pos = existingPositionForEntry(groupedThread);
// if the group is empty, we need to insert it into the map
if (pos < 0) {
HistoryThreadGroup group;
int newPos = positionForItem(groupedThread.properties());
group.threads = groupedThread.groupedThreads();
group.displayedThread = groupedThread;
beginInsertRows(QModelIndex(), newPos, newPos);
mGroups.insert(newPos, group);
endInsertRows();
return;
}
HistoryThreadGroup &group = mGroups[pos];
group.threads = restoreParticipants(group.threads, groupedThread.groupedThreads());
updateDisplayedThread(group);
markGroupAsChanged(group);
}
void HistoryGroupedThreadsModel::removeThreadFromGroup(const History::Thread &thread)
{
QVariantMap properties = thread.properties();
int pos = existingPositionForEntry(thread);
if (pos < 0) {
qWarning() << "Could not find group for property " << properties[mGroupingProperty];
return;
}
HistoryThreadGroup &group = mGroups[pos];
group.threads.removeAll(thread);
if (group.threads.isEmpty()) {
removeGroup(group);
} else {
updateDisplayedThread(group);
markGroupAsChanged(group);
}
}
void HistoryGroupedThreadsModel::markGroupAsChanged(const HistoryThreadGroup &group)
{
if (!mChangedGroups.contains(group)) {
mChangedGroups.append(group);
}
}
void HistoryGroupedThreadsModel::notifyDataChanged()
{
Q_FOREACH(const HistoryThreadGroup &group, mChangedGroups) {
int pos = mGroups.indexOf(group);
if (pos >= 0) {
QModelIndex idx = index(pos);
Q_EMIT dataChanged(idx, idx);
} else {
qWarning() << "Group not found!";
}
}
mChangedGroups.clear();
}
QString HistoryGroupedThreadsModel::groupingProperty() const
{
return mGroupingProperty;
}
void HistoryGroupedThreadsModel::setGroupingProperty(const QString &value)
{
mGroupingProperty = value;
Q_EMIT groupingPropertyChanged();
triggerQueryUpdate();
}
int HistoryGroupedThreadsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return mGroups.count();
}
bool HistoryThreadGroup::operator==(const HistoryThreadGroup &other) const
{
return displayedThread == other.displayedThread;
}
history-service-0.5/Lomiri/History/historygroupedthreadsmodel.h 0000664 0000000 0000000 00000006315 14554502467 0025266 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYGROUPEDTHREADSMODEL_H
#define HISTORYGROUPEDTHREADSMODEL_H
#include "historythreadmodel.h"
#include
class HistoryThreadGroup {
public:
History::Thread displayedThread;
History::Threads threads;
bool operator==(const HistoryThreadGroup &other) const;
};
typedef QList HistoryThreadGroupList;
class HistoryGroupedThreadsModel : public HistoryThreadModel
{
Q_OBJECT
Q_PROPERTY(QString groupingProperty
READ groupingProperty
WRITE setGroupingProperty
NOTIFY groupingPropertyChanged)
Q_ENUMS(CustomRoles)
public:
enum CustomRoles {
ThreadsRole = LastThreadRole
};
explicit HistoryGroupedThreadsModel(QObject *parent = 0);
QString groupingProperty() const;
void setGroupingProperty(const QString &value);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role) const;
Q_INVOKABLE void fetchMore(const QModelIndex &parent = QModelIndex());
virtual QHash roleNames() const;
Q_INVOKABLE QVariant get(int row) const;
Q_SIGNALS:
void groupingPropertyChanged();
protected:
int existingPositionForEntry(const History::Thread &thread) const;
void removeGroup(const HistoryThreadGroup &group);
void updateDisplayedThread(HistoryThreadGroup &group);
History::Threads restoreParticipants(const History::Threads &oldThreads, const History::Threads &newThreads);
protected Q_SLOTS:
virtual void updateQuery();
virtual void onThreadsAdded(const History::Threads &threads);
virtual void onThreadsModified(const History::Threads &threads);
virtual void onThreadsRemoved(const History::Threads &threads);
void onThreadParticipantsChanged(const History::Thread &thread,
const History::Participants &added,
const History::Participants &removed,
const History::Participants &modified) override;
private Q_SLOTS:
void processThreadGrouping(const History::Thread &thread);
void removeThreadFromGroup(const History::Thread &thread);
void markGroupAsChanged(const HistoryThreadGroup &group);
void notifyDataChanged();
private:
QString mGroupingProperty;
HistoryThreadGroupList mGroups;
QList mChangedGroups;
QHash mRoles;
};
#endif // HISTORYGROUPEDTHREADSMODEL_H
history-service-0.5/Lomiri/History/historymanager.cpp 0000664 0000000 0000000 00000006033 14554502467 0023167 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2021 UBports Foundation
*
* Authors:
* Lionel Duboeuf
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historymanager.h"
#include "event.h"
#include "manager.h"
#include "types.h"
#include
#include
HistoryManager::HistoryManager(QObject *parent) :
QObject(parent), mPendingOperation(false)
{
}
void HistoryManager::removeEvents(int eventType, const QString &maxDate, const QJSValue &callback)
{
if (!callback.isCallable()) {
qCritical() << "no callback found!";
return;
}
QJSValue result(callback);
if (mPendingOperation) {
result.call(QJSValueList { 0, OperationError::OPERATION_ALREADY_PENDING });
qWarning() << "there is a pending operation, request cancelled";
return;
}
QDateTime fromDate = QDateTime::fromString(maxDate, Qt::ISODate);
History::EventType type = (History::EventType) eventType;
if (type == History::EventTypeNull|| !fromDate.isValid()) {
result.call(QJSValueList { 0, OperationError::OPERATION_INVALID });
qWarning() << "invalid type or date, request cancelled";
return;
}
History::Filter queryFilter(History::FieldTimestamp, QVariant(maxDate), History::MatchLess);
if (!queryFilter.isValid()) {
result.call(QJSValueList { 0, OperationError::OPERATION_INVALID });
qWarning() << "invalid filter, operation cancelled";
return;
}
auto onCompleted = [this, callback](int removedCount, bool isError) {
QJSValue result(callback);
OperationError error = isError ? OperationError::OPERATION_FAILED : OperationError::NO_ERROR;
result.call(QJSValueList { removedCount, error });
};
History::Manager::instance()->removeEvents(type, queryFilter, onCompleted);
}
int HistoryManager::getEventsCount(int eventType, const QString &maxDate)
{
QDateTime fromDate = QDateTime::fromString(maxDate, Qt::ISODate);
History::EventType type = (History::EventType) eventType;
if (type == History::EventTypeNull|| !fromDate.isValid()) {
qWarning() << "invalid type or date, request cancelled";
return -1;
}
History::Filter queryFilter(History::FieldTimestamp, QVariant(maxDate), History::MatchLess);
if (!queryFilter.isValid()) {
qWarning() << "invalid filter, request cancelled";
return -1;
}
return History::Manager::instance()->getEventsCount(type, queryFilter);
}
history-service-0.5/Lomiri/History/historymanager.h 0000664 0000000 0000000 00000004045 14554502467 0022635 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2021 UBports Foundation
*
* Authors:
* Lionel Duboeuf
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYMANAGER_H
#define HISTORYMANAGER_H
#include
#include
#include "historymodel.h"
class HistoryManager : public QObject
{
Q_OBJECT
public:
enum OperationError {
NO_ERROR,
OPERATION_ALREADY_PENDING,
OPERATION_INVALID,
OPERATION_FAILED,
OPERATION_TIMEOUT
};
Q_ENUM(OperationError)
explicit HistoryManager(QObject *parent = 0);
/*!
* \brief removeEvents remove all events given eventType and created before maxDate,
* \param eventType event type according to History.EventType
* \param maxDate QString date in ISO format
* \param callback expect a javascript function(deletedEventsCount, error)
* deletedEventsCount number of deleted events
* error HistoryManager::OperationError enum type,
*/
Q_INVOKABLE void removeEvents(int eventType, const QString &maxDate, const QJSValue &callback);
/*!
* \brief getEventsCount return the number of events given eventType and created before maxDate
* \param eventType event type according to History.EventType
* \param maxDate QString date in ISO format
* \return number of events count
*/
Q_INVOKABLE int getEventsCount(int eventType, const QString &maxDate);
private:
bool mPendingOperation;
};
#endif // HISTORYMANAGER_H
history-service-0.5/Lomiri/History/historymodel.cpp 0000664 0000000 0000000 00000052322 14554502467 0022657 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2016 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historymodel.h"
#include "historyqmlfilter.h"
#include "historyqmlsort.h"
#include "contactmatcher_p.h"
#include "phoneutils_p.h"
#include "thread.h"
#include "textevent.h"
#include "manager.h"
#include "utils_p.h"
#include "voiceevent.h"
#include
#include
#include
HistoryModel::HistoryModel(QObject *parent) :
QAbstractListModel(parent), mFilter(0), mSort(new HistoryQmlSort(this)),
mType(EventTypeText), mMatchContacts(false), mUpdateTimer(0), mEventWritingTimer(0), mThreadWritingTimer(0), mWaitingForQml(false)
{
// configure the roles
mRoles[AccountIdRole] = "accountId";
mRoles[ThreadIdRole] = "threadId";
mRoles[ParticipantsRole] = "participants";
mRoles[ParticipantsRemotePendingRole] = "remotePendingParticipants";
mRoles[ParticipantsLocalPendingRole] = "localPendingParticipants";
mRoles[TypeRole] = "type";
mRoles[TimestampRole] = "timestamp";
mRoles[SentTimeRole] = "sentTime";
mRoles[PropertiesRole] = "properties";
connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()));
connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()));
connect(this, SIGNAL(modelReset()), this, SIGNAL(countChanged()));
// reset the view when the service is stopped or started
connect(History::Manager::instance(), SIGNAL(serviceRunningChanged()),
this, SLOT(triggerQueryUpdate()));
// create the view and get some objects
triggerQueryUpdate();
}
bool HistoryModel::canFetchMore(const QModelIndex& /* parent */) const
{
return false;
}
void HistoryModel::fetchMore(const QModelIndex &parent)
{
Q_UNUSED(parent)
// do nothing, just make the method invokable
}
QHash HistoryModel::roleNames() const
{
return mRoles;
}
QVariant HistoryModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
return QVariant();
}
QVariantMap properties = index.data(PropertiesRole).toMap();
QVariant result;
switch (role) {
case AccountIdRole:
result = properties[History::FieldAccountId];
break;
case ThreadIdRole:
result = properties[History::FieldThreadId];
break;
case TypeRole:
result = properties[History::FieldType];
break;
case ParticipantsRole: {
History::Participants participants = History::Participants::fromVariantList(properties[History::FieldParticipants].toList())
.filterByState(History::ParticipantStateRegular);
if (mMatchContacts) {
QVariantList finalParticipantsList;
QVariantList participantsInfo = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
participants.identifiers());
for (int i = 0; i < participantsInfo.count(); ++i) {
QVariantMap newMap = participantsInfo[i].toMap();
History::Participant participant = participants[i];
newMap[History::FieldParticipantState] = participant.state();
newMap[History::FieldParticipantRoles] = participant.roles();
finalParticipantsList << newMap;
}
result = finalParticipantsList;
} else {
//FIXME: handle contact changes
result = participants.identifiers();
}
break;
}
case ParticipantsRemotePendingRole: {
History::Participants participants = History::Participants::fromVariantList(properties[History::FieldParticipants].toList())
.filterByState(History::ParticipantStateRemotePending);
if (mMatchContacts) {
QVariantList finalParticipantsList;
QVariantList participantsInfo = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
participants.identifiers());
int count = 0;
Q_FOREACH(const QVariant &participantInfo, participantsInfo) {
QVariantMap newMap = participantInfo.toMap();
newMap[History::FieldParticipantState] = participants.at(count).state();
newMap[History::FieldParticipantRoles] = participants.at(count++).roles();
finalParticipantsList << newMap;
}
result = finalParticipantsList;
} else {
//FIXME: handle contact changes
result = participants.identifiers();
}
break;
}
case ParticipantsLocalPendingRole: {
History::Participants participants = History::Participants::fromVariantList(properties[History::FieldParticipants].toList())
.filterByState(History::ParticipantStateLocalPending);
if (mMatchContacts) {
QVariantList finalParticipantsList;
QVariantList participantsInfo = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
participants.identifiers());
int count = 0;
Q_FOREACH(const QVariant &participantInfo, participantsInfo) {
QVariantMap newMap = participantInfo.toMap();
newMap[History::FieldParticipantState] = participants.at(count).state();
newMap[History::FieldParticipantRoles] = participants.at(count++).roles();
finalParticipantsList << newMap;
}
result = finalParticipantsList;
} else {
//FIXME: handle contact changes
result = participants.identifiers();
}
break;
}
case ParticipantIdsRole:
result = History::Participants::fromVariantList(properties[History::FieldParticipants].toList()).identifiers();
break;
case TimestampRole:
result = QDateTime::fromString(properties[History::FieldTimestamp].toString(), Qt::ISODate);
break;
case SentTimeRole:
result = QDateTime::fromString(properties[History::FieldSentTime].toString(), Qt::ISODate);
break;
}
return result;
}
HistoryQmlFilter *HistoryModel::filter() const
{
return mFilter;
}
void HistoryModel::setFilter(HistoryQmlFilter *value)
{
if (mFilter) {
mFilter->disconnect(this);
}
mFilter = value;
if (mFilter) {
connect(mFilter,
SIGNAL(filterChanged()),
SLOT(triggerQueryUpdate()));
}
Q_EMIT filterChanged();
triggerQueryUpdate();
}
HistoryQmlSort *HistoryModel::sort() const
{
return mSort;
}
void HistoryModel::setSort(HistoryQmlSort *value)
{
// disconnect the previous sort
if (mSort) {
mSort->disconnect(this);
}
mSort = value;
if (mSort) {
connect(mSort,
SIGNAL(sortChanged()),
SLOT(triggerQueryUpdate()));
}
Q_EMIT sortChanged();
triggerQueryUpdate();
}
HistoryModel::EventType HistoryModel::type() const
{
return mType;
}
void HistoryModel::setType(EventType value)
{
mType = value;
Q_EMIT typeChanged();
triggerQueryUpdate();
}
bool HistoryModel::matchContacts() const
{
return mMatchContacts;
}
void HistoryModel::setMatchContacts(bool value)
{
if (mMatchContacts == value) {
return;
}
mMatchContacts = value;
Q_EMIT matchContactsChanged();
if (mMatchContacts) {
connect(History::ContactMatcher::instance(),
SIGNAL(contactInfoChanged(QString,QString,QVariantMap)),
SLOT(onContactInfoChanged(QString,QString,QVariantMap)));
} else {
History::ContactMatcher::instance()->disconnect(this);
}
// mark all indexes as changed
if (rowCount() > 0) {
Q_EMIT dataChanged(index(0), index(rowCount()-1));
}
}
QVariantMap HistoryModel::threadForProperties(const QString &accountId, int eventType, const QVariantMap &properties, int matchFlags, bool create)
{
QVariantMap newProperties = properties;
if (properties.isEmpty()) {
return QVariantMap();
}
if (newProperties.contains(History::FieldParticipantIds)) {
newProperties[History::FieldParticipantIds] = newProperties[History::FieldParticipantIds].toStringList();
}
History::Thread thread = History::Manager::instance()->threadForProperties(accountId,
(History::EventType)eventType,
newProperties,
(History::MatchFlags)matchFlags,
create);
if (!thread.isNull()) {
return thread.properties();
}
return QVariantMap();
}
QString HistoryModel::threadIdForProperties(const QString &accountId, int eventType, const QVariantMap &properties, int matchFlags, bool create)
{
QVariantMap newProperties = properties;
if (properties.isEmpty()) {
return QString();
}
if (newProperties.contains(History::FieldParticipantIds)) {
newProperties[History::FieldParticipantIds] = newProperties[History::FieldParticipantIds].toStringList();
}
History::Thread thread = History::Manager::instance()->threadForProperties(accountId,
(History::EventType)eventType,
newProperties,
(History::MatchFlags)matchFlags,
create);
if (!thread.isNull()) {
return thread.threadId();
}
return QString();
}
QVariantMap HistoryModel::threadForParticipants(const QString &accountId, int eventType, const QStringList &participants, int matchFlags, bool create)
{
if (participants.isEmpty()) {
return QVariantMap();
}
QVariantMap properties;
properties[History::FieldParticipantIds] = participants;
History::Thread thread = History::Manager::instance()->threadForProperties(accountId,
(History::EventType)eventType,
properties,
(History::MatchFlags)matchFlags,
create);
if (!thread.isNull()) {
return thread.properties();
}
return QVariantMap();
}
QString HistoryModel::threadIdForParticipants(const QString &accountId, int eventType, const QStringList &participants, int matchFlags, bool create)
{
if (participants.isEmpty()) {
return QString();
}
QVariantMap properties;
properties[History::FieldParticipantIds] = participants;
History::Thread thread = History::Manager::instance()->threadForProperties(accountId,
(History::EventType)eventType,
properties,
(History::MatchFlags)matchFlags,
create);
if (!thread.isNull()) {
return thread.threadId();
}
return QString();
}
void HistoryModel::requestThreadParticipants(const QVariantList &threads)
{
History::Threads theThreads;
Q_FOREACH(const QVariant &threadVariant, threads) {
History::Thread theThread = History::Thread::fromProperties(threadVariant.toMap());
// if the given thread already has the list of participants, there is no point
// in fetching it again
if (theThread.participants().isEmpty()) {
theThreads << theThread;
}
}
History::Manager::instance()->requestThreadParticipants(theThreads);
}
bool HistoryModel::writeTextInformationEvent(const QString &accountId, const QString &threadId, const QStringList &participants, const QString &message, int informationType, const QString &subject)
{
if (participants.isEmpty() || threadId.isEmpty() || accountId.isEmpty()) {
return false;
}
History::TextEvent historyEvent = History::TextEvent(accountId,
threadId,
QString(QCryptographicHash::hash(QByteArray(
QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmsszzz").toLatin1()),
QCryptographicHash::Md5).toHex()),
"self",
QDateTime::currentDateTime(),
QDateTime::currentDateTime(),
false,
message,
History::MessageTypeInformation,
History::MessageStatusUnknown,
QDateTime::currentDateTime(),
subject,
(History::InformationType)informationType);
History::Events events;
events << historyEvent;
return History::Manager::instance()->writeEvents(events);
}
void HistoryModel::onContactInfoChanged(const QString &accountId, const QString &identifier, const QVariantMap &contactInfo)
{
Q_UNUSED(contactInfo)
if (!mMatchContacts) {
return;
}
QList changedIndexes;
int count = rowCount();
for (int i = 0; i < count; ++i) {
// WARNING: do not use mEvents directly to verify which indexes to change as there is the
// HistoryGroupedEventsModel which is based on this model and handles the items in a different way
QModelIndex idx = index(i);
QVariantMap properties = idx.data(PropertiesRole).toMap();
History::Participants participants = History::Participants::fromVariantList(properties[History::FieldParticipants].toList());
Q_FOREACH(const History::Participant &participant, participants) {
// FIXME: right now we might be grouping threads from different accounts, so we are not enforcing
// the accountId to be the same as the one from the contact info, but maybe we need to do that
// in the future?
if (History::Utils::compareIds(accountId, History::ContactMatcher::normalizeId(participant.identifier()), identifier)) {
changedIndexes << idx;
}
}
}
// now emit the dataChanged signal to all changed indexes
Q_FOREACH(const QModelIndex &idx, changedIndexes) {
Q_EMIT dataChanged(idx, idx);
}
}
void HistoryModel::watchContactInfo(const QString &accountId, const QString &identifier, const QVariantMap ¤tInfo)
{
if (mMatchContacts) {
History::ContactMatcher::instance()->watchIdentifier(accountId, identifier, currentInfo);
}
}
void HistoryModel::timerEvent(QTimerEvent *event)
{
if (event->timerId() == mUpdateTimer) {
if (!mWaitingForQml) {
killTimer(mUpdateTimer);
mUpdateTimer = 0;
updateQuery();
}
} else if (event->timerId() == mEventWritingTimer) {
killTimer(mEventWritingTimer);
mEventWritingTimer = 0;
if (mEventWritingQueue.isEmpty()) {
return;
}
if (History::Manager::instance()->writeEvents(mEventWritingQueue)) {
mEventWritingQueue.clear();
}
} else if (event->timerId() == mThreadWritingTimer) {
killTimer(mThreadWritingTimer);
mThreadWritingTimer = 0;
if (mThreadWritingQueue.isEmpty()) {
return;
}
History::Manager::instance()->markThreadsAsRead(mThreadWritingQueue);
mThreadWritingQueue.clear();
}
}
bool HistoryModel::lessThan(const QVariantMap &left, const QVariantMap &right) const
{
QStringList sortFields = sort()->sortField().split(",");
while(!sortFields.isEmpty()) {
QString sortField = sortFields.takeFirst().trimmed();
QVariant leftValue = left.value(sortField, QVariant());
QVariant rightValue = right.value(sortField, QVariant());
if (leftValue != rightValue) {
return leftValue < rightValue;
}
}
return false;
}
int HistoryModel::positionForItem(const QVariantMap &item) const
{
// do a binary search for the item position on the list
int lowerBound = 0;
int upperBound = rowCount() - 1;
if (upperBound < 0) {
return 0;
}
while (true) {
int pos = (upperBound + lowerBound) / 2;
const QVariantMap posItem = index(pos).data(PropertiesRole).toMap();
if (lowerBound == pos) {
if (isAscending() ? lessThan(item, posItem) : lessThan(posItem, item)) {
return pos;
}
}
if (isAscending() ? lessThan(posItem, item) : lessThan(item, posItem)) {
lowerBound = pos + 1; // its in the upper
if (lowerBound > upperBound) {
return pos += 1;
}
} else if (lowerBound > upperBound) {
return pos;
} else {
upperBound = pos - 1; // its in the lower
}
}
}
bool HistoryModel::isAscending() const
{
return mSort && mSort->sort().sortOrder() == Qt::AscendingOrder;
}
QVariant HistoryModel::get(int row) const
{
QVariantMap data;
QModelIndex idx = index(row, 0);
if (idx.isValid()) {
QHash roles = roleNames();
Q_FOREACH(int role, roles.keys()) {
data.insert(roles[role], idx.data(role));
}
}
return data;
}
bool HistoryModel::markEventAsRead(const QVariantMap &eventProperties)
{
History::Event event;
History::EventType type = (History::EventType) eventProperties[History::FieldType].toInt();
switch (type) {
case History::EventTypeText:
event = History::TextEvent::fromProperties(eventProperties);
break;
case History::EventTypeVoice:
event = History::VoiceEvent::fromProperties(eventProperties);
break;
case History::EventTypeNull:
qWarning("HistoryModel::markEventAsRead: Got EventTypeNull, ignoring this event!");
break;
}
event.setNewEvent(false);
if (event.type() == History::EventTypeText) {
History::TextEvent textEvent = event;
textEvent.setReadTimestamp(QDateTime::currentDateTime());
event = textEvent;
}
// for repeated events, keep the last called one only
if (mEventWritingQueue.contains(event)) {
mEventWritingQueue.removeOne(event);
}
mEventWritingQueue << event;
if (mEventWritingTimer != 0) {
killTimer(mEventWritingTimer);
}
mEventWritingTimer = startTimer(500);
return true;
}
void HistoryModel::markThreadsAsRead(const QVariantList &threadsProperties)
{
Q_FOREACH(const QVariant &entry, threadsProperties) {
QVariantMap threadProperties = entry.toMap();
History::Thread thread = History::Thread::fromProperties(threadProperties);
if (!thread.isNull()) {
if (mThreadWritingQueue.contains(thread)) {
continue;
}
mThreadWritingQueue << thread;
}
}
if (mThreadWritingTimer != 0) {
killTimer(mThreadWritingTimer);
}
mThreadWritingTimer = startTimer(2000);
}
void HistoryModel::classBegin()
{
mWaitingForQml = true;
}
void HistoryModel::componentComplete()
{
mWaitingForQml = false;
if (mUpdateTimer) {
killTimer(mUpdateTimer);
mUpdateTimer = 0;
}
updateQuery();
}
void HistoryModel::triggerQueryUpdate()
{
if (mUpdateTimer) {
killTimer(mUpdateTimer);
}
// delay the loading of the model data until the settings settle down
mUpdateTimer = startTimer(100);
}
history-service-0.5/Lomiri/History/historymodel.h 0000664 0000000 0000000 00000022045 14554502467 0022323 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2016 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYMODEL_H
#define HISTORYMODEL_H
#include "types.h"
#include "event.h"
#include "thread.h"
#include "historyqmlfilter.h"
#include "historyqmlsort.h"
#include
#include
#include
class HistoryModel : public QAbstractListModel, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(HistoryQmlFilter *filter READ filter WRITE setFilter NOTIFY filterChanged)
Q_PROPERTY(HistoryQmlSort *sort READ sort WRITE setSort NOTIFY sortChanged)
Q_PROPERTY(EventType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(bool matchContacts READ matchContacts WRITE setMatchContacts NOTIFY matchContactsChanged)
Q_PROPERTY(bool canFetchMore READ canFetchMore NOTIFY canFetchMoreChanged)
Q_ENUMS(ChatType)
Q_ENUMS(EventType)
Q_ENUMS(MessageType)
Q_ENUMS(MatchFlag)
Q_ENUMS(MessageStatus)
Q_ENUMS(AttachmentFlag)
Q_ENUMS(Role)
Q_ENUMS(InformationType)
public:
enum ChatType {
ChatTypeNone = History::ChatTypeNone,
ChatTypeContact = History::ChatTypeContact,
ChatTypeRoom = History::ChatTypeRoom
};
enum EventType {
EventTypeText = History::EventTypeText,
EventTypeVoice = History::EventTypeVoice
};
enum MessageType {
MessageTypeText = History::MessageTypeText,
MessageTypeMultiPart = History::MessageTypeMultiPart,
MessageTypeInformation = History::MessageTypeInformation
};
enum MatchFlag {
MatchCaseSensitive = History::MatchCaseSensitive,
MatchCaseInsensitive = History::MatchCaseInsensitive,
MatchContains = History::MatchContains,
MatchPhoneNumber = History::MatchPhoneNumber,
MatchNotEquals = History::MatchNotEquals,
MatchLess = History::MatchLess,
MatchGreater = History::MatchGreater,
MatchLessOrEquals = History::MatchLessOrEquals,
MatchGreaterOrEquals = History::MatchGreaterOrEquals
};
enum MessageStatus
{
MessageStatusUnknown = History::MessageStatusUnknown,
MessageStatusDelivered = History::MessageStatusDelivered,
MessageStatusTemporarilyFailed = History::MessageStatusTemporarilyFailed,
MessageStatusPermanentlyFailed = History::MessageStatusPermanentlyFailed,
MessageStatusAccepted = History::MessageStatusAccepted,
MessageStatusRead = History::MessageStatusRead,
MessageStatusDeleted = History::MessageStatusDeleted,
MessageStatusPending = History::MessageStatusPending, // pending attachment download
MessageStatusDraft = History::MessageStatusDraft
};
enum AttachmentFlag
{
AttachmentDownloaded = History::AttachmentDownloaded,
AttachmentPending = History::AttachmentPending,
AttachmentError = History::AttachmentError
};
enum InformationType
{
InformationTypeNone = History::InformationTypeNone,
InformationTypeSimChange = History::InformationTypeSimChange,
InformationTypeText = History::InformationTypeText,
InformationTypeSelfJoined = History::InformationTypeSelfJoined,
InformationTypeJoined = History::InformationTypeJoined,
InformationTypeTitleChanged = History::InformationTypeTitleChanged,
InformationTypeInvitationSent = History::InformationTypeInvitationSent,
InformationTypeLeaving = History::InformationTypeLeaving,
InformationTypeSelfLeaving = History::InformationTypeSelfLeaving,
InformationTypeAdminGranted = History::InformationTypeAdminGranted,
InformationTypeAdminRemoved = History::InformationTypeAdminRemoved,
InformationTypeSelfAdminGranted = History::InformationTypeSelfAdminGranted,
InformationTypeSelfAdminRemoved = History::InformationTypeSelfAdminRemoved,
InformationTypeSelfKicked = History::InformationTypeSelfKicked,
InformationTypeGroupGone = History::InformationTypeGroupGone
};
enum Role {
AccountIdRole = Qt::UserRole,
ThreadIdRole,
ParticipantsRole,
ParticipantsLocalPendingRole,
ParticipantsRemotePendingRole,
ParticipantIdsRole,
TypeRole,
TimestampRole,
SentTimeRole,
PropertiesRole,
LastRole
};
explicit HistoryModel(QObject *parent = 0);
Q_INVOKABLE virtual bool canFetchMore(const QModelIndex &parent = QModelIndex()) const;
Q_INVOKABLE virtual void fetchMore(const QModelIndex &parent = QModelIndex());
virtual QHash roleNames() const;
virtual QVariant data(const QModelIndex &index, int role) const;
HistoryQmlFilter *filter() const;
void setFilter(HistoryQmlFilter *value);
HistoryQmlSort *sort() const;
void setSort(HistoryQmlSort *value);
EventType type() const;
void setType(EventType value);
bool matchContacts() const;
void setMatchContacts(bool value);
Q_INVOKABLE QVariantMap threadForProperties(const QString &accountId,
int eventType,
const QVariantMap &properties,
int matchFlags = (int)History::MatchCaseSensitive,
bool create = false);
Q_INVOKABLE QString threadIdForProperties(const QString &accountId,
int eventType,
const QVariantMap &properties,
int matchFlags = (int)History::MatchCaseSensitive,
bool create = false);
Q_INVOKABLE QVariantMap threadForParticipants(const QString &accountId,
int eventType,
const QStringList &participants,
int matchFlags = (int)History::MatchCaseSensitive,
bool create = false);
Q_INVOKABLE QString threadIdForParticipants(const QString &accountId,
int eventType,
const QStringList &participants,
int matchFlags = (int)History::MatchCaseSensitive,
bool create = false);
Q_INVOKABLE void requestThreadParticipants(const QVariantList &threads);
Q_INVOKABLE bool writeTextInformationEvent(const QString &accountId,
const QString &threadId,
const QStringList &participants,
const QString &message,
int informationType = (int)History::InformationTypeNone,
const QString &subject = QString());
Q_INVOKABLE virtual QVariant get(int row) const;
// Marking events and threads as read
Q_INVOKABLE bool markEventAsRead(const QVariantMap &eventProperties);
Q_INVOKABLE void markThreadsAsRead(const QVariantList &threadsProperties);
// QML parser status things
void classBegin();
void componentComplete();
Q_SIGNALS:
void countChanged();
void filterChanged();
void sortChanged();
void typeChanged();
void matchContactsChanged();
void canFetchMoreChanged();
protected Q_SLOTS:
void triggerQueryUpdate();
virtual void updateQuery() = 0;
void onContactInfoChanged(const QString &accountId, const QString &identifier, const QVariantMap &contactInfo);
void watchContactInfo(const QString &accountId, const QString &identifier, const QVariantMap ¤tInfo);
protected:
virtual void timerEvent(QTimerEvent *event);
bool lessThan(const QVariantMap &left, const QVariantMap &right) const;
int positionForItem(const QVariantMap &item) const;
bool isAscending() const;
HistoryQmlFilter *mFilter;
HistoryQmlSort *mSort;
EventType mType;
bool mMatchContacts;
private:
History::Events mEventWritingQueue;
int mUpdateTimer;
int mEventWritingTimer;
int mThreadWritingTimer;
bool mWaitingForQml;
History::Threads mThreadWritingQueue;
QHash mRoles;
};
#endif // HISTORYMODEL_H
history-service-0.5/Lomiri/History/historyqmlfilter.cpp 0000664 0000000 0000000 00000007421 14554502467 0023556 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historyqmlfilter.h"
#include "filter.h"
HistoryQmlFilter::HistoryQmlFilter(QObject *parent) :
QObject(parent)
{
connect(this,
SIGNAL(filterPropertyChanged()),
SIGNAL(filterChanged()));
connect(this,
SIGNAL(filterValueChanged()),
SIGNAL(filterChanged()));
connect(this,
SIGNAL(matchFlagsChanged()),
SIGNAL(filterChanged()));
}
QString HistoryQmlFilter::filterProperty() const
{
return mFilter.filterProperty();
}
void HistoryQmlFilter::setFilterProperty(const QString &value)
{
mFilter.setFilterProperty(value);
Q_EMIT filterPropertyChanged();
}
QVariant HistoryQmlFilter::filterValue() const
{
return mFilter.filterValue();
}
void HistoryQmlFilter::setFilterValue(const QVariant &value)
{
mFilter.setFilterValue(value);
Q_EMIT filterValueChanged();
}
int HistoryQmlFilter::matchFlags() const
{
return mFilter.matchFlags();
}
void HistoryQmlFilter::setMatchFlags(int flags)
{
mFilter.setMatchFlags((History::MatchFlags)flags);
Q_EMIT matchFlagsChanged();
}
History::Filter HistoryQmlFilter::filter() const
{
return mFilter;
}
HistoryQmlCompoundFilter::HistoryQmlCompoundFilter(QObject *parent)
: HistoryQmlFilter(parent)
{
}
HistoryQmlCompoundFilter::~HistoryQmlCompoundFilter()
{
}
QQmlListProperty HistoryQmlCompoundFilter::filters()
{
return QQmlListProperty(this,
0, // opaque data
filtersAppend,
filtersCount,
filtersAt,
filtersClear);
}
void HistoryQmlCompoundFilter::filtersAppend(QQmlListProperty *prop, HistoryQmlFilter *filter)
{
HistoryQmlCompoundFilter* compoundFilter = static_cast(prop->object);
compoundFilter->mFilters.append(filter);
QObject::connect(filter, SIGNAL(filterChanged()), compoundFilter, SIGNAL(filterChanged()), Qt::UniqueConnection);
Q_EMIT compoundFilter->filterChanged();
}
int HistoryQmlCompoundFilter::filtersCount(QQmlListProperty *prop)
{
HistoryQmlCompoundFilter *compoundFilter = static_cast(prop->object);
return compoundFilter->mFilters.count();
}
HistoryQmlFilter *HistoryQmlCompoundFilter::filtersAt(QQmlListProperty *prop, int index)
{
HistoryQmlCompoundFilter* compoundFilter = static_cast(prop->object);
return compoundFilter->mFilters[index];
}
void HistoryQmlCompoundFilter::filtersClear(QQmlListProperty *prop)
{
HistoryQmlCompoundFilter* compoundFilter = static_cast(prop->object);
if (!compoundFilter->mFilters.isEmpty()) {
Q_FOREACH(HistoryQmlFilter *filter, compoundFilter->mFilters) {
filter->disconnect(compoundFilter);
}
compoundFilter->mFilters.clear();
}
}
history-service-0.5/Lomiri/History/historyqmlfilter.h 0000664 0000000 0000000 00000006110 14554502467 0023215 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYQMLFILTER_H
#define HISTORYQMLFILTER_H
#include
#include
#include "types.h"
#include "filter.h"
class HistoryQmlFilter : public QObject
{
Q_OBJECT
Q_ENUMS(MatchFlag)
Q_PROPERTY(QString filterProperty READ filterProperty WRITE setFilterProperty NOTIFY filterPropertyChanged)
Q_PROPERTY(QVariant filterValue READ filterValue WRITE setFilterValue NOTIFY filterValueChanged)
Q_PROPERTY(int matchFlags READ matchFlags WRITE setMatchFlags NOTIFY matchFlagsChanged)
public:
enum MatchFlag {
MatchCaseSensitive = History::MatchCaseSensitive,
MatchCaseInsensitive = History::MatchCaseInsensitive,
MatchContains = History::MatchContains,
MatchPhoneNumber = History::MatchPhoneNumber,
MatchNotEquals = History::MatchNotEquals,
MatchLess = History::MatchLess,
MatchGreater = History::MatchGreater,
MatchLessOrEquals = History::MatchLessOrEquals,
MatchGreaterOrEquals = History::MatchGreaterOrEquals
};
explicit HistoryQmlFilter(QObject *parent = 0);
QString filterProperty() const;
void setFilterProperty(const QString &value);
QVariant filterValue() const;
void setFilterValue(const QVariant &value);
int matchFlags() const;
void setMatchFlags(int flags);
virtual History::Filter filter() const;
Q_SIGNALS:
void filterPropertyChanged();
void filterValueChanged();
void matchFlagsChanged();
void filterChanged();
protected:
History::Filter mFilter;
};
// compound filter
class HistoryQmlCompoundFilter : public HistoryQmlFilter
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty filters READ filters NOTIFY filtersChanged)
Q_CLASSINFO("DefaultProperty", "filters")
public:
explicit HistoryQmlCompoundFilter(QObject* parent = 0);
virtual ~HistoryQmlCompoundFilter();
QQmlListProperty filters();
static void filtersAppend(QQmlListProperty* prop, HistoryQmlFilter* filter);
static int filtersCount(QQmlListProperty* prop);
static HistoryQmlFilter* filtersAt(QQmlListProperty* prop, int index);
static void filtersClear(QQmlListProperty* prop);
Q_SIGNALS:
void filtersChanged();
protected:
QList mFilters;
};
#endif // HISTORYQMLFILTER_H
history-service-0.5/Lomiri/History/historyqmlintersectionfilter.cpp 0000664 0000000 0000000 00000002270 14554502467 0026202 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historyqmlintersectionfilter.h"
#include "intersectionfilter.h"
HistoryQmlIntersectionFilter::HistoryQmlIntersectionFilter(QObject *parent) :
HistoryQmlCompoundFilter(parent)
{
}
History::Filter HistoryQmlIntersectionFilter::filter() const
{
History::IntersectionFilter intersectionFilter;
Q_FOREACH(HistoryQmlFilter *filter, mFilters) {
intersectionFilter.append(filter->filter());
}
return intersectionFilter;
}
history-service-0.5/Lomiri/History/historyqmlintersectionfilter.h 0000664 0000000 0000000 00000002200 14554502467 0025640 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYQMLINTERSECTIONFILTER_H
#define HISTORYQMLINTERSECTIONFILTER_H
#include "historyqmlfilter.h"
#include "types.h"
#include "intersectionfilter.h"
class HistoryQmlIntersectionFilter : public HistoryQmlCompoundFilter
{
Q_OBJECT
public:
explicit HistoryQmlIntersectionFilter(QObject *parent = 0);
History::Filter filter() const;
};
#endif // HISTORYQMLINTERSECTIONFILTER_H
history-service-0.5/Lomiri/History/historyqmlplugin.cpp 0000664 0000000 0000000 00000004364 14554502467 0023572 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historyqmlplugin.h"
#include "historyqmlfilter.h"
#include "historyqmlintersectionfilter.h"
#include "historyqmlsort.h"
#include "historyqmlunionfilter.h"
#include "historythreadmodel.h"
#include "historygroupedthreadsmodel.h"
#include "historyeventmodel.h"
#include "historygroupedeventsmodel.h"
#include "historyqmltexteventattachment.h"
#include "historymanager.h"
#include
#include
void HistoryQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
// FIXME: check what to do here
Q_UNUSED(engine)
Q_UNUSED(uri)
}
void HistoryQmlPlugin::registerTypes(const char *uri)
{
// @uri History
qmlRegisterType(uri, 0, 1, "HistoryEventModel");
qmlRegisterType(uri, 0, 1, "HistoryGroupedEventsModel");
qmlRegisterType(uri, 0, 1, "HistoryThreadModel");
qmlRegisterType(uri, 0, 1, "HistoryGroupedThreadsModel");
qmlRegisterType(uri, 0, 1, "HistoryFilter");
qmlRegisterType(uri, 0, 1, "HistoryIntersectionFilter");
qmlRegisterType(uri, 0, 1, "HistorySort");
qmlRegisterType(uri, 0, 1, "HistoryUnionFilter");
qmlRegisterType(uri, 0, 1, "HistoryManager");
qmlRegisterUncreatableType(uri, 0, 1, "HistoryTextEventAttachment", "");
qmlRegisterUncreatableType(uri, 0, 1, "QAbstractItemModel", "");
}
history-service-0.5/Lomiri/History/historyqmlplugin.h 0000664 0000000 0000000 00000002144 14554502467 0023231 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYQMLPLUGIN_H
#define HISTORYQMLPLUGIN_H
#include
class HistoryQmlPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void initializeEngine(QQmlEngine *engine, const char *uri);
void registerTypes(const char *uri);
};
#endif // HISTORYQMLPLUGIN_H
history-service-0.5/Lomiri/History/historyqmlsort.cpp 0000664 0000000 0000000 00000003714 14554502467 0023261 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historyqmlsort.h"
#include "sort.h"
HistoryQmlSort::HistoryQmlSort(QObject *parent) :
QObject(parent)
{
connect(this,
SIGNAL(sortFieldChanged()),
SIGNAL(sortChanged()));
connect(this,
SIGNAL(sortOrderChanged()),
SIGNAL(sortChanged()));
connect(this,
SIGNAL(caseSensitivityChanged()),
SIGNAL(sortChanged()));
}
QString HistoryQmlSort::sortField() const
{
return mSort.sortField();
}
void HistoryQmlSort::setSortField(const QString &value)
{
mSort.setSortField(value);
Q_EMIT sortFieldChanged();
}
HistoryQmlSort::SortOrder HistoryQmlSort::sortOrder() const
{
return (SortOrder) mSort.sortOrder();
}
void HistoryQmlSort::setSortOrder(HistoryQmlSort::SortOrder order)
{
mSort.setSortOrder((Qt::SortOrder) order);
Q_EMIT sortOrderChanged();
}
HistoryQmlSort::CaseSensitivity HistoryQmlSort::caseSensitivity() const
{
return (CaseSensitivity) mSort.caseSensitivity();
}
void HistoryQmlSort::setCaseSensitivity(HistoryQmlSort::CaseSensitivity value)
{
mSort.setCaseSensitivity((Qt::CaseSensitivity) value);
Q_EMIT caseSensitivityChanged();
}
History::Sort HistoryQmlSort::sort() const
{
return mSort;
}
history-service-0.5/Lomiri/History/historyqmlsort.h 0000664 0000000 0000000 00000004010 14554502467 0022714 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYQMLSORT_H
#define HISTORYQMLSORT_H
#include
#include "types.h"
#include "sort.h"
class HistoryQmlSort : public QObject
{
Q_OBJECT
Q_ENUMS(SortOrder)
Q_ENUMS(CaseSensitivity)
Q_PROPERTY(QString sortField READ sortField WRITE setSortField NOTIFY sortFieldChanged)
Q_PROPERTY(SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
Q_PROPERTY(CaseSensitivity caseSensitivity READ caseSensitivity WRITE setCaseSensitivity NOTIFY caseSensitivityChanged)
public:
enum SortOrder {
AscendingOrder = Qt::AscendingOrder,
DescendingOrder = Qt::DescendingOrder
};
enum CaseSensitivity {
CaseInsensitive = Qt::CaseInsensitive,
CaseSensitive = Qt::CaseSensitive
};
explicit HistoryQmlSort(QObject *parent = 0);
QString sortField() const;
void setSortField(const QString &value);
SortOrder sortOrder() const;
void setSortOrder(SortOrder order);
CaseSensitivity caseSensitivity() const;
void setCaseSensitivity(CaseSensitivity value);
History::Sort sort() const;
Q_SIGNALS:
void sortChanged();
void sortFieldChanged();
void sortOrderChanged();
void caseSensitivityChanged();
private:
History::Sort mSort;
};
#endif // HISTORYQMLSORT_H
history-service-0.5/Lomiri/History/historyqmltexteventattachment.cpp 0000664 0000000 0000000 00000003316 14554502467 0026367 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
* Tiago Salem Herrmann
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "texteventattachment.h"
#include "historyqmltexteventattachment.h"
HistoryQmlTextEventAttachment::HistoryQmlTextEventAttachment(const History::TextEventAttachment &attachment, QObject *parent) :
QObject(parent), mAttachment(attachment)
{
}
QString HistoryQmlTextEventAttachment::accountId() const
{
return mAttachment.accountId();
}
QString HistoryQmlTextEventAttachment::threadId() const
{
return mAttachment.threadId();
}
QString HistoryQmlTextEventAttachment::eventId() const
{
return mAttachment.eventId();
}
QString HistoryQmlTextEventAttachment::attachmentId() const
{
return mAttachment.attachmentId();
}
QString HistoryQmlTextEventAttachment::contentType() const
{
return mAttachment.contentType();
}
QString HistoryQmlTextEventAttachment::filePath() const
{
return mAttachment.filePath();
}
int HistoryQmlTextEventAttachment::status() const
{
return mAttachment.status();
}
history-service-0.5/Lomiri/History/historyqmltexteventattachment.h 0000664 0000000 0000000 00000004160 14554502467 0026032 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
* Tiago Salem Herrmann
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYQMLTEXTEVENTATTACHMENT_H
#define HISTORYQMLTEXTEVENTATTACHMENT_H
#include
#include
#include "historyqmltexteventattachment.h"
#include "types.h"
#include "texteventattachment.h"
class HistoryQmlTextEventAttachment : public QObject
{
Q_OBJECT
Q_ENUMS(AttachmentFlag)
Q_PROPERTY(QString accountId READ accountId CONSTANT)
Q_PROPERTY(QString threadId READ threadId CONSTANT)
Q_PROPERTY(QString eventId READ eventId CONSTANT)
Q_PROPERTY(QString attachmentId READ attachmentId CONSTANT)
Q_PROPERTY(QString contentType READ contentType CONSTANT)
Q_PROPERTY(QString filePath READ filePath CONSTANT)
Q_PROPERTY(int status READ status CONSTANT)
public:
enum AttachmentFlag
{
AttachmentDownloaded = History::AttachmentDownloaded,
AttachmentPending = History::AttachmentPending,
AttachmentError = History::AttachmentError
};
explicit HistoryQmlTextEventAttachment(const History::TextEventAttachment &attachment, QObject *parent = 0);
QString accountId() const;
QString threadId() const;
QString eventId() const;
QString attachmentId() const;
QString contentType() const;
QString filePath() const;
int status() const;
protected:
History::TextEventAttachment mAttachment;
};
#endif // HISTORYQMLTEXTEVENTATTACHMENT_H
history-service-0.5/Lomiri/History/historyqmlunionfilter.cpp 0000664 0000000 0000000 00000002171 14554502467 0024624 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historyqmlunionfilter.h"
#include "unionfilter.h"
HistoryQmlUnionFilter::HistoryQmlUnionFilter(QObject *parent) :
HistoryQmlCompoundFilter(parent)
{
}
History::Filter HistoryQmlUnionFilter::filter() const
{
History::UnionFilter unionFilter;
Q_FOREACH(HistoryQmlFilter *filter, mFilters) {
unionFilter.append(filter->filter());
}
return unionFilter;
}
history-service-0.5/Lomiri/History/historyqmlunionfilter.h 0000664 0000000 0000000 00000002122 14554502467 0024265 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYQMLUNIONFILTER_H
#define HISTORYQMLUNIONFILTER_H
#include "historyqmlfilter.h"
#include
#include
class HistoryQmlUnionFilter : public HistoryQmlCompoundFilter
{
Q_OBJECT
public:
explicit HistoryQmlUnionFilter(QObject *parent = 0);
History::Filter filter() const;
};
#endif // HISTORYQMLUNIONFILTER_H
history-service-0.5/Lomiri/History/historythreadmodel.cpp 0000664 0000000 0000000 00000031137 14554502467 0024050 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2016 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historythreadmodel.h"
#include "historyqmltexteventattachment.h"
#include "manager.h"
#include "threadview.h"
#include "voiceevent.h"
#include
#include
Q_DECLARE_METATYPE(History::TextEventAttachments)
Q_DECLARE_METATYPE(QList)
HistoryThreadModel::HistoryThreadModel(QObject *parent) :
HistoryModel(parent), mCanFetchMore(true), mGroupThreads(false)
{
qRegisterMetaType >();
qDBusRegisterMetaType >();
// configure the roles
mRoles = HistoryModel::roleNames();
mRoles[CountRole] = "count";
mRoles[UnreadCountRole] = "unreadCount";
mRoles[ChatType] = "chatType";
mRoles[ChatRoomInfo] = "chatRoomInfo";
// roles related to the thread´s last event
mRoles[LastEventIdRole] = "eventId";
mRoles[LastEventSenderIdRole] = "eventSenderId";
mRoles[LastEventTimestampRole] = "eventTimestamp";
mRoles[LastEventDateRole] = "eventDate";
mRoles[LastEventNewRole] = "eventNew";
mRoles[LastEventTextMessageRole] = "eventTextMessage";
mRoles[LastEventTextMessageTypeRole] = "eventTextMessageType";
mRoles[LastEventTextMessageStatusRole] = "eventTextMessageStatus";
mRoles[LastEventTextReadTimestampRole] = "eventTextReadTimestamp";
mRoles[LastEventTextAttachmentsRole] = "eventTextAttachments";
mRoles[LastEventTextSubjectRole] = "eventTextSubject";
mRoles[LastEventCallMissedRole] = "eventCallMissed";
mRoles[LastEventCallDurationRole] = "eventCallDuration";
}
int HistoryThreadModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return mThreads.count();
}
QVariant HistoryThreadModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= mThreads.count()) {
return QVariant();
}
History::Thread thread = mThreads[index.row()];
QVariant result = threadData(thread, role);
if (result.isNull()) {
result = HistoryModel::data(index, role);
}
return result;
}
QVariant HistoryThreadModel::threadData(const History::Thread &thread, int role) const
{
History::Event event = thread.lastEvent();
History::TextEvent textEvent;
History::VoiceEvent voiceEvent;
if (!event.isNull()) {
switch (event.type()) {
case History::EventTypeText:
textEvent = event;
break;
case History::EventTypeVoice:
voiceEvent = event;
break;
case History::EventTypeNull:
qWarning("HistoryThreadModel::threadData: Got EventTypeNull, ignoring this event!");
break;
}
}
QVariant result;
switch (role) {
case CountRole:
result = thread.count();
break;
case UnreadCountRole:
result = thread.unreadCount();
break;
case ChatType:
result = thread.chatType();
break;
case ChatRoomInfo:
result = thread.chatRoomInfo();
break;
case PropertiesRole:
result = thread.properties();
break;
case LastEventIdRole:
if (!event.isNull()) {
result = event.eventId();
}
break;
case LastEventSenderIdRole:
if (!event.isNull()) {
result = event.senderId();
}
break;
case LastEventTimestampRole:
if (!event.isNull()) {
result = event.timestamp();
}
break;
case LastEventDateRole:
if (!event.isNull()) {
result = event.timestamp().date();
}
break;
case LastEventNewRole:
if (!event.isNull()) {
result = event.newEvent();
}
break;
case LastEventTextMessageRole:
if (!textEvent.isNull()) {
result = textEvent.message();
}
break;
case LastEventTextMessageTypeRole:
if (!textEvent.isNull()) {
result = (int) textEvent.messageType();
}
break;
case LastEventTextMessageStatusRole:
if (!textEvent.isNull()) {
result = (int) textEvent.messageStatus();
}
break;
case LastEventTextReadTimestampRole:
if (!textEvent.isNull()) {
result = textEvent.readTimestamp();
}
break;
case LastEventTextSubjectRole:
if (!textEvent.isNull()) {
result = textEvent.subject();
}
break;
case LastEventTextAttachmentsRole:
if (!textEvent.isNull()) {
if (mAttachmentCache.contains(textEvent)) {
result = mAttachmentCache.value(textEvent);
} else {
QList attachments;
Q_FOREACH(const History::TextEventAttachment &attachment, textEvent.attachments()) {
attachments << QVariant::fromValue(new HistoryQmlTextEventAttachment(attachment, const_cast(this)));
}
mAttachmentCache[textEvent] = attachments;
result = attachments;
}
}
break;
case LastEventCallMissedRole:
if (!voiceEvent.isNull()) {
result = voiceEvent.missed();
}
break;
case LastEventCallDurationRole:
if (!voiceEvent.isNull()) {
result = voiceEvent.duration();
}
break;
}
return result;
}
bool HistoryThreadModel::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid() || !mFilter || mThreadView.isNull()) {
return false;
}
return mCanFetchMore;
}
void HistoryThreadModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid() || mThreadView.isNull()) {
return;
}
History::Threads threads = fetchNextPage();
if (threads.isEmpty()) {
mCanFetchMore = false;
Q_EMIT canFetchMoreChanged();
} else {
beginInsertRows(QModelIndex(), mThreads.count(), mThreads.count() + threads.count() - 1);
mThreads << threads;
endInsertRows();
}
}
QHash HistoryThreadModel::roleNames() const
{
return mRoles;
}
bool HistoryThreadModel::removeThreads(const QVariantList &threadsProperties)
{
History::Threads threads;
Q_FOREACH(const QVariant &entry, threadsProperties) {
QVariantMap threadProperties = entry.toMap();
History::Thread thread = History::Thread::fromProperties(threadProperties);
if (!thread.isNull()) {
threads << thread;
}
}
if (threads.isEmpty()) {
return false;
}
return History::Manager::instance()->removeThreads(threads);
}
void HistoryThreadModel::updateQuery()
{
// remove all events from the model
if (!mThreads.isEmpty()) {
beginRemoveRows(QModelIndex(), 0, mThreads.count() - 1);
mThreads.clear();
endRemoveRows();
}
History::Filter queryFilter;
History::Sort querySort;
if (!mThreadView.isNull()) {
mThreadView->disconnect(this);
}
if (mFilter) {
queryFilter = mFilter->filter();
} else {
// we should not return anything if there is no filter
return;
}
if (mSort) {
querySort = mSort->sort();
}
QVariantMap properties;
if (mGroupThreads) {
properties[History::FieldGroupingProperty] = History::FieldParticipants;
}
mThreadView = History::Manager::instance()->queryThreads((History::EventType)mType, querySort, queryFilter, properties);
connect(mThreadView.data(),
SIGNAL(threadsAdded(History::Threads)),
SLOT(onThreadsAdded(History::Threads)));
connect(mThreadView.data(),
SIGNAL(threadsModified(History::Threads)),
SLOT(onThreadsModified(History::Threads)));
connect(mThreadView.data(),
SIGNAL(threadsRemoved(History::Threads)),
SLOT(onThreadsRemoved(History::Threads)));
connect(mThreadView.data(),
SIGNAL(threadParticipantsChanged(History::Thread, History::Participants, History::Participants, History::Participants)),
SLOT(onThreadParticipantsChanged(History::Thread, History::Participants, History::Participants, History::Participants)));
connect(mThreadView.data(),
SIGNAL(invalidated()),
SLOT(triggerQueryUpdate()));
Q_FOREACH(const QVariant &attachment, mAttachmentCache) {
HistoryQmlTextEventAttachment *qmlAttachment = attachment.value();
if(qmlAttachment) {
qmlAttachment->deleteLater();
}
}
mAttachmentCache.clear();
// and fetch again
mCanFetchMore = true;
Q_EMIT canFetchMoreChanged();
fetchMore(QModelIndex());
}
void HistoryThreadModel::onThreadParticipantsChanged(const History::Thread &thread, const History::Participants &added, const History::Participants &removed, const History::Participants &modified)
{
int pos = mThreads.indexOf(thread);
if (pos >= 0) {
mThreads[pos].removeParticipants(removed);
mThreads[pos].removeParticipants(modified);
mThreads[pos].addParticipants(added);
mThreads[pos].addParticipants(modified);
QModelIndex idx = index(pos);
Q_EMIT dataChanged(idx, idx);
}
// watch the contact info for the received participants
Q_FOREACH(const History::Participant &participant, added) {
watchContactInfo(thread.accountId(), participant.identifier(), participant.properties());
}
Q_FOREACH(const History::Participant &participant, modified) {
watchContactInfo(thread.accountId(), participant.identifier(), participant.properties());
}
}
void HistoryThreadModel::fetchParticipantsIfNeeded(const History::Threads &threads)
{
History::Threads filtered;
Q_FOREACH(const History::Thread &thread, threads) {
if (thread.type() == History::EventTypeText && thread.participants().isEmpty() &&
(thread.chatType() != History::ChatTypeRoom || thread.accountId().startsWith("ofono"))) {
filtered << thread;
}
}
if (filtered.isEmpty()) {
return;
}
History::Manager::instance()->requestThreadParticipants(filtered);
}
void HistoryThreadModel::onThreadsAdded(const History::Threads &threads)
{
if (threads.isEmpty()) {
return;
}
Q_FOREACH(const History::Thread &thread, threads) {
// if the thread is already inserted, skip it
if (mThreads.contains(thread)) {
continue;
}
int pos = positionForItem(thread.properties());
beginInsertRows(QModelIndex(), pos, pos);
mThreads.insert(pos, thread);
endInsertRows();
}
fetchParticipantsIfNeeded(threads);
}
void HistoryThreadModel::onThreadsModified(const History::Threads &threads)
{
History::Threads newThreads;
Q_FOREACH(const History::Thread &thread, threads) {
int pos = mThreads.indexOf(thread);
if (pos >= 0) {
mThreads[pos] = thread;
QModelIndex idx = index(pos);
Q_EMIT dataChanged(idx, idx);
} else {
newThreads << thread;
}
}
// add threads that were not yet on the model
if (!newThreads.isEmpty()) {
onThreadsAdded(newThreads);
}
fetchParticipantsIfNeeded(threads);
}
void HistoryThreadModel::onThreadsRemoved(const History::Threads &threads)
{
Q_FOREACH(const History::Thread &thread, threads) {
int pos = mThreads.indexOf(thread);
if (pos >= 0) {
beginRemoveRows(QModelIndex(), pos, pos);
mThreads.removeAt(pos);
endRemoveRows();
}
}
// FIXME: there is a corner case here: if a thread was not loaded yet, but was already
// removed by another client, it will still show up when a new page is requested. Maybe it
// should be handle internally in History::ThreadView?
}
History::Threads HistoryThreadModel::fetchNextPage()
{
History::Threads threads = mThreadView->nextPage();
fetchParticipantsIfNeeded(threads);
return threads;
}
history-service-0.5/Lomiri/History/historythreadmodel.h 0000664 0000000 0000000 00000005672 14554502467 0023522 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2016 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYTHREADMODEL_H
#define HISTORYTHREADMODEL_H
#include "historymodel.h"
#include "types.h"
#include "textevent.h"
#include "thread.h"
class HistoryQmlFilter;
class HistoryQmlSort;
class HistoryThreadModel : public HistoryModel
{
Q_OBJECT
Q_ENUMS(ThreadRole)
public:
enum ThreadRole {
CountRole = HistoryModel::LastRole,
UnreadCountRole,
ChatType,
ChatRoomInfo,
LastEventIdRole,
LastEventSenderIdRole,
LastEventTimestampRole,
LastEventDateRole,
LastEventNewRole,
LastEventTextMessageRole,
LastEventTextMessageTypeRole,
LastEventTextMessageStatusRole,
LastEventTextReadTimestampRole,
LastEventTextSubjectRole,
LastEventTextAttachmentsRole,
LastEventCallMissedRole,
LastEventCallDurationRole,
LastThreadRole
};
explicit HistoryThreadModel(QObject *parent = 0);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role) const;
QVariant threadData(const History::Thread &thread, int role) const;
bool canFetchMore(const QModelIndex &parent = QModelIndex()) const;
void fetchMore(const QModelIndex &parent);
virtual QHash roleNames() const;
Q_INVOKABLE bool removeThreads(const QVariantList &threadsProperties);
protected Q_SLOTS:
virtual void updateQuery();
virtual void onThreadsAdded(const History::Threads &threads);
virtual void onThreadsModified(const History::Threads &threads);
virtual void onThreadsRemoved(const History::Threads &threads);
virtual void onThreadParticipantsChanged(const History::Thread &thread, const History::Participants &added, const History::Participants &removed, const History::Participants &modified);
protected:
void fetchParticipantsIfNeeded(const History::Threads &threads);
History::Threads fetchNextPage();
bool mCanFetchMore;
bool mGroupThreads;
private:
History::ThreadViewPtr mThreadView;
History::Threads mThreads;
QHash mRoles;
mutable QMap > mAttachmentCache;
};
#endif // HISTORYTHREADMODEL_H
history-service-0.5/Lomiri/History/qmldir 0000664 0000000 0000000 00000000051 14554502467 0020634 0 ustar 00root root 0000000 0000000 module Lomiri.History
plugin history-qml
history-service-0.5/README.md 0000664 0000000 0000000 00000001714 14554502467 0016013 0 ustar 00root root 0000000 0000000 # history-service
Service that provides call log and conversation history
## Getting Started
History service provide the database and an API to store/retrieve the call log (used by dialer-app ) and the sms/mms history ( used by messaging-app ).
See as well telepathy-ofono for incoming message events.
Database location: ~.local/share/history-service/history.sqlite
### Installing
You can use [crossbuilder](http://docs.ubports.com/en/latest/systemdev/testing-locally.html#cross-building-with-crossbuilder)
( you may need to add manually dh-translations, e.g `crossbuilder inst-foreign dh-translations)
```
crossbuilder
```
## Running the tests
Run tests within the container `crossbuilder shell` and find the generated tests, currently on `history-service/obj-..../tests/`
## Contributing
Please read [CONTRIBUTING.md](http://docs.ubports.com/en/latest/systemdev/testing-locally.html).
## License
GPL v3.0 - see the [COPYING](COPYING) file for details
history-service-0.5/TODO 0000664 0000000 0000000 00000000057 14554502467 0015223 0 ustar 00root root 0000000 0000000 - Use implicit sharing for Threads and Events.
history-service-0.5/clickable.yml 0000664 0000000 0000000 00000000416 14554502467 0017166 0 ustar 00root root 0000000 0000000 builder: cmake
dependencies_host:
- libmessaging-menu-dev
- libusermetricsinput1-dev
- liburl-dispatcher1-dev
- telepathy-mission-control-5
- lcov
- gcovr
- libphonenumber-dev
- libqt5sql5-sqlite
- libsqlite3-dev
- libtelepathy-qt5-dev
- qtpim5-dev history-service-0.5/cmake/ 0000775 0000000 0000000 00000000000 14554502467 0015611 5 ustar 00root root 0000000 0000000 history-service-0.5/cmake/modules/ 0000775 0000000 0000000 00000000000 14554502467 0017261 5 ustar 00root root 0000000 0000000 history-service-0.5/cmake/modules/FindLibPhoneNumber.cmake 0000664 0000000 0000000 00000001414 14554502467 0023735 0 ustar 00root root 0000000 0000000 set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
include(GNUInstallDirs)
include(LibFindMacros)
# Include dir
find_path(LibPhoneNumber_INCLUDE_DIR
NAMES phonenumberutil.h
PATHS "/usr/local/${CMAKE_INSTALL_INCLUDEDIR}" ${CMAKE_INSTALL_FULL_INCLUDEDIR}
PATH_SUFFIXES "phonenumbers"
)
# library itself
find_library(LibPhoneNumber_LIBRARY
NAMES phonenumber
PATHS "/usr/local/${CMAKE_INSTALL_LIBDIR}" ${CMAKE_INSTALL_FULL_LIBDIR}
)
# Set the include dir variables and the libraries and let libfind_process do the rest.
# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
set(LibPhoneNumber_PROCESS_INCLUDES LibPhoneNumber_INCLUDE_DIR)
set(LibPhoneNumber_PROCESS_LIBS LibPhoneNumber_LIBRARY)
libfind_process(LibPhoneNumber)
history-service-0.5/cmake/modules/GenerateTest.cmake 0000664 0000000 0000000 00000014052 14554502467 0022657 0 ustar 00root root 0000000 0000000 #
# Copyright (C) 2015 Canonical, Ltd.
#
# Authors:
# Gustavo Pichorim Boiko
#
# This file is part of history-service.
#
# history-service is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# history-service is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
include(CMakeParseArguments)
find_program(DCONF_SERVICE dconf-service
PATHS /usr/local/libexec /usr/local/lib/dconf /usr/libexec /usr/lib/dconf
NO_DEFAULT_PATH)
find_program(DBUS_RUNNER dbus-test-runner)
find_program(XVFB_RUN_BIN
NAMES xvfb-run
)
function(generate_test TESTNAME)
set(options USE_DBUS USE_UI USE_XVFB)
set(oneValueArgs TIMEOUT WORKING_DIRECTORY QML_TEST WAIT_FOR)
set(multiValueArgs TASKS LIBRARIES QT5_MODULES SOURCES ENVIRONMENT)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
MESSAGE(STATUS "Adding test: ${TESTNAME}")
# set reasonable defaults for the arguments
if (NOT DEFINED ARG_WORKING_DIRECTORY)
set(ARG_WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endif ()
if (NOT DEFINED ARG_TIMEOUT)
set(ARG_TIMEOUT 120)
endif ()
if (NOT DEFINED ARG_QT5_MODULES)
set(ARG_QT5_MODULES Core Test)
endif ()
if (${ARG_USE_UI})
if (${ARG_USE_DBUS})
set(PLATFORM -p -platform -p offscreen)
else ()
set(PLATFORM -platform offscreen)
endif ()
endif()
# Generate QML tests
if (DEFINED ARG_QML_TEST)
add_test(NAME ${TESTNAME}
WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY}
COMMAND qmltestrunner -platform offscreen -import ${CMAKE_BINARY_DIR} -input ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_QML_TEST})
set_tests_properties(${TESTNAME} PROPERTIES ENVIRONMENT "QT_QPA_FONTDIR=${CMAKE_BINARY_DIR}")
else ()
# For sanity checking, make sure DBUS_RUNNER is available for DBUS tests
if (${ARG_USE_DBUS} AND "${DBUS_RUNNER}" STREQUAL "")
message(WARNING "Test ${TESTNAME} disabled because dbus-test-runner was not found.")
return()
endif ()
# No QML test, regular binary compiled test.
add_executable(${TESTNAME} ${ARG_SOURCES})
qt5_use_modules(${TESTNAME} ${ARG_QT5_MODULES})
if (${ARG_USE_DBUS})
execute_process(COMMAND mktemp -d OUTPUT_VARIABLE TMPDIR)
string(REPLACE "\n" "" TMPDIR ${TMPDIR})
if (NOT DEFINED ARG_ENVIRONMENT)
set(ARG_ENVIRONMENT HOME=${TMPDIR}
HISTORY_PLUGIN_PATH=${CMAKE_BINARY_DIR}/plugins/sqlite
HISTORY_SQLITE_DBPATH=:memory:
HISTORY_LOCK_FILE=${TMPDIR}/history-service.lock
MC_ACCOUNT_DIR=${TMPDIR}
MC_MANAGER_DIR=${TMPDIR})
endif ()
if (${ARG_USE_XVFB})
SET(XVFB_RUN ${XVFB_RUN_BIN} -a -s "-screen 0 1024x768x24")
endif ()
set(TEST_COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME} ${PLATFORM} -p -o -p -,txt -p -o -p ${CMAKE_BINARY_DIR}/test_${TESTNAME}.xml,xunitxml)
if (DEFINED ARG_WAIT_FOR)
SET(TEST_COMMAND ${TEST_COMMAND} --wait-for ${ARG_WAIT_FOR})
endif ()
add_test(${TESTNAME} ${XVFB_RUN} ${DBUS_RUNNER} --keep-env --dbus-config=${CMAKE_BINARY_DIR}/tests/common/dbus-session.conf --max-wait=${ARG_TIMEOUT}
${ARG_TASKS} --task ${TEST_COMMAND} --task-name ${TESTNAME})
else ()
add_test(${TESTNAME} ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME} ${PLATFORM} -o -,txt -o ${CMAKE_BINARY_DIR}/test_${TESTNAME}.xml,xunitxml)
endif()
set_tests_properties(${TESTNAME} PROPERTIES
ENVIRONMENT "${ARG_ENVIRONMENT}"
TIMEOUT ${ARG_TIMEOUT})
if (DEFINED ARG_LIBRARIES)
target_link_libraries(${TESTNAME}
${ARG_LIBRARIES})
endif ()
enable_coverage(${TESTNAME})
endif ()
endfunction(generate_test)
function(generate_telepathy_test TESTNAME)
set(options "")
set(oneValueArgs "")
set(multiValueArgs TASKS LIBRARIES QT5_MODULES)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
if ("${DCONF_SERVICE}" STREQUAL "")
message(WARNING "Test ${TESTNAME} disabled because dconf-service was not found.")
return()
endif ()
set(TASKS --task gnome-keyring-daemon -p -r -p -d --task-name gnome-keyring --ignore-return
--task "${DCONF_SERVICE}" --task-name dconf-service --ignore-return
--task dconf -p write -p /org/gnome/empathy/use-conn -p false --task-name dconf-write --wait-for ca.desrt.dconf --ignore-return
--task /usr/lib/telepathy/mission-control-5 --task-name mission-control --wait-for ca.desrt.dconf --ignore-return
--task ${CMAKE_BINARY_DIR}/tests/common/mock/telepathy-mock --task-name telepathy-mock --wait-for org.freedesktop.Telepathy.MissionControl5 --ignore-return
${ARG_TASKS})
if (NOT DEFINED ARG_LIBRARIES)
set(ARG_LIBRARIES ${TP_QT5_LIBRARIES} historyservice mockcontroller telepathytest)
endif(NOT DEFINED ARG_LIBRARIES)
if (NOT DEFINED ARG_QT5_MODULES)
set(ARG_QT5_MODULES Core DBus Test Qml)
endif (NOT DEFINED ARG_QT5_MODULES)
generate_test(${TESTNAME} ${ARGN}
TASKS ${TASKS}
LIBRARIES ${ARG_LIBRARIES}
QT5_MODULES ${ARG_QT5_MODULES}
USE_DBUS)
endfunction(generate_telepathy_test)
history-service-0.5/cmake/modules/LibFindMacros.cmake 0000664 0000000 0000000 00000011060 14554502467 0022735 0 ustar 00root root 0000000 0000000 # Version 1.0 (2013-04-12)
# Public Domain, originally written by Lasse Kärkkäinen
# Published at http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries
# If you improve the script, please modify the forementioned wiki page because
# I no longer maintain my scripts (hosted as static files at zi.fi). Feel free
# to remove this entire header if you use real version control instead.
# Changelog:
# 2013-04-12 Added version number (1.0) and this header, no other changes
# 2009-10-08 Originally published
# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
# used for the current package. For this to work, the first parameter must be the
# prefix of the current package, then the prefix of the new package etc, which are
# passed to find_package.
macro (libfind_package PREFIX)
set (LIBFIND_PACKAGE_ARGS ${ARGN})
if (${PREFIX}_FIND_QUIETLY)
set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
endif (${PREFIX}_FIND_QUIETLY)
if (${PREFIX}_FIND_REQUIRED)
set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
endif (${PREFIX}_FIND_REQUIRED)
find_package(${LIBFIND_PACKAGE_ARGS})
endmacro (libfind_package)
# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
# where they added pkg_check_modules. Consequently I need to support both in my scripts
# to avoid those deprecated warnings. Here's a helper that does just that.
# Works identically to pkg_check_modules, except that no checks are needed prior to use.
macro (libfind_pkg_check_modules PREFIX PKGNAME)
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
include(UsePkgConfig)
pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(${PREFIX} ${PKGNAME})
endif (PKG_CONFIG_FOUND)
endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
endmacro (libfind_pkg_check_modules)
# Do the final processing once the paths have been detected.
# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
# all the variables, each of which contain one include directory.
# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
# Also handles errors in case library detection was required, etc.
macro (libfind_process PREFIX)
# Skip processing if already processed during this run
if (NOT ${PREFIX}_FOUND)
# Start with the assumption that the library was found
set (${PREFIX}_FOUND TRUE)
# Process all includes and set _FOUND to false if any are missing
foreach (i ${${PREFIX}_PROCESS_INCLUDES})
if (${i})
set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
mark_as_advanced(${i})
else (${i})
set (${PREFIX}_FOUND FALSE)
endif (${i})
endforeach (i)
# Process all libraries and set _FOUND to false if any are missing
foreach (i ${${PREFIX}_PROCESS_LIBS})
if (${i})
set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
mark_as_advanced(${i})
else (${i})
set (${PREFIX}_FOUND FALSE)
endif (${i})
endforeach (i)
# Print message and/or exit on fatal error
if (${PREFIX}_FOUND)
if (NOT ${PREFIX}_FIND_QUIETLY)
message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
endif (NOT ${PREFIX}_FIND_QUIETLY)
else (${PREFIX}_FOUND)
if (${PREFIX}_FIND_REQUIRED)
foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
message("${i}=${${i}}")
endforeach (i)
message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
endif (${PREFIX}_FIND_REQUIRED)
endif (${PREFIX}_FOUND)
endif (NOT ${PREFIX}_FOUND)
endmacro (libfind_process)
macro(libfind_library PREFIX basename)
set(TMP "")
if(MSVC80)
set(TMP -vc80)
endif(MSVC80)
if(MSVC90)
set(TMP -vc90)
endif(MSVC90)
set(${PREFIX}_LIBNAMES ${basename}${TMP})
if(${ARGC} GREATER 2)
set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
endif(${ARGC} GREATER 2)
find_library(${PREFIX}_LIBRARY
NAMES ${${PREFIX}_LIBNAMES}
PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
)
endmacro(libfind_library)
history-service-0.5/cmake/modules/ParseArguments.cmake 0000664 0000000 0000000 00000003406 14554502467 0023226 0 ustar 00root root 0000000 0000000 # Parse arguments passed to a function into several lists separated by
# upper-case identifiers and options that do not have an associated list e.g.:
#
# SET(arguments
# hello OPTION3 world
# LIST3 foo bar
# OPTION2
# LIST1 fuz baz
# )
# PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments})
#
# results in 7 distinct variables:
# * ARG_DEFAULT_ARGS: hello;world
# * ARG_LIST1: fuz;baz
# * ARG_LIST2:
# * ARG_LIST3: foo;bar
# * ARG_OPTION1: FALSE
# * ARG_OPTION2: TRUE
# * ARG_OPTION3: TRUE
#
# taken from http://www.cmake.org/Wiki/CMakeMacroParseArguments
MACRO(PARSE_ARGUMENTS prefix arg_names option_names)
SET(DEFAULT_ARGS)
FOREACH(arg_name ${arg_names})
SET(${prefix}_${arg_name})
ENDFOREACH(arg_name)
FOREACH(option ${option_names})
SET(${prefix}_${option} FALSE)
ENDFOREACH(option)
SET(current_arg_name DEFAULT_ARGS)
SET(current_arg_list)
FOREACH(arg ${ARGN})
SET(larg_names ${arg_names})
LIST(FIND larg_names "${arg}" is_arg_name)
IF (is_arg_name GREATER -1)
SET(${prefix}_${current_arg_name} ${current_arg_list})
SET(current_arg_name ${arg})
SET(current_arg_list)
ELSE (is_arg_name GREATER -1)
SET(loption_names ${option_names})
LIST(FIND loption_names "${arg}" is_option)
IF (is_option GREATER -1)
SET(${prefix}_${arg} TRUE)
ELSE (is_option GREATER -1)
SET(current_arg_list ${current_arg_list} ${arg})
ENDIF (is_option GREATER -1)
ENDIF (is_arg_name GREATER -1)
ENDFOREACH(arg)
SET(${prefix}_${current_arg_name} ${current_arg_list})
ENDMACRO(PARSE_ARGUMENTS)
history-service-0.5/cmake/modules/qt5.cmake 0000664 0000000 0000000 00000003106 14554502467 0020774 0 ustar 00root root 0000000 0000000 # shamelessly copied over from oxide’s build system
# to enable ARM cross compilation
if(CMAKE_CROSSCOMPILING)
# QT_MOC_EXECUTABLE is set by Qt5CoreConfigExtras, but it sets it to
# the target executable rather than the host executable, which is no
# use for cross-compiling. For cross-compiling, we have a guess and
# override it ourselves
if(NOT TARGET Qt5::moc)
find_program(
QT_MOC_EXECUTABLE moc
PATHS /usr/lib/qt5/bin /usr/lib/${HOST_ARCHITECTURE}/qt5/bin
NO_DEFAULT_PATH)
if(QT_MOC_EXECUTABLE STREQUAL "QT_MOC_EXECUTABLE-NOTFOUND")
message(FATAL_ERROR "Can't find a moc executable for the host arch")
endif()
add_executable(Qt5::moc IMPORTED)
set_target_properties(Qt5::moc PROPERTIES
IMPORTED_LOCATION "${QT_MOC_EXECUTABLE}")
endif()
# Dummy targets - not used anywhere, but this stops Qt5CoreConfigExtras.cmake
# from creating them and checking if the binary exists, which is broken when
# cross-building because it checks for the target system binary. We need the
# host system binaries installed, because they are in the same package as the
# moc in Ubuntu (qtbase5-dev-tools), which is not currently multi-arch
if(NOT TARGET Qt5::qmake)
add_executable(Qt5::qmake IMPORTED)
endif()
if(NOT TARGET Qt5::rcc)
add_executable(Qt5::rcc IMPORTED)
endif()
if(NOT TARGET Qt5::uic)
add_executable(Qt5::uic IMPORTED)
endif()
if(NOT TARGET Qt5::DBus)
add_executable(Qt5::DBus IMPORTED)
endif()
else()
# This should be enough to initialize QT_MOC_EXECUTABLE
find_package(Qt5Core)
endif()
history-service-0.5/config.h.in 0000664 0000000 0000000 00000001513 14554502467 0016554 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* This file is part of phone-app.
*
* phone-app is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* phone-app is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef CONFIG_H
#define CONFIG_H
#define HISTORY_PLUGIN_PATH "@CMAKE_INSTALL_PREFIX@/@HISTORY_PLUGIN_PATH@"
#define TEST_DATA_DIR "@TEST_DATA_DIR@"
#endif
history-service-0.5/daemon/ 0000775 0000000 0000000 00000000000 14554502467 0015774 5 ustar 00root root 0000000 0000000 history-service-0.5/daemon/CMakeLists.txt 0000664 0000000 0000000 00000003044 14554502467 0020535 0 ustar 00root root 0000000 0000000
set(qt_SRCS
callchannelobserver.cpp
emblemcountmanager.cpp
historydaemon.cpp
historyservicedbus.cpp
pluginmanager.cpp
rolesinterface.cpp
textchannelobserver.cpp
)
set(daemon_SRCS main.cpp ${qt_SRCS})
include_directories(
${TP_QT5_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
)
qt5_add_dbus_adaptor(daemon_SRCS HistoryService.xml historyservicedbus.h HistoryServiceDBus)
add_executable(history-daemon ${daemon_SRCS} ${daemon_HDRS})
qt5_use_modules(history-daemon Core DBus)
target_link_libraries(history-daemon
${TP_QT5_LIBRARIES}
historyservice
)
pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemduserunitdir)
configure_file(org.freedesktop.Telepathy.Client.HistoryDaemonObserver.service.in org.freedesktop.Telepathy.Client.HistoryDaemonObserver.service)
configure_file(com.lomiri.HistoryService.service.in com.lomiri.HistoryService.service)
configure_file(history-daemon.service.in ${CMAKE_CURRENT_BINARY_DIR}/history-daemon.service)
install(TARGETS history-daemon RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR})
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.HistoryDaemonObserver.service
${CMAKE_CURRENT_BINARY_DIR}/com.lomiri.HistoryService.service
DESTINATION share/dbus-1/services
)
install(FILES HistoryDaemonObserver.client DESTINATION share/telepathy/clients)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/history-daemon.service
DESTINATION ${SYSTEMD_USER_UNIT_DIR})
history-service-0.5/daemon/HistoryDaemonObserver.client 0000664 0000000 0000000 00000001376 14554502467 0023500 0 ustar 00root root 0000000 0000000 [org.freedesktop.Telepathy.Client]
Interfaces=org.freedesktop.Telepathy.Client.Observer;
[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 0]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1
org.freedesktop.Telepathy.Channel.TargetHandleType u=1
org.freedesktop.Telepathy.Channel.Type.Call1.InitialAudio b=true
[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 1]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
[org.freedesktop.Telepathy.Client.Observer.Capabilities]
org.freedesktop.Telepathy.Channel.Type.Call1/audio=true
org.freedesktop.Telepathy.Channel.Type.Call1/audio/speex=true
[org.freedesktop.Telepathy.Client.Observer]
Recover=true
history-service-0.5/daemon/HistoryService.xml 0000664 0000000 0000000 00000025271 14554502467 0021507 0 ustar 00root root 0000000 0000000
An interface to the history service
history-service-0.5/daemon/callchannelobserver.cpp 0000664 0000000 0000000 00000005003 14554502467 0022512 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "callchannelobserver.h"
CallChannelObserver::CallChannelObserver(QObject *parent) :
QObject(parent)
{
}
void CallChannelObserver::onCallChannelAvailable(Tp::CallChannelPtr callChannel)
{
// save the timestamp as a property in the call channel
callChannel->setProperty("timestamp", QDateTime::currentDateTime());
if (callChannel->callState() == Tp::CallStateActive) {
callChannel->setProperty("activeTimestamp", QDateTime::currentDateTime());
}
connect(callChannel.data(),
SIGNAL(callStateChanged(Tp::CallState)),
SLOT(onCallStateChanged(Tp::CallState)));
mChannels.append(callChannel);
mCallStates[callChannel.data()] = callChannel->callState();
}
void CallChannelObserver::onCallStateChanged(Tp::CallState state)
{
Tp::CallChannel *channel = qobject_cast(sender());
if (!channel) {
return;
}
switch (state) {
case Tp::CallStateEnded: {
bool incoming = !channel->isRequested();
bool missed = incoming && channel->callStateReason().reason == Tp::CallStateChangeReasonNoAnswer;
// If the call state is not missed at this point, we need to check from which state we transitioned to ended,
// if from Initialised, it means it was indeed missed
if (incoming && !missed) {
missed = mCallStates[channel] == Tp::CallStateInitialised;
}
mCallStates.remove(channel);
mChannels.removeOne(Tp::CallChannelPtr(channel));
Q_EMIT callEnded(Tp::CallChannelPtr(channel), missed);
break;
}
case Tp::CallStateActive:
channel->setProperty("activeTimestamp", QDateTime::currentDateTime());
// fall through
default:
mCallStates[channel] = state;
break;
}
}
history-service-0.5/daemon/callchannelobserver.h 0000664 0000000 0000000 00000002524 14554502467 0022164 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef CALLCHANNELOBSERVER_H
#define CALLCHANNELOBSERVER_H
#include
#include
class CallChannelObserver : public QObject
{
Q_OBJECT
public:
explicit CallChannelObserver(QObject *parent = 0);
public Q_SLOTS:
void onCallChannelAvailable(Tp::CallChannelPtr callChannel);
Q_SIGNALS:
void callEnded(Tp::CallChannelPtr callChannel, bool missed);
protected Q_SLOTS:
void onCallStateChanged(Tp::CallState state);
private:
QList mChannels;
QMap mCallStates;
};
#endif // CALLCHANNELOBSERVER_H
history-service-0.5/daemon/com.lomiri.HistoryService.service.in 0000664 0000000 0000000 00000000251 14554502467 0025012 0 ustar 00root root 0000000 0000000 [D-BUS Service]
Name=com.lomiri.HistoryService
Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/history-daemon
SystemdService=history-daemon.service
AssumedAppArmorLabel=unconfined
history-service-0.5/daemon/emblemcountmanager.cpp 0000664 0000000 0000000 00000006212 14554502467 0022346 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2022 Ubports Foundation.
*
* Authors:
* Lionel Duboeuf
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "emblemcountmanager.h"
#include "historydaemon.h"
#include "types.h"
#include
#include
#define LAUNCHER_SERVICE "com.lomiri.Shell.Launcher"
#define LAUNCHER_ITEM_IFACE "com.lomiri.Shell.Launcher.Item"
#define MESSAGING_APP_EMBLEM_OBJECT_PATH "/com/lomiri/Shell/Launcher/messaging_2Dapp"
#define DIALER_APP_EMBLEM_OBJECT_PATH "/com/lomiri/Shell/Launcher/dialer_2Dapp"
EmblemCountManager::EmblemCountManager(QObject *parent) :
QObject(parent),
mWatcher(LAUNCHER_SERVICE, QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForRegistration)
{
connect(&mWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this]() {
updateCounters();
});
updateCounters();
qDebug() << "emblem counters initialized";
}
EmblemCountManager::~EmblemCountManager()
{
}
QDBusInterface *EmblemCountManager::getEmblemCounter(History::EventType type)
{
QDBusInterface* emblemCounter = nullptr;
switch (type) {
case History::EventTypeText:
emblemCounter = new QDBusInterface( LAUNCHER_SERVICE, MESSAGING_APP_EMBLEM_OBJECT_PATH,
LAUNCHER_ITEM_IFACE);
break;
case History::EventTypeVoice:
emblemCounter = new QDBusInterface( LAUNCHER_SERVICE, DIALER_APP_EMBLEM_OBJECT_PATH,
LAUNCHER_ITEM_IFACE);
break;
default:
qWarning() << "fail to get emblem counter dbus interface, got event type null";
break;
}
return emblemCounter;
}
void EmblemCountManager::updateCounter(History::EventType type) {
QDBusInterface* emblemCounter = getEmblemCounter(type);
if (emblemCounter == nullptr) {
return;
}
// only update counter if app is pinned
if (emblemCounter->isValid() && emblemCounter->property("count").isValid()) {
int count = HistoryDaemon::instance()->getUnreadCount(type);
// when messaging-app/dialer app is not pinned, launcher service only creates the emblem on countVisible property,
// in that case the count is initialized to zero. This allows to force Item creation before setting the count
emblemCounter->setProperty("countVisible", count > 0);
emblemCounter->setProperty("count", count);
}
emblemCounter->deleteLater();
}
void EmblemCountManager::updateCounters()
{
updateCounter(History::EventTypeText);
updateCounter(History::EventTypeVoice);
}
history-service-0.5/daemon/emblemcountmanager.h 0000664 0000000 0000000 00000002360 14554502467 0022013 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2022 Ubports Foundation.
*
* Authors:
* Lionel Duboeuf
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef EMBLEMCOUNTMANAGER_H
#define EMBLEMCOUNTMANAGER_H
#include
#include
#include
#include "types.h"
class EmblemCountManager : public QObject
{
Q_OBJECT
public:
~EmblemCountManager();
explicit EmblemCountManager(QObject *parent = 0);
void updateCounter(History::EventType type);
void updateCounters();
private:
QDBusInterface *getEmblemCounter(History::EventType type);
QDBusServiceWatcher mWatcher;
};
#endif // EMBLEMCOUNTMANAGER_H
history-service-0.5/daemon/history-daemon.service.in 0000664 0000000 0000000 00000000322 14554502467 0022722 0 ustar 00root root 0000000 0000000 [Unit]
Description=History service to store messages and calls
Wants=address-book-service.service
[Service]
Type=dbus
BusName=com.lomiri.HistoryService
ExecStart=@CMAKE_INSTALL_FULL_LIBEXECDIR@/history-daemon
history-service-0.5/daemon/historydaemon.cpp 0000664 0000000 0000000 00000172435 14554502467 0021401 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2017 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historydaemon.h"
#include "mmsstoragemanager_p.h"
#include "telepathyhelper_p.h"
#include "filter.h"
#include "sort.h"
#include "utils_p.h"
#include "pluginmanager.h"
#include "plugin.h"
#include "pluginthreadview.h"
#include "plugineventview.h"
#include "textevent.h"
#include
#include
#include
#include
#include
Q_DECLARE_METATYPE(RolesMap)
const constexpr static int AdminRole = 2;
enum ChannelGroupChangeReason
{
ChannelGroupChangeReasonNone = 0,
ChannelGroupChangeReasonOffline = 1,
ChannelGroupChangeReasonKicked = 2,
ChannelGroupChangeReasonBusy = 3,
ChannelGroupChangeReasonInvited = 4,
ChannelGroupChangeReasonBanned = 5,
ChannelGroupChangeReasonError = 6,
ChannelGroupChangeReasonInvalidContact = 7,
ChannelGroupChangeReasonNoAnswer = 8,
ChannelGroupChangeReasonRenamed = 9,
ChannelGroupChangeReasonPermissionDenied = 10,
ChannelGroupChangeReasonSeparated = 11,
// additional enum values not included in original ChannelGroupChangeReason
// telepathy enumeration but needed here to provide extra info to client when group
// is cancelled
ChannelGroupChangeReasonGone = 12,
ChannelGroupChangeReasonRejected = 13
};
const QDBusArgument &operator>>(const QDBusArgument &argument, RolesMap &roles)
{
argument.beginMap();
while ( !argument.atEnd() ) {
argument.beginMapEntry();
uint key,value;
argument >> key >> value;
argument.endMapEntry();
roles[key] = value;
}
argument.endMap();
return argument;
}
bool foundAsMemberInThread(const Tp::ContactPtr& contact, QVariantMap thread)
{
Q_FOREACH (QVariant participant, thread[History::FieldParticipants].toList()) {
// found if same identifier and as member into thread info
QVariantMap participantMap = participant.toMap();
if (History::Utils::compareIds(thread[History::FieldAccountId].toString(),
contact->id(),
participantMap[History::FieldIdentifier].toString()) &&
participantMap[History::FieldParticipantState].toUInt() == History::ParticipantStateRegular)
{
return true;
}
}
return false;
}
bool foundInThread(const Tp::ContactPtr& contact, QVariantMap thread)
{
Q_FOREACH (QVariant participant, thread[History::FieldParticipants].toList()) {
if (History::Utils::compareIds(thread[History::FieldAccountId].toString(),
contact->id(),
participant.toMap()[History::FieldIdentifier].toString()))
{
return true;
}
}
return false;
}
HistoryDaemon::HistoryDaemon(QObject *parent)
: QObject(parent), mCallObserver(this), mTextObserver(this)
{
qRegisterMetaType();
qDBusRegisterMetaType();
// get the first plugin
if (!History::PluginManager::instance()->plugins().isEmpty()) {
mBackend = History::PluginManager::instance()->plugins().first();
}
// FIXME: maybe we should only set the plugin as ready after the contact cache was generated
connect(History::TelepathyHelper::instance(), &History::TelepathyHelper::setupReady, [&]() {
mBackend->generateContactCache();
mDBus.connectToBus();
mEmblemCountManager = new EmblemCountManager();
});
connect(History::TelepathyHelper::instance(), &History::TelepathyHelper::accountAdded, [&](const Tp::AccountPtr &account) {
// handle ofono accountId name change
mBackend->verifyAccount(account->uniqueIdentifier());
});
connect(History::TelepathyHelper::instance(),
SIGNAL(channelObserverCreated(ChannelObserver*)),
SLOT(onObserverCreated()));
History::TelepathyHelper::instance()->registerChannelObserver();
connect(&mCallObserver,
SIGNAL(callEnded(Tp::CallChannelPtr, bool)),
SLOT(onCallEnded(Tp::CallChannelPtr, bool)));
connect(&mTextObserver,
SIGNAL(messageReceived(Tp::TextChannelPtr,Tp::ReceivedMessage)),
SLOT(onMessageReceived(Tp::TextChannelPtr,Tp::ReceivedMessage)));
connect(&mTextObserver,
SIGNAL(messageSent(Tp::TextChannelPtr,Tp::Message,QString)),
SLOT(onMessageSent(Tp::TextChannelPtr,Tp::Message,QString)));
connect(&mTextObserver,
SIGNAL(channelAvailable(Tp::TextChannelPtr)),
SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));
connect(&mTextObserver,
SIGNAL(textChannelInvalidated(Tp::TextChannelPtr)),
SLOT(onTextChannelInvalidated(Tp::TextChannelPtr)));
// FIXME: we need to do this in a better way, but for now this should do
mProtocolFlags["ofono"] = History::MatchPhoneNumber;
mProtocolFlags["multimedia"] = History::MatchPhoneNumber;
}
HistoryDaemon::~HistoryDaemon()
{
mEmblemCountManager->deleteLater();
}
HistoryDaemon *HistoryDaemon::instance()
{
static HistoryDaemon *self = new HistoryDaemon();
return self;
}
void HistoryDaemon::onRolesChanged(const HandleRolesMap &added, const HandleRolesMap &removed)
{
ChannelInterfaceRolesInterface *roles_interface = qobject_cast(sender());
Tp::TextChannelPtr channel(qobject_cast(sender()->parent()));
RolesMap rolesMap;
if (!mRolesMap.contains(channel->objectPath())) {
rolesMap = roles_interface->getRoles();
} else {
rolesMap = mRolesMap[channel->objectPath()];
}
QMapIterator it(removed);
while (it.hasNext()) {
it.next();
rolesMap.remove(it.key());
}
QMapIterator it2(added);
while (it2.hasNext()) {
it2.next();
rolesMap[it2.key()] = it2.value();
}
mRolesMap[channel->objectPath()] = rolesMap;
QVariantMap properties = propertiesFromChannel(channel);
QVariantMap thread = threadForProperties(channel->property(History::FieldAccountId).toString(),
History::EventTypeText,
properties,
matchFlagsForChannel(channel),
false);
if (!thread.isEmpty()) {
writeRolesInformationEvents(thread, channel, rolesMap);
updateRoomRoles(channel, rolesMap);
}
}
QVariantMap HistoryDaemon::propertiesFromChannel(const Tp::ChannelPtr &textChannel)
{
QVariantMap properties;
QVariantList participants;
QStringList participantIds;
QString accountId = textChannel->property(History::FieldAccountId).toString();
if (History::Utils::shouldIncludeParticipants(accountId, fromTelepathyHandleType(textChannel->targetHandleType()))) {
ChannelInterfaceRolesInterface *roles_interface = textChannel->optionalInterface();
RolesMap roles;
if (roles_interface) {
if (mRolesMap.contains(textChannel->objectPath())) {
roles = mRolesMap[textChannel->objectPath()];
}
}
Q_FOREACH(const Tp::ContactPtr contact, textChannel->groupContacts(false)) {
QVariantMap contactProperties;
contactProperties[History::FieldAlias] = contact->alias();
contactProperties[History::FieldAccountId] = accountId;
contactProperties[History::FieldIdentifier] = contact->id();
contactProperties[History::FieldParticipantState] = History::ParticipantStateRegular;
contactProperties[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
participantIds << contact->id();
participants << contactProperties;
}
Q_FOREACH(const Tp::ContactPtr contact, textChannel->groupRemotePendingContacts(false)) {
QVariantMap contactProperties;
contactProperties[History::FieldAlias] = contact->alias();
contactProperties[History::FieldAccountId] = accountId;
contactProperties[History::FieldIdentifier] = contact->id();
contactProperties[History::FieldParticipantState] = History::ParticipantStateRemotePending;
contactProperties[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
participantIds << contact->id();
participants << contactProperties;
}
Q_FOREACH(const Tp::ContactPtr contact, textChannel->groupLocalPendingContacts(false)) {
QVariantMap contactProperties;
contactProperties[History::FieldAlias] = contact->alias();
contactProperties[History::FieldAccountId] = accountId;
contactProperties[History::FieldIdentifier] = contact->id();
contactProperties[History::FieldParticipantState] = History::ParticipantStateLocalPending;
contactProperties[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
participantIds << contact->id();
participants << contactProperties;
}
if (participants.isEmpty() && textChannel->targetHandleType() == Tp::HandleTypeContact &&
textChannel->targetContact() == textChannel->connection()->selfContact()) {
QVariantMap contactProperties;
contactProperties[History::FieldAlias] = textChannel->targetContact()->alias();
contactProperties[History::FieldAccountId] = accountId;
contactProperties[History::FieldIdentifier] = textChannel->targetContact()->id();
contactProperties[History::FieldParticipantState] = History::ParticipantStateRegular;
participantIds << textChannel->targetContact()->id();
participants << contactProperties;
}
}
// We map chatType directly from telepathy targetHandleType: None, Contact, Room
properties[History::FieldChatType] = textChannel->targetHandleType();
properties[History::FieldParticipants] = participants;
properties[History::FieldParticipantIds] = participantIds;
QVariantMap roomProperties;
switch(textChannel->targetHandleType()) {
case Tp::HandleTypeRoom:
if (textChannel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM)) {
auto room_interface = textChannel->optionalInterface();
QVariantMap map = getInterfaceProperties(room_interface);
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
if (iter.value().isValid()) {
roomProperties[iter.key()] = iter.value();
}
}
}
if (textChannel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG)) {
auto room_config_interface = textChannel->optionalInterface();
QVariantMap map = getInterfaceProperties(room_config_interface);
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
if (iter.value().isValid()) {
roomProperties[iter.key()] = iter.value();
}
}
}
if (textChannel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT)) {
auto subject_interface = textChannel->optionalInterface();
QVariantMap map = getInterfaceProperties(subject_interface);
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
if (iter.value().isValid()) {
roomProperties[iter.key()] = iter.value();
}
}
}
properties[History::FieldChatRoomInfo] = roomProperties;
properties[History::FieldThreadId] = textChannel->targetId();
break;
case Tp::HandleTypeContact:
case Tp::HandleTypeNone:
default:
break;
}
return properties;
}
QVariantMap HistoryDaemon::threadForProperties(const QString &accountId,
History::EventType type,
const QVariantMap &properties,
History::MatchFlags matchFlags,
bool create)
{
if (!mBackend) {
return QVariantMap();
}
QVariantMap thread = mBackend->threadForProperties(accountId,
type,
properties,
matchFlags);
if (thread.isEmpty() && create) {
thread = mBackend->createThreadForProperties(accountId, type, properties);
if (!thread.isEmpty()) {
if (properties.contains("Requested") && properties[History::FieldChatType].toInt() == History::ChatTypeRoom) {
QVariantMap map = thread[History::FieldChatRoomInfo].toMap();
map["Requested"] = properties["Requested"];
thread[History::FieldChatRoomInfo] = map;
}
mDBus.notifyThreadsAdded(QList() << thread);
}
}
return thread;
}
QString HistoryDaemon::threadIdForProperties(const QString &accountId, History::EventType type, const QVariantMap &properties, History::MatchFlags matchFlags, bool create)
{
if (!mBackend) {
return QString();
}
QString threadId = mBackend->threadIdForProperties(accountId,
type,
properties,
matchFlags);
if (threadId.isEmpty() && create) {
QVariantMap thread = mBackend->createThreadForProperties(accountId, type, properties);
if (!thread.isEmpty()) {
if (properties.contains("Requested") && properties[History::FieldChatType].toInt() == History::ChatTypeRoom) {
QVariantMap map = thread[History::FieldChatRoomInfo].toMap();
map["Requested"] = properties["Requested"];
thread[History::FieldChatRoomInfo] = map;
}
mDBus.notifyThreadsAdded(QList() << thread);
threadId = thread[History::FieldThreadId].toString();
}
}
return threadId;
}
QList HistoryDaemon::participantsForThreads(const QList &threadIds)
{
if (!mBackend) {
return QList();
}
return mBackend->participantsForThreads(threadIds);
}
QString HistoryDaemon::queryThreads(int type, const QVariantMap &sort, const QVariantMap &filter, const QVariantMap &properties)
{
if (!mBackend) {
return QString();
}
History::Sort theSort = History::Sort::fromProperties(sort);
History::Filter theFilter = History::Filter::fromProperties(filter);
History::PluginThreadView *view = mBackend->queryThreads((History::EventType)type, theSort, theFilter, properties);
if (!view) {
return QString();
}
// FIXME: maybe we should keep a list of views to manually remove them at some point?
view->setParent(this);
return view->objectPath();
}
QString HistoryDaemon::queryEvents(int type, const QVariantMap &sort, const QVariantMap &filter)
{
if (!mBackend) {
return QString();
}
History::Sort theSort = History::Sort::fromProperties(sort);
History::Filter theFilter = History::Filter::fromProperties(filter);
History::PluginEventView *view = mBackend->queryEvents((History::EventType)type, theSort, theFilter);
if (!view) {
return QString();
}
// FIXME: maybe we should keep a list of views to manually remove them at some point?
view->setParent(this);
return view->objectPath();
}
QVariantMap HistoryDaemon::getSingleThread(int type, const QString &accountId, const QString &threadId, const QVariantMap &properties)
{
if (!mBackend) {
return QVariantMap();
}
return mBackend->getSingleThread((History::EventType)type, accountId, threadId, properties);
}
QVariantMap HistoryDaemon::getSingleEvent(int type, const QString &accountId, const QString &threadId, const QString &eventId)
{
if (!mBackend) {
return QVariantMap();
}
return mBackend->getSingleEvent((History::EventType)type, accountId, threadId, eventId);
}
bool HistoryDaemon::writeEvents(const QList &events, const QVariantMap &properties, bool notify)
{
if (!mBackend) {
return false;
}
QList newEvents;
QList modifiedEvents;
QMap threads;
mBackend->beginBatchOperation();
Q_FOREACH(const QVariantMap &event, events) {
History::EventType type = (History::EventType) event[History::FieldType].toInt();
History::EventWriteResult result = History::EventWriteNone;
// get the threads for the events to notify their modifications
QString accountId = event[History::FieldAccountId].toString();
QString threadId = event[History::FieldThreadId].toString();
QVariantMap savedEvent = event;
// and finally write the event
switch (type) {
case History::EventTypeText:
result = mBackend->writeTextEvent(savedEvent);
break;
case History::EventTypeVoice:
result = mBackend->writeVoiceEvent(savedEvent);
break;
case History::EventTypeNull:
qWarning("HistoryDaemon::writeEvents: Got EventTypeNull, ignoring this event!");
continue;
}
// only get the thread AFTER the event is written to make sure it is up-to-date
QVariantMap thread = getSingleThread(type, accountId, threadId, properties);
QString hash = hashThread(thread);
threads[hash] = thread;
// set the participants field in the event
if (type == History::EventTypeVoice) {
savedEvent[History::FieldParticipants] = thread[History::FieldParticipants];
}
// check if the event was a new one or a modification to an existing one
switch (result) {
case History::EventWriteCreated:
newEvents << savedEvent;
break;
case History::EventWriteModified:
modifiedEvents << savedEvent;
break;
case History::EventWriteError:
mBackend->rollbackBatchOperation();
return false;
case History::EventWriteNone:
break;
}
}
mBackend->endBatchOperation();
mEmblemCountManager->updateCounters();
// and last but not least, notify the results
if (!newEvents.isEmpty() && notify) {
mDBus.notifyEventsAdded(newEvents);
}
if (!modifiedEvents.isEmpty() && notify) {
mDBus.notifyEventsModified(modifiedEvents);
}
if (!threads.isEmpty() && notify) {
mDBus.notifyThreadsModified(threads.values());
}
return true;
}
bool HistoryDaemon::removeEvents(const QList &events)
{
if (!mBackend) {
return false;
}
mBackend->beginBatchOperation();
Q_FOREACH(const QVariantMap &event, events) {
History::EventType type = (History::EventType) event[History::FieldType].toInt();
bool success = true;
switch (type) {
case History::EventTypeText:
success = mBackend->removeTextEvent(event);
break;
case History::EventTypeVoice:
success = mBackend->removeVoiceEvent(event);
break;
case History::EventTypeNull:
qWarning("HistoryDaemon::removeEvents: Got EventTypeNull, ignoring this event!");
break;
}
if (!success) {
mBackend->rollbackBatchOperation();
return false;
}
}
// now we need to get all the threads that were affected by the removal of events
// this loop needs to be separate from the item removal loop because we rely on the
// count property of threads to decide if they were just modified or if they need to
// be removed.
QMap removedThreads;
QMap modifiedThreads;
Q_FOREACH(const QVariantMap &event, events) {
History::EventType type = (History::EventType) event[History::FieldType].toInt();
QString accountId = event[History::FieldAccountId].toString();
QString threadId = event[History::FieldThreadId].toString();
QVariantMap thread = mBackend->getSingleThread(type, accountId, threadId, QVariantMap());
if (thread.isEmpty()) {
continue;
}
QString hash = hashThread(thread);
if (thread[History::FieldCount].toInt() > 0) {
// the thread still has items and we should notify it was modified
modifiedThreads[hash] = thread;
} else {
removedThreads[hash] = thread;
}
}
// finally remove the threads that are now empty
Q_FOREACH(const QVariantMap &thread, removedThreads.values()) {
// the thread is now empty and needs to be removed
if (!mBackend->removeThread(thread)) {
mBackend->rollbackBatchOperation();
return false;
}
}
mBackend->endBatchOperation();
History::MmsStorageManager::instance()->removeAttachmentsFromEvents(events);
History::MmsStorageManager::instance()->removeAttachmentsFromThreads(removedThreads.values());
mDBus.notifyEventsRemoved(events);
if (!removedThreads.isEmpty()) {
mDBus.notifyThreadsRemoved(removedThreads.values());
}
if (!modifiedThreads.isEmpty()) {
mDBus.notifyThreadsModified(modifiedThreads.values());
}
return true;
}
bool HistoryDaemon::removeEvents(int type, const QVariantMap &filter, int &removedCount)
{
if (!mBackend) {
return false;
}
History::EventType eventType = (History::EventType) type;
History::Filter theFilter = History::Filter::fromProperties(filter);
QList attachments;
if (eventType == History::EventTypeText) {
attachments = mBackend->attachmentFilePathsForFilter(theFilter);
}
mBackend->beginBatchOperation();
removedCount = mBackend->removeEvents(eventType, theFilter);
if (removedCount == -1) {
mBackend->rollbackBatchOperation();
return false;
}
mBackend->endBatchOperation();
History::MmsStorageManager::instance()->removeAttachments(attachments);
mEmblemCountManager->updateCounter((History::EventType) type);
return true;
}
int HistoryDaemon::getEventsCount(int type, const QVariantMap &filter)
{
History::Filter theFilter = History::Filter::fromProperties(filter);
return mBackend->eventsCount((History::EventType)type, theFilter);
}
int HistoryDaemon::getUnreadCount(History::EventType type)
{
return mBackend->unreadCount(type);
}
void HistoryDaemon::markThreadsAsRead(const QList &threads)
{
if (!mBackend) {
return;
}
QList modifiedThreads;
Q_FOREACH(const QVariantMap &thread, threads) {
mBackend->beginBatchOperation();
QVariantMap newThread = mBackend->markThreadAsRead(thread);
if (!newThread.isEmpty()) {
modifiedThreads << newThread;
}
mBackend->endBatchOperation();
}
if (!modifiedThreads.isEmpty()) {
mDBus.notifyThreadsModified(modifiedThreads);
mEmblemCountManager->updateCounters();
}
}
bool HistoryDaemon::removeThreads(const QList &threads)
{
if (!mBackend) {
return false;
}
// If the thread has events
mBackend->beginBatchOperation();
Q_FOREACH(const QVariantMap &thread, threads) {
if (!mBackend->removeThread(thread)) {
mBackend->rollbackBatchOperation();
return false;
}
}
mBackend->endBatchOperation();
mEmblemCountManager->updateCounters();
mDBus.notifyThreadsRemoved(threads);
History::MmsStorageManager::instance()->removeAttachmentsFromThreads(threads);
return true;
}
void HistoryDaemon::onObserverCreated()
{
History::ChannelObserver *observer = History::TelepathyHelper::instance()->channelObserver();
connect(observer, SIGNAL(callChannelAvailable(Tp::CallChannelPtr)),
&mCallObserver, SLOT(onCallChannelAvailable(Tp::CallChannelPtr)));
connect(observer, SIGNAL(textChannelAvailable(Tp::TextChannelPtr)),
&mTextObserver, SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));
}
void HistoryDaemon::onCallEnded(const Tp::CallChannelPtr &channel, bool missed)
{
QVariantMap properties = propertiesFromChannel(channel);
QVariantList participants;
Q_FOREACH(const Tp::ContactPtr contact, channel->remoteMembers()) {
QVariantMap contactProperties;
contactProperties[History::FieldAlias] = contact->alias();
contactProperties[History::FieldIdentifier] = contact->id();
contactProperties[History::FieldAccountId] = channel->property(History::FieldAccountId).toString();
participants << contactProperties;
}
// it shouldn't happen, but in case it does, we won't crash
if (participants.isEmpty()) {
qWarning() << "Participants list was empty for call channel" << channel;
return;
}
QString accountId = channel->property(History::FieldAccountId).toString();
QVariantMap thread = threadForProperties(accountId,
History::EventTypeVoice,
properties,
matchFlagsForChannel(channel),
true);
// fill the call info
QDateTime timestamp = channel->property(History::FieldTimestamp).toDateTime();
// FIXME: check if checking for isRequested() is enough
bool incoming = !channel->isRequested();
int duration = 0;
if (!missed) {
QDateTime activeTime = channel->property("activeTimestamp").toDateTime();
duration = activeTime.secsTo(QDateTime::currentDateTime());
}
QString eventId = QString("%1:%2").arg(thread[History::FieldThreadId].toString()).arg(timestamp.toString());
QVariantMap event;
event[History::FieldType] = History::EventTypeVoice;
event[History::FieldAccountId] = thread[History::FieldAccountId];
event[History::FieldThreadId] = thread[History::FieldThreadId];
event[History::FieldEventId] = eventId;
event[History::FieldSenderId] = incoming ? channel->initiatorContact()->id() : "self";
event[History::FieldTimestamp] = timestamp.toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldNewEvent] = missed; // only mark as a new (unseen) event if it is a missed call
event[History::FieldMissed] = missed;
event[History::FieldDuration] = duration;
// FIXME: check what to do when there are more than just one remote participant
event[History::FieldRemoteParticipant] = participants[0].toMap()[History::FieldIdentifier];
writeEvents(QList() << event, properties);
}
void HistoryDaemon::onTextChannelInvalidated(const Tp::TextChannelPtr channel)
{
mRolesMap.remove(channel->objectPath());
QString accountId = channel->property(History::FieldAccountId).toString();
QVariantMap properties = propertiesFromChannel(channel);
// first try to fetch the existing thread to see if there is any.
QVariantMap thread = threadForProperties(accountId,
History::EventTypeText,
properties,
matchFlagsForChannel(channel),
false);
QVariantMap roomInfo = thread[History::FieldChatRoomInfo].toMap();
if ((roomInfo.contains("Persistent") && !roomInfo["Persistent"].toBool()) && History::TelepathyHelper::instance()->accountForId(accountId)->protocolName() != "ofono") {
writeInformationEvent(thread, History::InformationTypeSelfLeaving);
// update backend
updateRoomProperties(channel, QVariantMap{{"Joined", false}});
}
channel->disconnect(this);
}
void HistoryDaemon::onTextChannelAvailable(const Tp::TextChannelPtr channel)
{
// for Rooms we need to explicitly create the thread to allow users to send messages to groups even
// before they receive any message.
// for other types, we can wait until messages are received
bool notify = false;
if (channel->targetHandleType() == Tp::HandleTypeRoom) {
QString accountId = channel->property(History::FieldAccountId).toString();
QVariantMap properties = propertiesFromChannel(channel);
// first try to fetch the existing thread to see if there is any.
QVariantMap thread = threadForProperties(accountId,
History::EventTypeText,
properties,
matchFlagsForChannel(channel),
false);
if (thread.isEmpty()) {
// if there no existing thread, create one
properties["Requested"] = channel->isRequested();
thread = threadForProperties(accountId,
History::EventTypeText,
properties,
matchFlagsForChannel(channel),
true);
// write information event including all initial invitees
Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
writeInformationEvent(thread, History::InformationTypeInvitationSent, contact->alias(), QString(), QString(), false);
}
// update participants only if the thread is not available previously. Otherwise we'll wait for membersChanged event
// for reflect in conversation information events for modified participants.
updateRoomParticipants(channel, false);
notify = true;
}
// write an entry saying you joined the group if 'joined' flag in thread is false and modify that flag.
if (!thread[History::FieldChatRoomInfo].toMap()["Joined"].toBool()) {
// only write self joined notification if protocol is not a phone one.
// FIXME (rmescandon): as a first solution, let's take only ofono as phone protocol
if (History::TelepathyHelper::instance()->accountForId(accountId)->protocolName() != "ofono") {
writeInformationEvent(thread, History::InformationTypeSelfJoined);
}
// update backend
updateRoomProperties(channel, QVariantMap{{"Joined", true}}, false);
notify = true;
}
Tp::AbstractInterface *room_interface = channel->optionalInterface();
Tp::AbstractInterface *room_config_interface = channel->optionalInterface();
Tp::AbstractInterface *subject_interface = channel->optionalInterface();
ChannelInterfaceRolesInterface *roles_interface = channel->optionalInterface();
QList interfaces;
interfaces << room_interface << room_config_interface << subject_interface << roles_interface;
for (auto interface : interfaces) {
if (interface) {
interface->setMonitorProperties(true);
interface->setProperty(History::FieldAccountId, accountId);
interface->setProperty(History::FieldThreadId, thread[History::FieldThreadId].toString());
interface->setProperty(History::FieldType, thread[History::FieldType].toInt());
connect(interface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)),
SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &)));
// update the stored info
Q_EMIT interface->propertiesChanged(getInterfaceProperties(interface), QStringList());
}
}
connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)),
SLOT(onGroupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)));
connect(roles_interface, SIGNAL(RolesChanged(const HandleRolesMap&, const HandleRolesMap&)), SLOT(onRolesChanged(const HandleRolesMap&, const HandleRolesMap&)));
}
if (notify) {
updateRoomParticipants(channel, true);
}
}
void HistoryDaemon::onGroupMembersChanged(const Tp::Contacts &groupMembersAdded,
const Tp::Contacts& /* groupLocalPendingMembersAdded */,
const Tp::Contacts &groupRemotePendingMembersAdded,
const Tp::Contacts &groupMembersRemoved,
const Tp::Channel::GroupMemberChangeDetails& /* details */)
{
Tp::TextChannelPtr channel(qobject_cast(sender()));
QVariantMap properties;
QVariantMap thread;
// information events for members updates.
bool hasRemotePendingMembersAdded = groupRemotePendingMembersAdded.size() > 0;
bool hasMembersAdded = groupMembersAdded.size() > 0;
bool hasMembersRemoved = groupMembersRemoved.size() > 0;
Tp::ContactPtr selfContact = channel->connection()->selfContact();
bool selfContactIsPending = channel->groupRemotePendingContacts(true).contains(selfContact);
if (hasRemotePendingMembersAdded || hasMembersAdded || hasMembersRemoved) {
properties = propertiesFromChannel(channel);
thread = threadForProperties(channel->property(History::FieldAccountId).toString(),
History::EventTypeText,
properties,
matchFlagsForChannel(channel),
false);
if (!thread.isEmpty() && !selfContactIsPending) {
QList added;
QList removed;
QList modified;
if (hasRemotePendingMembersAdded) {
Q_FOREACH (const Tp::ContactPtr& contact, groupRemotePendingMembersAdded) {
if (!foundInThread(contact, thread)) {
writeInformationEvent(thread, History::InformationTypeInvitationSent, contact->alias(), QString(), QString(), true);
QVariantMap participant;
participant[History::FieldIdentifier] = contact->id();
participant[History::FieldAlias] = contact->alias();
participant[History::FieldParticipantState] = History::ParticipantStateRemotePending;
added << participant;
}
}
}
if (hasMembersAdded) {
Q_FOREACH (const Tp::ContactPtr& contact, groupMembersAdded) {
// if this member was not previously regular member in thread, notify about his join
if (!foundAsMemberInThread(contact, thread) && contact->id() != channel->groupSelfContact()->id()) {
writeInformationEvent(thread, History::InformationTypeJoined, contact->alias(), QString(), QString(), true);
QVariantMap participant;
participant[History::FieldIdentifier] = contact->id();
participant[History::FieldAlias] = contact->alias();
participant[History::FieldParticipantState] = History::ParticipantStateRegular;
added << participant;
}
}
}
if (hasMembersRemoved) {
if (channel->groupSelfContactRemoveInfo().isValid()) {
// evaluate if we are leaving by our own or we are kicked
History::InformationType type = History::InformationTypeSelfLeaving;
if (channel->groupSelfContactRemoveInfo().hasReason()) {
switch (channel->groupSelfContactRemoveInfo().reason()) {
case ChannelGroupChangeReasonKicked:
type = History::InformationTypeSelfKicked;
break;
// As ChannelGroupChangeReasonGone is not in telepathy, we need to ignore the warning
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
case ChannelGroupChangeReasonGone:
type = History::InformationTypeGroupGone;
break;
#pragma GCC diagnostic pop
default:
break;
}
}
if (thread[History::FieldChatRoomInfo].toMap()["Joined"].toBool()) {
writeInformationEvent(thread, type);
// update backend
updateRoomProperties(channel, QVariantMap{{"Joined", false}}, true);
}
}
else // don't notify any other group member removal if we are leaving the group
{
Q_FOREACH (const Tp::ContactPtr& contact, groupMembersRemoved) {
// inform about removed members other than us
if (contact->id() != channel->groupSelfContact()->id()) {
writeInformationEvent(thread, History::InformationTypeLeaving, contact->alias(), QString(), QString(), true);
}
QVariantMap participant;
participant[History::FieldIdentifier] = contact->id();
participant[History::FieldAlias] = contact->alias();
removed << participant;
}
}
}
mDBus.notifyThreadParticipantsChanged(thread, added, removed, QList());
}
}
updateRoomParticipants(channel, !selfContactIsPending);
}
void HistoryDaemon::updateRoomParticipants(const Tp::TextChannelPtr channel, bool notify)
{
if (!channel) {
return;
}
QVariantList participants;
QStringList contactsAdded;
ChannelInterfaceRolesInterface *roles_interface = channel->optionalInterface();
RolesMap roles;
if (roles_interface) {
if (!mRolesMap.contains(channel->objectPath())) {
roles = roles_interface->getRoles();
mRolesMap[channel->objectPath()] = roles;
} else {
roles = mRolesMap[channel->objectPath()];
}
}
Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
QVariantMap participant;
contactsAdded << contact->id();
participant[History::FieldIdentifier] = contact->id();
participant[History::FieldAlias] = contact->alias();
participant[History::FieldParticipantState] = History::ParticipantStateRemotePending;
participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
participants << QVariant::fromValue(participant);
}
Q_FOREACH(const Tp::ContactPtr contact, channel->groupLocalPendingContacts(false)) {
QVariantMap participant;
contactsAdded << contact->id();
participant[History::FieldIdentifier] = contact->id();
participant[History::FieldAlias] = contact->alias();
participant[History::FieldParticipantState] = History::ParticipantStateLocalPending;
participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
participants << QVariant::fromValue(participant);
}
Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
// do not include remote and local pending members
if (contactsAdded.contains(contact->id())) {
continue;
}
QVariantMap participant;
participant[History::FieldIdentifier] = contact->id();
participant[History::FieldAlias] = contact->alias();
participant[History::FieldParticipantState] = History::ParticipantStateRegular;
participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
participants << QVariant::fromValue(participant);
}
QString accountId = channel->property(History::FieldAccountId).toString();
QString threadId = channel->targetId();
if (mBackend->updateRoomParticipants(accountId, threadId, History::EventTypeText, participants)) {
if (notify) {
QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
mDBus.notifyThreadsModified(QList() << updatedThread);
}
}
}
void HistoryDaemon::updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap, bool notify)
{
if (!channel) {
return;
}
QVariantMap participantsRoles;
Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
}
Q_FOREACH(const Tp::ContactPtr contact, channel->groupLocalPendingContacts(false)) {
participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
}
Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
if (!participantsRoles.contains(contact->id())) {
participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
}
}
// update participants roles
QString accountId = channel->property(History::FieldAccountId).toString();
QString threadId = channel->targetId();
if (mBackend->updateRoomParticipantsRoles(accountId, threadId, History::EventTypeText, participantsRoles)) {
if (notify) {
QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
mDBus.notifyThreadsModified(QList() << updatedThread);
}
}
// update self roles in room properties
uint selfRoles = rolesMap[channel->groupSelfContact()->handle().at(0)];
updateRoomProperties(channel, QVariantMap{{"SelfRoles", selfRoles}});
}
void HistoryDaemon::onRoomPropertiesChanged(const QVariantMap &properties,const QStringList &invalidated)
{
QString accountId = sender()->property(History::FieldAccountId).toString();
QString threadId = sender()->property(History::FieldThreadId).toString();
History::EventType type = (History::EventType)sender()->property(History::FieldType).toInt();
// get thread before updating to see if there are changes to insert as information events
QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
if (!thread.empty()) {
writeRoomChangesInformationEvents(thread, properties);
}
updateRoomProperties(accountId, threadId, type, properties, invalidated);
}
void HistoryDaemon::updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties, bool notify)
{
QString accountId = channel->property(History::FieldAccountId).toString();
QString threadId = channel->targetId();
History::EventType type = History::EventTypeText;
updateRoomProperties(accountId, threadId, type, properties, QStringList(), notify);
}
void HistoryDaemon::updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated, bool notify)
{
if (mBackend->updateRoomInfo(accountId, threadId, type, properties, invalidated)) {
if (notify) {
QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
mDBus.notifyThreadsModified(QList() << thread);
}
}
}
void HistoryDaemon::onMessageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message)
{
QString eventId;
QString senderId;
QString accountId = textChannel->property(History::FieldAccountId).toString();
QString threadId = textChannel->property(History::FieldThreadId).toString();
QVariantMap properties = propertiesFromChannel(textChannel);
if (threadId.isNull()) {
threadId = threadIdForProperties(accountId,
History::EventTypeText,
properties,
matchFlagsForChannel(textChannel),
true);
}
History::MessageStatus status = History::MessageStatusUnknown;
if (!message.sender() || message.sender()->handle().at(0) == textChannel->connection()->selfHandle()) {
senderId = "self";
status = History::MessageStatusDelivered;
} else {
senderId = message.sender()->id();
}
if (message.messageToken().isEmpty()) {
eventId = QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz");
} else {
eventId = message.messageToken();
}
// ignore delivery reports for now.
// FIXME: maybe we should set the readTimestamp when a delivery report is received
if (message.isRescued()) {
return;
}
if (message.isDeliveryReport() && message.deliveryDetails().hasOriginalToken()) {
// at this point we assume the delivery report is for a message that was already
// sent and properly saved at our database, so we can safely get it here to update
QVariantMap textEvent = getSingleEvent(History::EventTypeText, accountId, threadId, message.deliveryDetails().originalToken());
if (textEvent.isEmpty()) {
qWarning() << "Cound not find the original event to update with delivery details.";
return;
}
// FIXME: if this message is already read, don't allow reverting the status.
// we need to check if this is the right place to do it.
if (textEvent[History::FieldMessageStatus].toInt() == History::MessageStatusRead) {
qWarning() << "Skipping delivery report as it is trying to revert the Read status of an existing message to the following status:" << message.deliveryDetails().status();
return;
}
textEvent[History::FieldMessageStatus] = (int) fromTelepathyDeliveryStatus(message.deliveryDetails().status());
if (!writeEvents(QList() << textEvent, properties)) {
qWarning() << "Failed to save the new message status!";
}
return;
}
int count = 1;
QList attachments;
History::MessageType type = History::MessageTypeText;
QString subject;
if (message.hasNonTextContent()) {
type = History::MessageTypeMultiPart;
subject = message.header()["subject"].variant().toString();
Q_FOREACH(const Tp::MessagePart &part, message.parts()) {
// ignore the header part
if (part["content-type"].variant().toString().isEmpty()) {
continue;
}
QString attachmentFilePath = History::MmsStorageManager::instance()->saveAttachment(part, accountId, threadId, eventId);
if (attachmentFilePath.isNull()) {
qWarning() << "Failed to save attachment for attachment id:" << part["identifier"].variant().toString();
continue;
}
QVariantMap attachment;
attachment[History::FieldAccountId] = accountId;
attachment[History::FieldThreadId] = threadId;
attachment[History::FieldEventId] = eventId;
attachment[History::FieldAttachmentId] = part["identifier"].variant();
attachment[History::FieldContentType] = part["content-type"].variant();
attachment[History::FieldFilePath] = attachmentFilePath;
attachment[History::FieldStatus] = (int) History::AttachmentDownloaded;
attachments << attachment;
}
}
QString text = message.text();
if (message.deliveryDetails().isError()) {
status = fromTelepathyDeliveryStatus(message.deliveryDetails().status());
text = message.deliveryDetails().debugMessage();
}
QVariantMap event;
event[History::FieldType] = History::EventTypeText;
event[History::FieldAccountId] = accountId;
event[History::FieldThreadId] = threadId;
event[History::FieldEventId] = eventId;
event[History::FieldSenderId] = senderId;
event[History::FieldTimestamp] = message.received().toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldSentTime] = message.sent().toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldNewEvent] = true; // message is always unread until it reaches HistoryDaemon::onMessageRead
event[History::FieldMessage] = text;
event[History::FieldMessageType] = (int)type;
event[History::FieldMessageStatus] = (int)status;
event[History::FieldReadTimestamp] = QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldSubject] = subject;
event[History::FieldAttachments] = QVariant::fromValue(attachments);
writeEvents(QList() << event, properties);
// if this messages supersedes another one, remove the original message
if (!message.supersededToken().isEmpty()) {
event[History::FieldEventId] = message.supersededToken();
removeEvents(QList() << event);
}
}
QVariantMap HistoryDaemon::getSingleEventFromTextChannel(const Tp::TextChannelPtr textChannel, const QString &messageId)
{
QVariantMap properties = propertiesFromChannel(textChannel);
QVariantMap thread = threadForProperties(textChannel->property(History::FieldAccountId).toString(),
History::EventTypeText,
properties,
matchFlagsForChannel(textChannel),
false);
if (thread.isEmpty()) {
qWarning() << "Cound not find the thread related to this eventId.";
return QVariantMap();
}
QVariantMap textEvent = getSingleEvent((int)History::EventTypeText,
textChannel->property(History::FieldAccountId).toString(),
thread[History::FieldThreadId].toString(),
messageId);
return textEvent;
}
void HistoryDaemon::onMessageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken)
{
QVariantMap properties = propertiesFromChannel(textChannel);
QList attachments;
History::MessageType type = History::MessageTypeText;
int count = 1;
QString subject;
QString eventId;
if (messageToken.isEmpty()) {
eventId = QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz");
} else {
eventId = messageToken;
}
QVariantMap thread = threadForProperties(textChannel->property(History::FieldAccountId).toString(),
History::EventTypeText,
properties,
matchFlagsForChannel(textChannel),
true);
if (message.hasNonTextContent()) {
type = History::MessageTypeMultiPart;
subject = message.header()["subject"].variant().toString();
Q_FOREACH(const Tp::MessagePart &part, message.parts()) {
// ignore the header part
if (part["content-type"].variant().toString().isEmpty()) {
continue;
}
QString attachmentFilePath = History::MmsStorageManager::instance()->saveAttachment(part, thread[History::FieldAccountId].toString(), thread[History::FieldThreadId].toString(), eventId);
if (attachmentFilePath.isNull()) {
qWarning() << "Failed to save attachment for attachment id:" << part["identifier"].variant().toString();
continue;
}
QVariantMap attachment;
attachment[History::FieldAccountId] = thread[History::FieldAccountId];
attachment[History::FieldThreadId] = thread[History::FieldThreadId];
attachment[History::FieldEventId] = eventId;
attachment[History::FieldAttachmentId] = part["identifier"].variant();
attachment[History::FieldContentType] = part["content-type"].variant();
attachment[History::FieldFilePath] = attachmentFilePath;
attachment[History::FieldStatus] = (int) History::AttachmentDownloaded;
attachments << attachment;
}
}
QVariantMap event;
event[History::FieldType] = History::EventTypeText;
event[History::FieldAccountId] = thread[History::FieldAccountId];
event[History::FieldThreadId] = thread[History::FieldThreadId];
event[History::FieldEventId] = eventId;
event[History::FieldSenderId] = "self";
event[History::FieldTimestamp] = QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldSentTime] = QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldNewEvent] = false; // outgoing messages are never new (unseen)
event[History::FieldMessage] = message.text();
event[History::FieldMessageType] = type;
if (textChannel->deliveryReportingSupport() & Tp::DeliveryReportingSupportFlagReceiveSuccesses) {
event[History::FieldMessageStatus] = (int)History::MessageStatusUnknown;
} else {
event[History::FieldMessageStatus] = (int)History::MessageStatusAccepted;
}
event[History::FieldReadTimestamp] = QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz");
event[History::FieldSubject] = "";
event[History::FieldAttachments] = QVariant::fromValue(attachments);
writeEvents(QList() << event, properties);
}
History::MatchFlags HistoryDaemon::matchFlagsForChannel(const Tp::ChannelPtr &channel)
{
QString protocol = channel->connection()->protocolName();
if (mProtocolFlags.contains(protocol)) {
return mProtocolFlags[protocol];
}
// default to this value
return History::MatchCaseSensitive;
}
QString HistoryDaemon::hashThread(const QVariantMap &thread)
{
QString hash = QString::number(thread[History::FieldType].toInt());
hash += "#-#" + thread[History::FieldAccountId].toString();
hash += "#-#" + thread[History::FieldThreadId].toString();
return hash;
}
QVariantMap HistoryDaemon::getInterfaceProperties(const Tp::AbstractInterface *interface)
{
QDBusInterface propsInterface(interface->service(), interface->path(), "org.freedesktop.DBus.Properties");
QDBusReply reply = propsInterface.call("GetAll", interface->interface());
if (!reply.isValid()) {
qWarning() << "Failed to fetch channel properties for interface" << interface->interface() << reply.error().message();
}
return reply.value();
}
void HistoryDaemon::writeInformationEvent(const QVariantMap &thread, History::InformationType type, const QString &subject, const QString &sender, const QString &text, bool notify)
{
History::TextEvent historyEvent = History::TextEvent(thread[History::FieldAccountId].toString(),
thread[History::FieldThreadId].toString(),
QString(QCryptographicHash::hash(QByteArray(
(QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz") + subject + text).toLatin1()),
QCryptographicHash::Md5).toHex()),
sender,
QDateTime::currentDateTime(),
QDateTime::currentDateTime(),
false,
text,
History::MessageTypeInformation,
History::MessageStatusUnknown,
QDateTime::currentDateTime(),
subject,
type);
writeEvents(QList() << historyEvent.properties(), thread, notify);
}
void HistoryDaemon::writeRoomChangesInformationEvents(const QVariantMap &thread, const QVariantMap &interfaceProperties)
{
if (!thread.isEmpty()) {
// group subject
QString storedSubject = thread[History::FieldChatRoomInfo].toMap()["Subject"].toString();
QString newSubject = interfaceProperties["Subject"].toString();
if (!newSubject.isEmpty() && storedSubject != newSubject) {
//see if we have an actor. If actor is 'me', we have changed that subject
QString actor = thread[History::FieldChatRoomInfo].toMap()["Actor"].toString();
if (actor == "me") {
actor = "self";
}
writeInformationEvent(thread, History::InformationTypeTitleChanged, newSubject, actor);
}
}
}
void HistoryDaemon::writeRolesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap)
{
if (thread.isEmpty()) {
return;
}
if (!thread[History::FieldChatRoomInfo].toMap()["Joined"].toBool()) {
return;
}
// list of identifiers for current channel admins
QStringList adminIds;
Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
// see if admin role (ChannelAdminRole == 2)
if (rolesMap[contact->handle().at(0)] & AdminRole) {
adminIds << contact->id();
}
}
Q_FOREACH (QVariant participant, thread[History::FieldParticipants].toList()) {
QString participantId = participant.toMap()[History::FieldIdentifier].toString();
if (adminIds.contains(participantId)) {
// see if already was admin or not (ChannelAdminRole == 2)
if (! (participant.toMap()[History::FieldParticipantRoles].toUInt() & AdminRole)) {
writeInformationEvent(thread, History::InformationTypeAdminGranted, participantId);
}
}
}
//evaluate now self roles
if (rolesMap[channel->groupSelfContact()->handle().at(0)] & AdminRole) {
uint selfRoles = thread[History::FieldChatRoomInfo].toMap()["SelfRoles"].toUInt();
if (! (selfRoles & AdminRole)) {
writeInformationEvent(thread, History::InformationTypeSelfAdminGranted);
}
}
}
History::MessageStatus HistoryDaemon::fromTelepathyDeliveryStatus(Tp::DeliveryStatus deliveryStatus)
{
History::MessageStatus status = History::MessageStatusUnknown;
switch (deliveryStatus) {
case Tp::DeliveryStatusAccepted:
status = History::MessageStatusAccepted;
break;
case Tp::DeliveryStatusDeleted:
status = History::MessageStatusDeleted;
break;
case Tp::DeliveryStatusDelivered:
status = History::MessageStatusDelivered;
break;
case Tp::DeliveryStatusPermanentlyFailed:
status = History::MessageStatusPermanentlyFailed;
break;
case Tp::DeliveryStatusRead:
status = History::MessageStatusRead;
break;
case Tp::DeliveryStatusTemporarilyFailed:
status = History::MessageStatusTemporarilyFailed;
break;
case Tp::DeliveryStatusUnknown:
status = History::MessageStatusUnknown;
break;
case Tp::_DeliveryStatusPadding:
status = History::_MessageStatusPadding;
break;
}
return status;
}
History::ChatType HistoryDaemon::fromTelepathyHandleType(const Tp::HandleType &type)
{
History::ChatType chatType = History::ChatTypeNone;
switch(type) {
case Tp::HandleTypeContact:
chatType = History::ChatTypeContact;
break;
case Tp::HandleTypeNone:
chatType = History::ChatTypeNone;
break;
case Tp::HandleTypeRoom:
chatType = History::ChatTypeRoom;
break;
case Tp::HandleTypeGroup:
chatType = History::ChatTypeGroup;
break;
case Tp::HandleTypeList:
chatType = History::ChatTypeList;
break;
case Tp::_HandleTypePadding:
chatType = History::_ChatTypePadding;
break;
}
return chatType;
}
history-service-0.5/daemon/historydaemon.h 0000664 0000000 0000000 00000013471 14554502467 0021040 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2017 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYDAEMON_H
#define HISTORYDAEMON_H
#include
#include
#include
#include "types.h"
#include "textchannelobserver.h"
#include "callchannelobserver.h"
#include "emblemcountmanager.h"
#include "historyservicedbus.h"
#include "plugin.h"
#include "rolesinterface.h"
typedef QMap RolesMap;
class HistoryDaemon : public QObject
{
Q_OBJECT
public:
~HistoryDaemon();
static HistoryDaemon *instance();
QVariantMap propertiesFromChannel(const Tp::ChannelPtr &textChannel);
QVariantMap threadForProperties(const QString &accountId,
History::EventType type,
const QVariantMap &properties,
History::MatchFlags matchFlags = History::MatchCaseSensitive,
bool create = true);
QString threadIdForProperties(const QString &accountId,
History::EventType type,
const QVariantMap &properties,
History::MatchFlags matchFlags = History::MatchCaseSensitive,
bool create = true);
QList participantsForThreads(const QList &threadIds);
QString queryThreads(int type, const QVariantMap &sort, const QVariantMap &filter, const QVariantMap &properties);
QString queryEvents(int type, const QVariantMap &sort, const QVariantMap &filter);
QVariantMap getSingleThread(int type, const QString &accountId, const QString &threadId, const QVariantMap &properties);
QVariantMap getSingleEvent(int type, const QString &accountId, const QString &threadId, const QString &eventId);
QVariantMap getSingleEventFromTextChannel(const Tp::TextChannelPtr textChannel, const QString &messageId);
bool writeEvents(const QList &events, const QVariantMap &properties, bool notify = true);
bool removeEvents(const QList &events);
bool removeEvents(int type, const QVariantMap &filter, int &removedCount);
int getEventsCount(int type, const QVariantMap &filter);
int getUnreadCount(History::EventType type);
bool removeThreads(const QList &threads);
void markThreadsAsRead(const QList &threads);
private Q_SLOTS:
void onObserverCreated();
void onCallEnded(const Tp::CallChannelPtr &channel, bool missed);
void onMessageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message);
void onMessageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken);
void onTextChannelAvailable(const Tp::TextChannelPtr channel);
void onTextChannelInvalidated(const Tp::TextChannelPtr channel);
void onRoomPropertiesChanged(const QVariantMap &properties,const QStringList &invalidated);
void onGroupMembersChanged(const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded,
const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved,
const Tp::Channel::GroupMemberChangeDetails &details);
void onRolesChanged(const HandleRolesMap &added, const HandleRolesMap &removed);
protected:
History::MatchFlags matchFlagsForChannel(const Tp::ChannelPtr &channel);
void updateRoomParticipants(const Tp::TextChannelPtr channel, bool notify = true);
void updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap, bool notify = true);
QString hashThread(const QVariantMap &thread);
static QVariantMap getInterfaceProperties(const Tp::AbstractInterface *interface);
void updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties, bool notify = true);
void updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated, bool notify = true);
void writeInformationEvent(const QVariantMap &thread, History::InformationType type, const QString &subject = QString(), const QString &sender = QString("self"), const QString &text = QString(), bool notify = true);
void writeRoomChangesInformationEvents(const QVariantMap &thread, const QVariantMap &interfaceProperties);
void writeRolesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap);
void writeRolesChangesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap);
static History::MessageStatus fromTelepathyDeliveryStatus(Tp::DeliveryStatus deliveryStatus);
static History::ChatType fromTelepathyHandleType(const Tp::HandleType &type);
private:
HistoryDaemon(QObject *parent = 0);
CallChannelObserver mCallObserver;
TextChannelObserver mTextObserver;
QMap mProtocolFlags;
History::PluginPtr mBackend;
HistoryServiceDBus mDBus;
EmblemCountManager* mEmblemCountManager;
QMap mRolesMap;
};
#endif
history-service-0.5/daemon/historyservicedbus.cpp 0000664 0000000 0000000 00000017617 14554502467 0022454 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2016 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "historydaemon.h"
#include "historyservicedbus.h"
#include "historyserviceadaptor.h"
#include "types.h"
Q_DECLARE_METATYPE(QList< QVariantMap >)
HistoryServiceDBus::HistoryServiceDBus(QObject *parent) :
QObject(parent), mAdaptor(0), mSignalsTimer(-1)
{
qDBusRegisterMetaType >();
}
bool HistoryServiceDBus::connectToBus()
{
if (!mAdaptor) {
mAdaptor = new HistoryServiceAdaptor(this);
}
if (!QDBusConnection::sessionBus().registerObject(History::DBusObjectPath, this)) {
return false;
}
return QDBusConnection::sessionBus().registerService(History::DBusService);
}
void HistoryServiceDBus::notifyThreadsAdded(const QList &threads)
{
mThreadsAdded << threads;
triggerSignals();
}
void HistoryServiceDBus::notifyThreadsModified(const QList &threads)
{
mThreadsModified << threads;
triggerSignals();
}
void HistoryServiceDBus::notifyThreadsRemoved(const QList &threads)
{
mThreadsRemoved << threads;
triggerSignals();
}
void HistoryServiceDBus::notifyEventsAdded(const QList &events)
{
mEventsAdded << events;
triggerSignals();
}
void HistoryServiceDBus::notifyEventsModified(const QList &events)
{
mEventsModified << events;
triggerSignals();
}
void HistoryServiceDBus::notifyEventsRemoved(const QList &events)
{
mEventsRemoved << events;
triggerSignals();
}
void HistoryServiceDBus::notifyThreadParticipantsChanged(const QVariantMap &thread,
const QList &added,
const QList &removed,
const QList &modified)
{
Q_EMIT ThreadParticipantsChanged(thread, added, removed, modified);
}
QVariantMap HistoryServiceDBus::ThreadForProperties(const QString &accountId,
int type,
const QVariantMap &properties,
int matchFlags,
bool create)
{
return HistoryDaemon::instance()->threadForProperties(accountId,
(History::EventType) type,
properties,
(History::MatchFlags) matchFlags,
create);
}
QList HistoryServiceDBus::ParticipantsForThreads(const QList &threadIds)
{
return HistoryDaemon::instance()->participantsForThreads(threadIds);
}
QVariantMap HistoryServiceDBus::ThreadForParticipants(const QString &accountId,
int type,
const QStringList &participants,
int matchFlags,
bool create)
{
QVariantMap properties;
properties[History::FieldParticipants] = participants;
return HistoryDaemon::instance()->threadForProperties(accountId,
(History::EventType) type,
properties,
(History::MatchFlags) matchFlags,
create);
}
bool HistoryServiceDBus::WriteEvents(const QList &events)
{
return HistoryDaemon::instance()->writeEvents(events, QVariantMap());
}
bool HistoryServiceDBus::RemoveThreads(const QList &threads)
{
return HistoryDaemon::instance()->removeThreads(threads);
}
void HistoryServiceDBus::MarkThreadsAsRead(const QList &threads)
{
return HistoryDaemon::instance()->markThreadsAsRead(threads);
}
int HistoryServiceDBus::GetEventsCount(int type, const QVariantMap &filter)
{
return HistoryDaemon::instance()->getEventsCount(type, filter);
}
bool HistoryServiceDBus::RemoveEvents(const QList &events)
{
return HistoryDaemon::instance()->removeEvents(events);
}
int HistoryServiceDBus::RemoveEventsBy(int type, const QVariantMap &filter)
{
int removedCount = 0;
bool ok = HistoryDaemon::instance()->removeEvents(type, filter, removedCount);
if (!ok) {
sendErrorReply(QDBusError::InternalError, "Issue while removing events");
}
return removedCount;
}
QString HistoryServiceDBus::QueryThreads(int type, const QVariantMap &sort, const QVariantMap &filter, const QVariantMap &properties)
{
return HistoryDaemon::instance()->queryThreads(type, sort, filter, properties);
}
QString HistoryServiceDBus::QueryEvents(int type, const QVariantMap &sort, const QVariantMap &filter)
{
return HistoryDaemon::instance()->queryEvents(type, sort, filter);
}
QVariantMap HistoryServiceDBus::GetSingleThread(int type, const QString &accountId, const QString &threadId, const QVariantMap &properties)
{
return HistoryDaemon::instance()->getSingleThread(type, accountId, threadId, properties);
}
QVariantMap HistoryServiceDBus::GetSingleEvent(int type, const QString &accountId, const QString &threadId, const QString &eventId)
{
return HistoryDaemon::instance()->getSingleEvent(type, accountId, threadId, eventId);
}
void HistoryServiceDBus::timerEvent(QTimerEvent *event)
{
if (event->timerId() == mSignalsTimer) {
killTimer(mSignalsTimer);
mSignalsTimer = -1;
processSignals();
}
}
void HistoryServiceDBus::filterDuplicatesAndAdd(QList &targetList, const QList newItems, const QStringList &propertiesToCompare)
{
Q_FOREACH (const QVariantMap &item, newItems) {
Q_FOREACH(const QVariantMap &existing, targetList) {
bool found = true;
Q_FOREACH(const QString &prop, propertiesToCompare) {
if (item[prop] != existing[prop]) {
found = false;
break;
}
}
if (!found) {
targetList << item;
}
}
}
}
void HistoryServiceDBus::triggerSignals()
{
if (mSignalsTimer >= 0) {
killTimer(mSignalsTimer);
}
mSignalsTimer = startTimer(100);
}
void HistoryServiceDBus::processSignals()
{
if (!mThreadsAdded.isEmpty()) {
Q_EMIT ThreadsAdded(mThreadsAdded);
mThreadsAdded.clear();
}
if (!mThreadsModified.isEmpty()) {
Q_EMIT ThreadsModified(mThreadsModified);
mThreadsModified.clear();
}
if (!mThreadsRemoved.isEmpty()) {
Q_EMIT ThreadsRemoved(mThreadsRemoved);
mThreadsRemoved.clear();
}
if (!mEventsAdded.isEmpty()) {
Q_EMIT EventsAdded(mEventsAdded);
mEventsAdded.clear();
}
if (!mEventsModified.isEmpty()) {
Q_EMIT EventsModified(mEventsModified);
mEventsModified.clear();
}
if (!mEventsRemoved.isEmpty()) {
Q_EMIT EventsRemoved(mEventsRemoved);
mEventsRemoved.clear();
}
}
history-service-0.5/daemon/historyservicedbus.h 0000664 0000000 0000000 00000010667 14554502467 0022117 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2013-2016 Canonical, Ltd.
*
* Authors:
* Gustavo Pichorim Boiko
*
* This file is part of history-service.
*
* history-service is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* history-service is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HISTORYSERVICEDBUS_H
#define HISTORYSERVICEDBUS_H
#include
#include
#include "types.h"
class HistoryServiceAdaptor;
class HistoryServiceDBus : public QObject, public QDBusContext
{
Q_OBJECT
public:
explicit HistoryServiceDBus(QObject *parent = 0);
bool connectToBus();
void notifyThreadsAdded(const QList &threads);
void notifyThreadsModified(const QList &threads);
void notifyThreadsRemoved(const QList &threads);
void notifyThreadParticipantsChanged(const QVariantMap &thread,
const QList &added,
const QList &removed,
const QList &modified);
void notifyEventsAdded(const QList &events);
void notifyEventsModified(const QList &events);
void notifyEventsRemoved(const QList &events);
// functions exposed on DBUS
QVariantMap ThreadForParticipants(const QString &accountId,
int type,
const QStringList &participants,
int matchFlags,
bool create);
QVariantMap ThreadForProperties(const QString &accountId,
int type,
const QVariantMap &properties,
int matchFlags,
bool create);
QList ParticipantsForThreads(const QList &threadIds);
bool WriteEvents(const QList &events);
bool RemoveThreads(const QList &threads);
bool RemoveEvents(const QList &events);
int RemoveEventsBy(int type, const QVariantMap &filter);
void MarkThreadsAsRead(const QList &threads);
int GetEventsCount(int type, const QVariantMap &filter);
// views
QString QueryThreads(int type, const QVariantMap &sort, const QVariantMap &filter, const QVariantMap &properties);
QString QueryEvents(int type, const QVariantMap &sort, const QVariantMap &filter);
QVariantMap GetSingleThread(int type, const QString &accountId, const QString &threadId, const QVariantMap &properties);
QVariantMap GetSingleEvent(int type, const QString &accountId, const QString &threadId, const QString &eventId);
Q_SIGNALS:
// signals that will be relayed into the bus
void ThreadsAdded(const QList &threads);
void ThreadsModified(const QList