Skip to content
Snippets Groups Projects
  • Andreas Traczyk's avatar
    4bda3306
    swarm: simplify and update avatar update mechanism · 4bda3306
    Andreas Traczyk authored
    Implements a leaner avatar caching system. The avatar component
    listens for uid filtering its id, which may be:
    - conversation id
    - account id
    - contact uri
    
    In response to the uid change, a the image source is updated with
    a new image url invoking a fresh QQuickImageProvider query. With
    this design, only the avatarregistry's uid mapping needs to be
    updated when profiles are changed, and no longer should specific
    avatar components receive manual source updates.
    
    Gitlab: #466
    Change-Id: Ie5313f5c187a0977ca51b890dd92187480a42537
    4bda3306
    History
    swarm: simplify and update avatar update mechanism
    Andreas Traczyk authored
    Implements a leaner avatar caching system. The avatar component
    listens for uid filtering its id, which may be:
    - conversation id
    - account id
    - contact uri
    
    In response to the uid change, a the image source is updated with
    a new image url invoking a fresh QQuickImageProvider query. With
    this design, only the avatarregistry's uid mapping needs to be
    updated when profiles are changed, and no longer should specific
    avatar components receive manual source updates.
    
    Gitlab: #466
    Change-Id: Ie5313f5c187a0977ca51b890dd92187480a42537
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CMakeLists.txt 18.15 KiB
cmake_minimum_required(VERSION 3.7)

project(jami-qt)

if(MSVC)
    cmake_minimum_required(VERSION 3.15)
endif()

# todo: show error if Qt version < 5.14
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS_DEBUG "-Og -ggdb")

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(SRC_DIR ${PROJECT_SOURCE_DIR}/src)
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true)

set(QML_RESOURCES ${PROJECT_SOURCE_DIR}/resources.qrc)
set(QML_RESOURCES_QML ${PROJECT_SOURCE_DIR}/qml.qrc)

# library compatibility (boost, libnotify, etc.)
add_definitions(-DQT_NO_KEYWORDS)

set(COMMON_SOURCES
    ${SRC_DIR}/bannedlistmodel.cpp
    ${SRC_DIR}/accountlistmodel.cpp
    ${SRC_DIR}/networkmanager.cpp
    ${SRC_DIR}/runguard.cpp
    ${SRC_DIR}/updatemanager.cpp
    ${SRC_DIR}/webchathelpers.cpp
    ${SRC_DIR}/main.cpp
    ${SRC_DIR}/smartlistmodel.cpp
    ${SRC_DIR}/utils.cpp
    ${SRC_DIR}/rendermanager.cpp
    ${SRC_DIR}/connectivitymonitor.cpp
    ${SRC_DIR}/mainapplication.cpp
    ${SRC_DIR}/messagesadapter.cpp
    ${SRC_DIR}/accountadapter.cpp
    ${SRC_DIR}/calladapter.cpp
    ${SRC_DIR}/conversationsadapter.cpp
    ${SRC_DIR}/distantrenderer.cpp
    ${SRC_DIR}/previewrenderer.cpp
    ${SRC_DIR}/avadapter.cpp
    ${SRC_DIR}/contactadapter.cpp
    ${SRC_DIR}/pluginadapter.cpp
    ${SRC_DIR}/settingsadapter.cpp
    ${SRC_DIR}/deviceitemlistmodel.cpp
    ${SRC_DIR}/pluginitemlistmodel.cpp
    ${SRC_DIR}/pluginhandleritemlistmodel.cpp
    ${SRC_DIR}/preferenceitemlistmodel.cpp
    ${SRC_DIR}/mediacodeclistmodel.cpp
    ${SRC_DIR}/accountstomigratelistmodel.cpp
    ${SRC_DIR}/audiodevicemodel.cpp
    ${SRC_DIR}/videoinputdevicemodel.cpp
    ${SRC_DIR}/pluginlistpreferencemodel.cpp
    ${SRC_DIR}/videoformatfpsmodel.cpp
    ${SRC_DIR}/videoformatresolutionmodel.cpp
    ${SRC_DIR}/audiomanagerlistmodel.cpp
    ${SRC_DIR}/qmlregister.cpp
    ${SRC_DIR}/utilsadapter.cpp
    ${SRC_DIR}/moderatorlistmodel.cpp
    ${SRC_DIR}/screensaver.cpp
    ${SRC_DIR}/systemtray.cpp
    ${SRC_DIR}/appsettingsmanager.cpp
    ${SRC_DIR}/lrcinstance.cpp
    ${SRC_DIR}/selectablelistproxymodel.cpp
    ${SRC_DIR}/conversationlistmodelbase.cpp
    ${SRC_DIR}/conversationlistmodel.cpp
    ${SRC_DIR}/searchresultslistmodel.cpp
    ${SRC_DIR}/calloverlaymodel.cpp
    ${SRC_DIR}/filestosendlistmodel.cpp
    ${SRC_DIR}/avatarregistry.cpp)

set(COMMON_HEADERS
    ${SRC_DIR}/avatarimageprovider.h
    ${SRC_DIR}/networkmanager.h
    ${SRC_DIR}/smartlistmodel.h
    ${SRC_DIR}/updatemanager.h
    ${SRC_DIR}/utils.h
    ${SRC_DIR}/bannedlistmodel.h
    ${SRC_DIR}/version.h
    ${SRC_DIR}/accountlistmodel.h
    ${SRC_DIR}/runguard.h
    ${SRC_DIR}/webchathelpers.h
    ${SRC_DIR}/rendermanager.h
    ${SRC_DIR}/connectivitymonitor.h
    ${SRC_DIR}/jamiavatartheme.h
    ${SRC_DIR}/mainapplication.h
    ${SRC_DIR}/qrimageprovider.h
    ${SRC_DIR}/messagesadapter.h
    ${SRC_DIR}/accountadapter.h
    ${SRC_DIR}/tintedbuttonimageprovider.h
    ${SRC_DIR}/calladapter.h
    ${SRC_DIR}/conversationsadapter.h
    ${SRC_DIR}/distantrenderer.h
    ${SRC_DIR}/previewrenderer.h
    ${SRC_DIR}/qmladapterbase.h
    ${SRC_DIR}/avadapter.h
    ${SRC_DIR}/contactadapter.h
    ${SRC_DIR}/pluginadapter.h
    ${SRC_DIR}/settingsadapter.h
    ${SRC_DIR}/deviceitemlistmodel.h
    ${SRC_DIR}/pluginitemlistmodel.h
    ${SRC_DIR}/pluginhandleritemlistmodel.h
    ${SRC_DIR}/preferenceitemlistmodel.h
    ${SRC_DIR}/mediacodeclistmodel.h
    ${SRC_DIR}/accountstomigratelistmodel.h
    ${SRC_DIR}/audiodevicemodel.h
    ${SRC_DIR}/videoinputdevicemodel.h
    ${SRC_DIR}/pluginlistpreferencemodel.h
    ${SRC_DIR}/videoformatfpsmodel.h
    ${SRC_DIR}/videoformatresolutionmodel.h
    ${SRC_DIR}/audiomanagerlistmodel.h
    ${SRC_DIR}/qmlregister.h
    ${SRC_DIR}/abstractlistmodelbase.h
    ${SRC_DIR}/quickimageproviderbase.h
    ${SRC_DIR}/qtutils.h
    ${SRC_DIR}/utilsadapter.h
    ${SRC_DIR}/moderatorlistmodel.h
    ${SRC_DIR}/screensaver.h
    ${SRC_DIR}/systemtray.h
    ${SRC_DIR}/appsettingsmanager.h
    ${SRC_DIR}/lrcinstance.h
    ${SRC_DIR}/selectablelistproxymodel.h
    ${SRC_DIR}/conversationlistmodelbase.h
    ${SRC_DIR}/conversationlistmodel.h
    ${SRC_DIR}/searchresultslistmodel.h
    ${SRC_DIR}/calloverlaymodel.h
    ${SRC_DIR}/filestosendlistmodel.h
    ${SRC_DIR}/avatarregistry.h)

set(QML_LIBS
    Qt5::Quick
    Qt5::QuickWidgets
    Qt5::Network
    Qt5::Svg
    Qt5::Sql
    Qt5::Concurrent
    Qt5::QuickControls2
    Qt5::WebEngine
    Qt5::Core)

set(QML_LIBS_LIST
    Core
    Concurrent
    Quick
    QuickWidgets
    Network
    Svg
    Sql
    QuickControls2
    WebEngine)

set(WINDOWS_SYS_LIBS Shell32.lib
                     Ole32.lib
                     Advapi32.lib
                     Shlwapi.lib
                     User32.lib
                     Gdi32.lib
                     Crypt32.lib
                     Strmiids.lib)

if(MSVC)
    # preprocessor defines
    add_definitions(-DUNICODE -DQT_NO_DEBUG -DNDEBUG)

    # dependencies
    set(LRC ${PROJECT_SOURCE_DIR}/../lrc)
    set(DRING ${PROJECT_SOURCE_DIR}/../daemon)
    set(QRENCODE ${PROJECT_SOURCE_DIR}/qrencode-win32/qrencode-win32)

    # compiler options
    add_compile_options(/wd4068 /wd4099 /wd4189 /wd4267 /wd4577 /wd4467 /wd4715 /wd4828)
    add_compile_options(/MP /GS /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Zc:inline /fp:precise /errorReport:prompt)
    add_compile_options(/Gd /Oi /MD /std:c++17 /FC /EHsc /nologo /sdl)

    # linker options
    add_link_options("/IGNORE:4006,4049,4078,4098" "/FORCE:MULTIPLE" "/INCREMENTAL:NO" "/DEBUG" "/LTCG" "/NODEFAULTLIB:LIBCMT")

    # client deps
    set(QRENCODE_LIB ${QRENCODE}/vc8/qrcodelib/x64/Release-Lib/qrcodelib.lib)

    # lrc
    set(LRC_SRC_PATH ${LRC}/src)
    set(RINGCLIENT_STATIC_LIB ${LRC}/build/release/ringclient_static.lib)
    set(QTWRAPPER_LIB ${LRC}/build/src/qtwrapper/Release/qtwrapper.lib)

    # daemon
    set(DRING_SRC_PATH ${DRING}/contrib/msvc/include)
    set(DRING_LIB ${DRING}/build/x64/ReleaseLib_win32/bin/jami.lib)
    set(GNUTLS_LIB ${DRING}/contrib/msvc/lib/x64/libgnutls.lib)

    # ReleaseCompile config
    if(ReleaseCompile)
        message("ReleaseCompile config enabled")
        add_definitions(-DCOMPILE_ONLY)
    else()
        # Beta config
        if(BETA)
            message("Beta config enabled")
            add_definitions(-DBETA)
            set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Beta)
        else()
            set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Release)
        endif()
    endif()

    include_directories(${DRING_SRC_PATH}
                        ${LRC_SRC_PATH}
                        ${QRENCODE})
else()
    list(APPEND COMMON_SOURCES
                ${SRC_DIR}/xrectsel.c
                ${SRC_DIR}/dbuserrorhandler.cpp)
    list(APPEND COMMON_HEADERS
                ${SRC_DIR}/dbuserrorhandler.h
                ${SRC_DIR}/xrectsel.h)
    list(APPEND QML_LIBS Qt5::DBus)
    list(APPEND QML_LIBS_LIST DBus)

    find_package(PkgConfig REQUIRED)

    pkg_check_modules(LIBNM libnm)
    if(LIBNM_FOUND)
        add_definitions(-DUSE_LIBNM)
    endif()

    pkg_check_modules(LIBNOTIFY libnotify>=0.7.6)
    if(LIBNOTIFY_FOUND)
        add_definitions(-DUSE_LIBNOTIFY)
        add_definitions(${LIBNOTIFY_CFLAGS})
        pkg_check_modules(LIBGDKPIXBUF gdk-pixbuf-2.0>=2.40.0)
        add_definitions(${LIBGDKPIXBUF_CFLAGS})
    endif()

    if(NOT DEFINED LRC)
        if(EXISTS ${PROJECT_SOURCE_DIR}/../install/lrc)
            set(LRC ${PROJECT_SOURCE_DIR}/../install/lrc)
        endif()
    endif()

    # If LRC is not globally installed, it's path should be specified
    # by setting variable LRC. If library is not inside LRC + suffixes
    # lib, build or build-local, it's path should be set with LRCLIB.
    if(DEFINED LRC)
        if(EXISTS ${LRC}/include/libringclient)
            set(LRC_SRC_PATH ${LRC}/include/libringclient)
        else()
            set(LRC_SRC_PATH ${LRC}/src)
        endif()
        if(NOT DEFINED LRCLIB)
            set(LRCLIB ${LRC})
        endif()
        find_library(ringclient ringclient
            PATHS ${LRCLIB}
            PATH_SUFFIXES lib build build-local NO_DEFAULT_PATH)
        message("Will expect lrc library in ${LRCLIB} (including \
    subdirs /lib, /build and /build-local)")
        set(LRC_LIB_NAME ${ringclient})
    else()
        find_package(LibRingClient REQUIRED)
        if (LibRingClient_FOUND)
            set(LRC_SRC_PATH ${LIB_RING_CLIENT_INCLUDE_DIR})
            set(LRC_LIB_NAME ${LIB_RING_CLIENT_LIBRARY})
        else()
            message("lrc not found!")
        endif()
    endif()

    message("Will expect lrc headers in ${LRC_SRC_PATH}")

    include_directories(${LRC_SRC_PATH}
                        ${LIBNM_INCLUDE_DIRS}
                        ${LIBNOTIFY_INCLUDE_DIRS}
                        ${LIBGDKPIXBUF_INCLUDE_DIRS})

    set(JAMI_DATA_PREFIX "${CMAKE_INSTALL_PREFIX}/share")

    find_library(ringclient ringclient ${LRCLIBDIR} NO_DEFAULT_PATH)
    find_library(qrencode qrencode)
    find_library(X11 X11)
endif()

# Qt find package
if(QT5_VER AND QT5_PATH)
    string(REPLACE "." ";" VERSION_LIST ${QT5_VER})
    list(GET VERSION_LIST 0 QT5_VER_MAJOR)
    list(GET VERSION_LIST 1 QT5_VER_MINOR)
    list(GET VERSION_LIST 2 QT5_VER_PATCH)

    if((${QT5_VER_MAJOR} GREATER_EQUAL 5) AND (${QT5_VER_MINOR} GREATER_EQUAL 14))
        message(STATUS "Using custom Qt version")
        find_package(Qt5 ${QT5_VER} REQUIRED COMPONENTS ${QML_LIBS_LIST}
                     PATHS ${QT5_PATH} NO_DEFAULT_PATH)
        find_package(Qt5LinguistTools ${QT5_VER} PATHS ${QT5_PATH} NO_DEFAULT_PATH)
    endif()
else()
    find_package(Qt5 REQUIRED COMPONENTS ${QML_LIBS_LIST})
    find_package(Qt5LinguistTools)
endif()

# common include
include_directories(${PROJECT_SOURCE_DIR}
                    ${SRC_DIR})

# common executable sources
add_executable(${PROJECT_NAME}
               ${SRC_DIR}/main.cpp
               ${COMMON_HEADERS}
               ${COMMON_SOURCES}
               ${QML_RESOURCES}
               ${QML_RESOURCES_QML}
               ${LRC_SRC_PATH}/webresource.qrc)

if(MSVC)
    # Makes it a GUI executable instead of a console application
    set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)

    target_link_libraries(${PROJECT_NAME}
                          ${QML_LIBS}
                          ${QRENCODE_LIB}
                          ${WINDOWS_SYS_LIBS})

    # specify output executable files
    set_target_properties(${PROJECT_NAME}
        PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY_RELEASE "${JAMI_OUTPUT_DIRECTORY_RELEASE}"
    )

    if(NOT DEFINED ReleaseCompile)
        # executable icon
        target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/ico.rc)

        target_link_libraries(${PROJECT_NAME}
                              ${RINGCLIENT_STATIC_LIB}
                              ${QTWRAPPER_LIB}
                              ${DRING_LIB}
                              ${GNUTLS_LIB})

        # translations
        if(Qt5LinguistTools_FOUND)
            message("Releasing and copying translation files")
            file(MAKE_DIRECTORY "${JAMI_OUTPUT_DIRECTORY_RELEASE}/share/ring/translations/")
            file(MAKE_DIRECTORY "${JAMI_OUTPUT_DIRECTORY_RELEASE}/share/libringclient/translations/")
            file(GLOB TS_CLIENT_FILES ${PROJECT_SOURCE_DIR}/translations/*.ts)
            file(GLOB TS_LRC_FILES ${LRC}/translations/*.ts)
            set_source_files_properties(${TS_CLIENT_FILES} PROPERTIES OUTPUT_LOCATION
                                        "${JAMI_OUTPUT_DIRECTORY_RELEASE}/share/ring/translations")
            set_source_files_properties(${TS_LRC_FILES} PROPERTIES OUTPUT_LOCATION
                                        "${JAMI_OUTPUT_DIRECTORY_RELEASE}/share/libringclient/translations")
            qt5_add_translation(QM_CLIENT_FILES ${TS_CLIENT_FILES})
            qt5_add_translation(QM_LRC_FILES ${TS_LRC_FILES})
            target_sources(${PROJECT_NAME} PRIVATE ${QM_CLIENT_FILES})
            target_sources(${PROJECT_NAME} PRIVATE ${QM_LRC_FILES})
        endif()

        # POST_BUILD steps

        # check time stamp
        set(TIME_STAMP_FILE ".deploy.stamp")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                           WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
                           COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE}
                                   -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/time_stamp_check.cmake)

        # copy runtime files and run windeployqt on target and deploy Qt libs
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                           WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
                           COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE}
                                   -DCOPY_TO_PATH=$<TARGET_FILE_DIR:${PROJECT_NAME}>
                                   -DDRING_PATH=${DRING}
                                   -DPROJECT_ROOT_DIR=${PROJECT_SOURCE_DIR}
                                   -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows_daemon_deploy.cmake)

        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                           WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
                           COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE}
                                   -DWIN_DEPLOY_QT_PATH=${CMAKE_PREFIX_PATH}/bin
                                   -DQML_SRC_DIR=${SRC_DIR}
                                   -DEXE_NAME=$<TARGET_FILE:${PROJECT_NAME}>
                                   -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows_qt_deploy.cmake)

        # create time stamp
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                           WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
                           COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE}
                                   -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/time_stamp_create.cmake)
    endif()

    # executable name
    set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "Jami")
else()
    target_link_libraries(${PROJECT_NAME}
                          ${QML_LIBS}
                          ${LRC_LIB_NAME}
                          ${qrencode}
                          ${X11}
                          ${LIBNM_LIBRARIES}
                          ${LIBNOTIFY_LIBRARIES}
                          ${LIBGDKPIXBUF_LIBRARIES})

    # Installation rules
    install(TARGETS jami-qt
        RUNTIME DESTINATION bin)

    # install .desktop in XDG desktop dir so that it is recognized by the system
    install(FILES ${PROJECT_SOURCE_DIR}/jami-qt.desktop
        DESTINATION ${JAMI_DATA_PREFIX}/applications)

    # install .desktop in the jami-qt data dir, so that it can be copied to the
    # autostart dir by the client
    install(FILES ${PROJECT_SOURCE_DIR}/jami-qt.desktop
       DESTINATION
          "${JAMI_DATA_PREFIX}/${PROJECT_NAME}"
       PERMISSIONS
          WORLD_READ
          OWNER_WRITE
          OWNER_READ
          GROUP_READ
    )

    # adjust JAMI_DATA_PREFIX for snap package
    #   (this must come after all 'install' commands that refer to
    #    JAMI_DATA_PREFIX; the following value is not meant to be used for
    #    any install destinations)
    if(DEFINED ENV{SNAPCRAFT_PROJECT_NAME})
        set(JAMI_DATA_PREFIX "/snap/$ENV{SNAPCRAFT_PROJECT_NAME}/current/usr/share")
    endif()

    # (this must come after the above adjustment to JAMI_DATA_PREFIX)
    target_compile_definitions(jami-qt PRIVATE JAMI_INSTALL_PREFIX="${JAMI_DATA_PREFIX}")

    # logos
    install(FILES images/jami.svg
        DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)

    install(FILES images/jami-48px.png
        DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps
        RENAME jami.png)

    install(FILES images/jami-32px.xpm
        DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps
        RENAME jami.xpm)

    install(FILES jami-qt.appdata.xml
        DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)

    # install jami launcher that selects between clients
    install(
        FILES
            "${PROJECT_SOURCE_DIR}/src/jami"
        DESTINATION
            ${CMAKE_INSTALL_PREFIX}/bin
        PERMISSIONS
            WORLD_READ
            OWNER_WRITE
            OWNER_READ
            GROUP_READ
            OWNER_EXECUTE
            GROUP_EXECUTE
            WORLD_EXECUTE)

    # add a target to generate API documentation with Doxygen and graphviz-dot
    find_package(Doxygen)
    find_program(dot "dot")
    if(Doxygen_FOUND AND dot)
        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile @ONLY)
        add_custom_target(doc
            COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc
            COMMENT "Generating API documentation with Doxygen" VERBATIM)

        # create doc/README.md symlink to README since Doxygen doesn't understand file with no extension
        add_custom_command(
            TARGET doc
            PRE_BUILD
            COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/README ${CMAKE_CURRENT_SOURCE_DIR}/doc/README.md)
    endif()

    # translations
    if(Qt5LinguistTools_FOUND)
        message("Releasing and copying translation files")
        file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/share/ring/translations/")
        file(GLOB TS_FILES ${PROJECT_SOURCE_DIR}/translations/*.ts)
        set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "share/ring/translations")
        qt5_add_translation(QM_FILES ${TS_FILES})
        add_custom_target(translations ALL DEPENDS ${QM_FILES})
        install(DIRECTORY "${CMAKE_BINARY_DIR}/share/ring/translations/"
                DESTINATION ${CMAKE_INSTALL_PREFIX}/share/ring/translations)
    endif()

    # uninstall
    configure_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
        "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
        IMMEDIATE @ONLY)

    add_custom_target(uninstall
        COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()

# test
if(ENABLE_TESTS)
    message("Add Jami tests")
    add_subdirectory(tests)
endif()