Commit 196f9f15 authored by Ronan Abhamon's avatar Ronan Abhamon

Merge commit '6641414d'

parents ea87f661 6641414d
# Changelog
## 4.1.0 - 2017-07-19
### Features
- Add tooltips on `recording` and `screenshot` buttons in `Calls Window`.
- Show notifications on `recording` and `screenshot`.
- Show `XXX is typing...` in `Timeline` and `Chat View`.
- Handle correctly `SIGINT`.
- Handle clicks on SIP URI in chat messages.
- Show video framerate in `Calls Stats`.
- Add a `Logs` menu entry in `Settings Window`, it provides send, remove, activate buttons...
- Supports EXIF orientation for file transfer images preview.
- Echo canceller supports 48kHz.
- Better GUI when a proxy config is modified in `Settings Window`.
### Fixes
- Handle correctly ringer device changes in `Settings Window`.
- In `Video Settings`, display FPS field only in `custom preset` mode.
- Use now the directory containing user documents files for saved video/audio/screenshots.
- Update `Chat View` correctly if it is used in many windows.
- Update correctly selected language when app is restarted.
- Avoid a deadlock on Mac OS when a call ends in fullscreen mode.
- Application can be started from one binary only.
- Single instance is now supported with flatpak. (It uses D-Bus.)
...@@ -21,10 +21,16 @@ ...@@ -21,10 +21,16 @@
################################################################################ ################################################################################
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
project(linphoneqt VERSION 4.0) project(linphoneqt VERSION 4.1.0)
set(APP_LIBRARY app-library)
set(EXECUTABLE_NAME linphone) set(EXECUTABLE_NAME linphone)
set(TESTER_EXECUTABLE_NAME "${EXECUTABLE_NAME}-tester")
set(TARGET_NAME linphone-qt) set(TARGET_NAME linphone-qt)
set(TESTER_TARGET_NAME "${TARGET_NAME}-tester")
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(ASSETS_DIR assets) set(ASSETS_DIR assets)
...@@ -98,6 +104,7 @@ endif () ...@@ -98,6 +104,7 @@ endif ()
set(SOURCES set(SOURCES
src/app/App.cpp src/app/App.cpp
src/app/AppController.cpp
src/app/cli/Cli.cpp src/app/cli/Cli.cpp
src/app/logger/Logger.cpp src/app/logger/Logger.cpp
src/app/paths/Paths.cpp src/app/paths/Paths.cpp
...@@ -144,7 +151,6 @@ set(SOURCES ...@@ -144,7 +151,6 @@ set(SOURCES
src/components/telephone-numbers/TelephoneNumbersModel.cpp src/components/telephone-numbers/TelephoneNumbersModel.cpp
src/components/timeline/TimelineModel.cpp src/components/timeline/TimelineModel.cpp
src/components/url-handlers/UrlHandlers.cpp src/components/url-handlers/UrlHandlers.cpp
src/main.cpp
src/utils/LinphoneUtils.cpp src/utils/LinphoneUtils.cpp
src/utils/Utils.cpp src/utils/Utils.cpp
src/utils/QExifImageHeader.cpp src/utils/QExifImageHeader.cpp
...@@ -152,6 +158,7 @@ set(SOURCES ...@@ -152,6 +158,7 @@ set(SOURCES
set(HEADERS set(HEADERS
src/app/App.hpp src/app/App.hpp
src/app/AppController.hpp
src/app/cli/Cli.hpp src/app/cli/Cli.hpp
src/app/logger/Logger.hpp src/app/logger/Logger.hpp
src/app/paths/Paths.hpp src/app/paths/Paths.hpp
...@@ -205,6 +212,20 @@ set(HEADERS ...@@ -205,6 +212,20 @@ set(HEADERS
src/utils/QExifImageHeader.h src/utils/QExifImageHeader.h
) )
set(TESTS
src/tests/assistant-view/AssistantViewTest.cpp
src/tests/assistant-view/AssistantViewTest.hpp
src/tests/main-view/MainViewTest.cpp
src/tests/main-view/MainViewTest.hpp
src/tests/self-test/SelfTest.cpp
src/tests/self-test/SelfTest.hpp
src/tests/TestUtils.cpp
src/tests/TestUtils.hpp
)
set(MAIN_FILE src/app/main.cpp)
set(TESTER_MAIN_FILE src/tests/main.cpp)
if(APPLE) if(APPLE)
list(APPEND SOURCES src/components/core/MessagesCountNotifierMacOS.m) list(APPEND SOURCES src/components/core/MessagesCountNotifierMacOS.m)
endif() endif()
...@@ -288,6 +309,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BIN ...@@ -288,6 +309,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BIN
find_package(Qt5 COMPONENTS ${QT5_PACKAGES} REQUIRED) find_package(Qt5 COMPONENTS ${QT5_PACKAGES} REQUIRED)
find_package(Qt5 COMPONENTS ${QT5_PACKAGES_OPTIONAL} QUIET) find_package(Qt5 COMPONENTS ${QT5_PACKAGES_OPTIONAL} QUIET)
find_package(Qt5 COMPONENTS Test REQUIRED)
if (CMAKE_INSTALL_RPATH) if (CMAKE_INSTALL_RPATH)
get_target_property(LUPDATE_PATH Qt5::lupdate LOCATION) get_target_property(LUPDATE_PATH Qt5::lupdate LOCATION)
...@@ -304,46 +326,44 @@ list(APPEND QRC_RESOURCES "${CMAKE_CURRENT_BINARY_DIR}/${LANGUAGES_DIRECTORY}/${ ...@@ -304,46 +326,44 @@ list(APPEND QRC_RESOURCES "${CMAKE_CURRENT_BINARY_DIR}/${LANGUAGES_DIRECTORY}/${
qt5_add_resources(RESOURCES ${QRC_RESOURCES}) qt5_add_resources(RESOURCES ${QRC_RESOURCES})
# Build. # Build.
# Note: `update_translations` is provided by `languages/CMakeLists.txt`. add_library(${APP_LIBRARY} OBJECT ${SOURCES} ${HEADERS} ${RESOURCES} ${QML_SOURCES})
set_property(TARGET ${APP_LIBRARY} PROPERTY POSITION_INDEPENDENT_CODE ON)
bc_git_version(${TARGET_NAME} ${PROJECT_VERSION})
add_dependencies(${APP_LIBRARY} ${TARGET_NAME}-git-version)
add_dependencies(${APP_LIBRARY} update_translations)
if (WIN32) if (WIN32)
add_executable(${TARGET_NAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} assets/linphone.rc) add_executable(${TARGET_NAME} WIN32 $<TARGET_OBJECTS:${APP_LIBRARY}> assets/linphone.rc ${MAIN_FILE})
add_executable(${TESTER_TARGET_NAME} WIN32 $<TARGET_OBJECTS:${APP_LIBRARY}> assets/linphone.rc ${TESTER_MAIN_FILE} ${TESTS})
else () else ()
add_executable(${TARGET_NAME} ${SOURCES} ${HEADERS} ${RESOURCES} ${QML_SOURCES}) add_executable(${TARGET_NAME} $<TARGET_OBJECTS:${APP_LIBRARY}> ${MAIN_FILE})
add_executable(${TESTER_TARGET_NAME} $<TARGET_OBJECTS:${APP_LIBRARY}> ${TESTER_MAIN_FILE} ${TESTS})
endif () endif ()
bc_git_version(${TARGET_NAME} ${PROJECT_VERSION})
add_dependencies(${TARGET_NAME} ${TARGET_NAME}-git-version)
add_dependencies(${TARGET_NAME} update_translations)
if (NOT WIN32) if (NOT WIN32)
add_dependencies(update_translations check_qml) add_dependencies(update_translations check_qml)
endif () endif ()
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${EXECUTABLE_NAME}") set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${EXECUTABLE_NAME}")
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE "${LINPHONECXX_INCLUDE_DIRS}" "${LINPHONE_INCLUDE_DIRS}" "${BELCARD_INCLUDE_DIRS}" "${BCTOOLBOX_INCLUDE_DIRS}") set_target_properties(${TESTER_TARGET_NAME} PROPERTIES OUTPUT_NAME "${TESTER_EXECUTABLE_NAME}")
# To start better integration into IDE. set(INCLUDED_DIRECTORIES "${LINPHONECXX_INCLUDE_DIRS}" "${LINPHONE_INCLUDE_DIRS}" "${BELCARD_INCLUDE_DIRS}" "${BCTOOLBOX_INCLUDE_DIRS}")
source_group( set(LIBRARIES ${BCTOOLBOX_CORE_LIBRARIES} ${BELCARD_LIBRARIES} ${LINPHONE_LIBRARIES} ${LINPHONECXX_LIBRARIES})
"Qml" REGULAR_EXPRESSION ".+\.qml$"
)
source_group(
"Js" REGULAR_EXPRESSION ".+\.js)$"
)
source_group(
"Svg" REGULAR_EXPRESSION ".+\.svg$"
)
foreach (package ${QT5_PACKAGES}) foreach (package ${QT5_PACKAGES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE "${Qt5${package}_INCLUDE_DIRS}") list(APPEND INCLUDED_DIRECTORIES "${Qt5${package}_INCLUDE_DIRS}")
# `qt5_create_translation` is provided from `LinguistTools` package. # `qt5_create_translation` is provided from `LinguistTools` package.
# But the `Qt5::LinguistTools` lib does not exist. Remove it. # But the `Qt5::LinguistTools` lib does not exist. Remove it.
if (NOT (${package} STREQUAL LinguistTools)) if (NOT (${package} STREQUAL LinguistTools))
target_link_libraries(${TARGET_NAME} ${Qt5${package}_LIBRARIES}) list(APPEND LIBRARIES ${Qt5${package}_LIBRARIES})
endif () endif ()
endforeach () endforeach ()
foreach (package ${QT5_PACKAGES_OPTIONAL}) foreach (package ${QT5_PACKAGES_OPTIONAL})
if ("${Qt5${package}_FOUND}") if ("${Qt5${package}_FOUND}")
message("Optional package ${package} found.") message("Optional package ${package} found.")
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE "${Qt5${package}_INCLUDE_DIRS}") list(APPEND INCLUDED_DIRECTORIES "${Qt5${package}_INCLUDE_DIRS}")
target_link_libraries(${TARGET_NAME} ${Qt5${package}_LIBRARIES}) list(APPEND LIBRARIES ${Qt5${package}_LIBRARIES})
string(TOUPPER "${package}" INCLUDE_NAME) string(TOUPPER "${package}" INCLUDE_NAME)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${INCLUDE_NAME}_ENABLED") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${INCLUDE_NAME}_ENABLED")
...@@ -352,17 +372,25 @@ foreach (package ${QT5_PACKAGES_OPTIONAL}) ...@@ -352,17 +372,25 @@ foreach (package ${QT5_PACKAGES_OPTIONAL})
endif () endif ()
endforeach () endforeach ()
target_link_libraries(${TARGET_NAME} ${BCTOOLBOX_CORE_LIBRARIES} ${BELCARD_LIBRARIES} ${LINPHONE_LIBRARIES} ${LINPHONECXX_LIBRARIES}) if (APPLE)
if(APPLE) list(APPEND LIBRARIES "-framework Cocoa")
target_link_libraries(${TARGET_NAME} "-framework Cocoa") endif ()
endif()
install(TARGETS ${TARGET_NAME} target_include_directories(${APP_LIBRARY} SYSTEM PRIVATE ${INCLUDED_DIRECTORIES})
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDED_DIRECTORIES})
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} target_include_directories(${TESTER_TARGET_NAME} SYSTEM PRIVATE ${INCLUDED_DIRECTORIES})
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE target_link_libraries(${TARGET_NAME} ${LIBRARIES})
) target_link_libraries(${TESTER_TARGET_NAME} ${LIBRARIES} Qt5::Test)
foreach (target ${TARGET_NAME} ${TESTER_TARGET_NAME})
install(TARGETS ${target}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endforeach ()
install(FILES "assets/linphone.desktop" install(FILES "assets/linphone.desktop"
DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" DESTINATION "${CMAKE_INSTALL_DATADIR}/applications"
...@@ -393,7 +421,6 @@ install(FILES "${ASSETS_ASSISTANT_DIR}/use-linphone-sip-account.rc" ...@@ -393,7 +421,6 @@ install(FILES "${ASSETS_ASSISTANT_DIR}/use-linphone-sip-account.rc"
DESTINATION "${ASSISTANT_INSTALL_DATADIR}" DESTINATION "${ASSISTANT_INSTALL_DATADIR}"
) )
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# CPack settings. # CPack settings.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
...@@ -401,12 +428,26 @@ install(FILES "${ASSETS_ASSISTANT_DIR}/use-linphone-sip-account.rc" ...@@ -401,12 +428,26 @@ install(FILES "${ASSETS_ASSISTANT_DIR}/use-linphone-sip-account.rc"
set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
set(CPACK_SOURCE_IGNORE_FILES set(CPACK_SOURCE_IGNORE_FILES
"^${CMAKE_BINARY_DIR}" "^${CMAKE_BINARY_DIR}"
"/\\\\..+" "/\\\\..+"
"OUTPUT" "OUTPUT"
"WORK" "WORK"
"cmake_builder" "cmake_builder"
"submodules" "submodules"
) )
include(CPack) include(CPack)
# ------------------------------------------------------------------------------
# To start better integration into IDE.
# ------------------------------------------------------------------------------
source_group(
"Qml" REGULAR_EXPRESSION ".+\.qml$"
)
source_group(
"Js" REGULAR_EXPRESSION ".+\.js)$"
)
source_group(
"Svg" REGULAR_EXPRESSION ".+\.svg$"
)
...@@ -40,10 +40,6 @@ ...@@ -40,10 +40,6 @@
</context> </context>
<context> <context>
<name>App</name> <name>App</name>
<message>
<source>selfTestResult</source>
<translation>Linphone seems to be running correctly.</translation>
</message>
<message> <message>
<source>commandLineOptionVerbose</source> <source>commandLineOptionVerbose</source>
<translation>log to stdout some debug information while running</translation> <translation>log to stdout some debug information while running</translation>
...@@ -52,10 +48,6 @@ ...@@ -52,10 +48,6 @@
<source>commandLineOptionConfig</source> <source>commandLineOptionConfig</source>
<translation>specify the linphone configuration file to be used</translation> <translation>specify the linphone configuration file to be used</translation>
</message> </message>
<message>
<source>commandLineOptionSelfTest</source>
<translation>run self test and exit 0 if it succeeded</translation>
</message>
<message> <message>
<source>applicationDescription</source> <source>applicationDescription</source>
<translation>A free (libre) SIP video-phone.</translation> <translation>A free (libre) SIP video-phone.</translation>
...@@ -1327,6 +1319,18 @@ your friend&apos;s SIP address or username.</translation> ...@@ -1327,6 +1319,18 @@ your friend&apos;s SIP address or username.</translation>
<source>confirm</source> <source>confirm</source>
<translation>CONFIRM</translation> <translation>CONFIRM</translation>
</message> </message>
<message>
<source>invalidSipAddress</source>
<translation>Invalid sip address.</translation>
</message>
<message>
<source>invalidServerAddress</source>
<translation>Invalid server address.</translation>
</message>
<message>
<source>invalidRoute</source>
<translation>Invalid route.</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsUi</name> <name>SettingsUi</name>
......
...@@ -40,10 +40,6 @@ ...@@ -40,10 +40,6 @@
</context> </context>
<context> <context>
<name>App</name> <name>App</name>
<message>
<source>selfTestResult</source>
<translation>Linphone semble fonctionner normalement.</translation>
</message>
<message> <message>
<source>commandLineOptionVerbose</source> <source>commandLineOptionVerbose</source>
<translation>afficher sur stdout les informations de debug</translation> <translation>afficher sur stdout les informations de debug</translation>
...@@ -52,10 +48,6 @@ ...@@ -52,10 +48,6 @@
<source>commandLineOptionConfig</source> <source>commandLineOptionConfig</source>
<translation>spécifier un fichier de configuration à utiliser</translation> <translation>spécifier un fichier de configuration à utiliser</translation>
</message> </message>
<message>
<source>commandLineOptionSelfTest</source>
<translation>éxécuter un test automatique et retourner 0 en cas de succès</translation>
</message>
<message> <message>
<source>applicationDescription</source> <source>applicationDescription</source>
<translation>Un logiciel libre de voix sur IP SIP.</translation> <translation>Un logiciel libre de voix sur IP SIP.</translation>
...@@ -1325,6 +1317,18 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt; ...@@ -1325,6 +1317,18 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<source>confirm</source> <source>confirm</source>
<translation>CONFIRMER</translation> <translation>CONFIRMER</translation>
</message> </message>
<message>
<source>invalidSipAddress</source>
<translation>Adresse sip invalide.</translation>
</message>
<message>
<source>invalidServerAddress</source>
<translation>Adresse du serveur invalide.</translation>
</message>
<message>
<source>invalidRoute</source>
<translation>Route invalide.</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsUi</name> <name>SettingsUi</name>
......
...@@ -55,8 +55,6 @@ ...@@ -55,8 +55,6 @@
#define QML_VIEW_SPLASH_SCREEN "qrc:/ui/views/App/SplashScreen/SplashScreen.qml" #define QML_VIEW_SPLASH_SCREEN "qrc:/ui/views/App/SplashScreen/SplashScreen.qml"
#define SELF_TEST_DELAY 300000
#define VERSION_UPDATE_CHECK_INTERVAL 86400000 // 24 hours in milliseconds. #define VERSION_UPDATE_CHECK_INTERVAL 86400000 // 24 hours in milliseconds.
using namespace std; using namespace std;
...@@ -104,6 +102,8 @@ App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::U ...@@ -104,6 +102,8 @@ App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::U
if (mParser->isSet("version")) if (mParser->isSet("version"))
mParser->showVersion(); mParser->showVersion();
qInfo() << QStringLiteral("Use locale: %1").arg(mLocale);
} }
App::~App () { App::~App () {
...@@ -202,19 +202,12 @@ void App::initContentApp () { ...@@ -202,19 +202,12 @@ void App::initContentApp () {
mNotifier = new Notifier(mEngine); mNotifier = new Notifier(mEngine);
// Load splashscreen. // Load splashscreen.
bool selfTest = mParser->isSet("self-test"); #ifdef Q_OS_MACOS
if (!selfTest) { ::activeSplashScreen(mEngine);
#ifdef Q_OS_MACOS #else
if (!mParser->isSet("iconified"))
::activeSplashScreen(mEngine); ::activeSplashScreen(mEngine);
#else #endif // ifdef Q_OS_MACOS
if (!mParser->isSet("iconified"))
::activeSplashScreen(mEngine);
#endif // ifdef Q_OS_MACOS
} else
// Set a self test limit.
QTimer::singleShot(SELF_TEST_DELAY, this, [] {
qFatal("Self test failed. :(");
});
// Load main view. // Load main view.
qInfo() << QStringLiteral("Loading main view..."); qInfo() << QStringLiteral("Loading main view...");
...@@ -225,7 +218,7 @@ void App::initContentApp () { ...@@ -225,7 +218,7 @@ void App::initContentApp () {
QObject::connect( QObject::connect(
CoreManager::getInstance()->getHandlers().get(), CoreManager::getInstance()->getHandlers().get(),
&CoreHandlers::coreStarted, &CoreHandlers::coreStarted,
this, selfTest ? &App::quit : &App::openAppAfterInit this, &App::openAppAfterInit
); );
} }
...@@ -308,7 +301,6 @@ void App::createParser () { ...@@ -308,7 +301,6 @@ void App::createParser () {
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
{ "iconified", tr("commandLineOptionIconified") }, { "iconified", tr("commandLineOptionIconified") },
#endif // ifndef Q_OS_MACOS #endif // ifndef Q_OS_MACOS
{ "self-test", tr("commandLineOptionSelfTest") },
{ { "V", "verbose" }, tr("commandLineOptionVerbose") } { { "V", "verbose" }, tr("commandLineOptionVerbose") }
// TODO: Enable me in future version! // TODO: Enable me in future version!
// , // ,
...@@ -331,11 +323,6 @@ void App::createParser () { ...@@ -331,11 +323,6 @@ void App::createParser () {
"Linphone", 1, 0, NAME, NAME " is uncreatable." \ "Linphone", 1, 0, NAME, NAME " is uncreatable." \
) )
template<class T>
void registerMetaType (const char *name) {
qRegisterMetaType<T>(name);
}
template<class T> template<class T>
void registerSingletonType (const char *name) { void registerSingletonType (const char *name) {
qmlRegisterSingletonType<T>("Linphone", 1, 0, name, [](QQmlEngine *engine, QJSEngine *) -> QObject *{ qmlRegisterSingletonType<T>("Linphone", 1, 0, name, [](QQmlEngine *engine, QJSEngine *) -> QObject *{
...@@ -367,6 +354,9 @@ void registerToolType (const char *name) { ...@@ -367,6 +354,9 @@ void registerToolType (const char *name) {
void App::registerTypes () { void App::registerTypes () {
qInfo() << QStringLiteral("Registering types..."); qInfo() << QStringLiteral("Registering types...");
qRegisterMetaType<std::shared_ptr<linphone::ProxyConfig> >();
qRegisterMetaType<ChatModel::EntryType>();
registerType<AssistantModel>("AssistantModel"); registerType<AssistantModel>("AssistantModel");
registerType<AuthenticationNotifier>("AuthenticationNotifier"); registerType<AuthenticationNotifier>("AuthenticationNotifier");
registerType<CallsListProxyModel>("CallsListProxyModel"); registerType<CallsListProxyModel>("CallsListProxyModel");
...@@ -387,8 +377,6 @@ void App::registerTypes () { ...@@ -387,8 +377,6 @@ void App::registerTypes () {
registerSingletonType<UrlHandlers>("UrlHandlers"); registerSingletonType<UrlHandlers>("UrlHandlers");
registerSingletonType<VideoCodecsModel>("VideoCodecsModel"); registerSingletonType<VideoCodecsModel>("VideoCodecsModel");
registerMetaType<ChatModel::EntryType>("ChatModel::EntryType");
registerUncreatableType(CallModel, "CallModel"); registerUncreatableType(CallModel, "CallModel");
registerUncreatableType(ChatModel, "ChatModel"); registerUncreatableType(ChatModel, "ChatModel");
registerUncreatableType(ConferenceHelperModel::ConferenceAddModel, "ConferenceAddModel"); registerUncreatableType(ConferenceHelperModel::ConferenceAddModel, "ConferenceAddModel");
...@@ -476,7 +464,6 @@ void App::initLocale (const shared_ptr<linphone::Config> &config) { ...@@ -476,7 +464,6 @@ void App::initLocale (const shared_ptr<linphone::Config> &config) {
if (!locale.isEmpty() && ::installLocale(*this, *mTranslator, QLocale(locale))) { if (!locale.isEmpty() && ::installLocale(*this, *mTranslator, QLocale(locale))) {
mLocale = locale; mLocale = locale;
qInfo() << QStringLiteral("Use preferred locale: %1").arg(locale);
return; return;
} }
...@@ -484,7 +471,6 @@ void App::initLocale (const shared_ptr<linphone::Config> &config) { ...@@ -484,7 +471,6 @@ void App::initLocale (const shared_ptr<linphone::Config> &config) {
QLocale sysLocale = QLocale::system(); QLocale sysLocale = QLocale::system();
if (::installLocale(*this, *mTranslator, sysLocale)) { if (::installLocale(*this, *mTranslator, sysLocale)) {
mLocale = sysLocale.name(); mLocale = sysLocale.name();
qInfo() << QStringLiteral("Use system locale: %1").arg(mLocale);
return; return;
} }
...@@ -492,7 +478,6 @@ void App::initLocale (const shared_ptr<linphone::Config> &config) { ...@@ -492,7 +478,6 @@ void App::initLocale (const shared_ptr<linphone::Config> &config) {
mLocale = DEFAULT_LOCALE; mLocale = DEFAULT_LOCALE;
if (!::installLocale(*this, *mTranslator, QLocale(mLocale))) if (!::installLocale(*this, *mTranslator, QLocale(mLocale)))
qFatal("Unable to install default translator."); qFatal("Unable to install default translator.");
qInfo() << QStringLiteral("Use default locale: %1").arg(mLocale);
} }
QString App::getConfigLocale () const { QString App::getConfigLocale () const {
...@@ -569,12 +554,3 @@ void App::checkForUpdate () { ...@@ -569,12 +554,3 @@ void App::checkForUpdate () {
::Utils::appStringToCoreString(applicationVersion()) ::Utils::appStringToCoreString(applicationVersion())
); );
} }
// -----------------------------------------------------------------------------
void App::quit () {
if (mParser->isSet("self-test"))
cout << tr("selfTestResult").toStdString() << endl;
QApplication::quit();
}
...@@ -71,8 +71,6 @@ public: ...@@ -71,8 +71,6 @@ public:
bool hasFocus () const; bool hasFocus () const;
void quit () override;
static App *getInstance () { static App *getInstance () {
return static_cast<App *>(QApplication::instance()); return static_cast<App *>(QApplication::instance());
} }
......
/* /*
* main.cpp * AppController.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France * Copyright (C) 2017 Belledonne Communications, Grenoble, France
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
* Created on: February 2, 2017 * Created on: July 17, 2017
* Author: Ronan Abhamon * Author: Ronan Abhamon
*/ */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "gitversion.h" #include "gitversion.h"
#include "app/App.hpp" #include "AppController.hpp"
// Must be unique. Used by `SingleApplication` and `Paths`. // Must be unique. Used by `SingleApplication` and `Paths`.
#define APPLICATION_NAME "linphone" #define APPLICATION_NAME "linphone"
...@@ -39,8 +39,9 @@ using namespace std; ...@@ -39,8 +39,9 @@ using namespace std;
// ============================================================================= // =============================================================================
int main (int argc, char *argv[]) { AppController::AppController (int &argc, char *argv[]) {
QT_REQUIRE_VERSION(argc, argv, APPLICATION_MINIMAL_QT_VERSION); QT_REQUIRE_VERSION(argc, argv, APPLICATION_MINIMAL_QT_VERSION);
Q_ASSERT(!mApp);
// Disable QML cache. Avoid malformed cache. // Disable QML cache. Avoid malformed cache.
qputenv("QML_DISABLE_DISK_CACHE", "true"); qputenv("QML_DISABLE_DISK_CACHE", "true");
...@@ -81,12 +82,11 @@ int main (int argc, char *argv[]) { ...@@ -81,12 +82,11 @@ int main (int argc, char *argv[]) {
QCoreApplication::setApplicationName(APPLICATION_NAME); QCoreApplication::setApplicationName(APPLICATION_NAME);
QCoreApplication::setApplicationVersion(APPLICATION_VERSION); QCoreApplication::setApplicationVersion(APPLICATION_VERSION);
App app(argc, argv); mApp = new App(argc, argv);
if (mApp->isSecondary()) {
if (app.isSecondary()) { QString command = mApp->getCommandArgument();
QString command = app.getCommandArgument(); mApp->sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1);
app.sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1); return;
return 0;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -104,18 +104,9 @@ int main (int argc, char *argv[]) { ...@@ -104,18 +104,9 @@ int main (int argc, char *argv[]) {
} }
} }
app.setFont(QFont(DEFAULT_FONT)); mApp->setFont(QFont(DEFAULT_FONT));
}
// ---------------------------------------------------------------------------
// Init and run!
// ---------------------------------------------------------------------------
qInfo() << QStringLiteral("Running app...");
int ret; AppController::~AppController () {
do { delete mApp;
app.initContentApp();
ret = app.exec();
} while (ret == APP_CODE_RESTART);
return ret;
} }
/*
* AppController.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 17, 2017
* Author: Ronan Abhamon
*/
#include "App.hpp"
// =============================================================================
class AppController {
public:
AppController (int &argc, char *argv[]);
~AppController ();
App *getApp () const {
Q_CHECK_PTR(mApp);
return mApp;
}
private:
App *mApp = nullptr;
};
/*
* main.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: February 2, 2017
* Author: Ronan Abhamon
*/
#include "AppController.hpp"
// =============================================================================
int main (int argc, char *argv[]) {
AppController controller(argc, argv);
App *app = controller.getApp();
if (app->isSecondary())
return EXIT_SUCCESS;
qInfo() << QStringLiteral("Running app...");
int ret;
do {
app->initContentApp();
ret = app->exec();
} while (ret == APP_CODE_RESTART);
return ret;
}
...@@ -63,6 +63,8 @@ CoreManager::CoreManager (QObject *parent, const QString &configPath) : ...@@ -63,6 +63,8 @@ CoreManager::CoreManager (QObject *parent, const QString &configPath) :
mInstance->mSettingsModel = new SettingsModel(mInstance); mInstance->mSettingsModel = new SettingsModel(mInstance);
mInstance->mAccountSettingsModel = new AccountSettingsModel(mInstance); mInstance->mAccountSettingsModel = new AccountSettingsModel(mInstance);
mInstance->mStarted = true;
emit mInstance->coreStarted(); emit mInstance->coreStarted();
}); });
......
...@@ -47,6 +47,10 @@ class CoreManager : public QObject { ...@@ -47,6 +47,10 @@ class CoreManager : public QObject {
public: public:
~CoreManager () = default; ~CoreManager () = default;
bool started () const {
return mStarted;
}
std::shared_ptr<linphone::Core> getCore () { std::shared_ptr<linphone::Core> getCore () {
Q_CHECK_PTR(mCore); Q_CHECK_PTR(mCore);
return mCore; return mCore;
...@@ -151,6 +155,8 @@ private: ...@@ -151,6 +155,8 @@ private:
std::shared_ptr<linphone::Core> mCore; std::shared_ptr<linphone::Core> mCore;
std::shared_ptr<CoreHandlers> mHandlers; std::shared_ptr<CoreHandlers> mHandlers;
bool mStarted = false;
CallsListModel *mCallsListModel = nullptr; CallsListModel *mCallsListModel = nullptr;
ContactsListModel *mContactsListModel = nullptr; ContactsListModel *mContactsListModel = nullptr;
SipAddressesModel *mSipAddressesModel = nullptr; SipAddressesModel *mSipAddressesModel = nullptr;
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#define NOTIFICATION_PROPERTY_X "popupX" #define NOTIFICATION_PROPERTY_X "popupX"
#define NOTIFICATION_PROPERTY_Y "popupY" #define NOTIFICATION_PROPERTY_Y "popupY"
#define NOTIFICATION_PROPERTY_WINDOW "__internalWindow" #define NOTIFICATION_PROPERTY_WINDOW "internalWindow"
#define NOTIFICATION_PROPERTY_TIMER "__timer" #define NOTIFICATION_PROPERTY_TIMER "__timer"
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
* Author: Ronan Abhamon * Author: Ronan Abhamon
*/ */
#include "../../app/paths/Paths.hpp"
#include "../../utils/Utils.hpp" #include "../../utils/Utils.hpp"
#include "../core/CoreManager.hpp" #include "../core/CoreManager.hpp"
...@@ -136,7 +137,11 @@ bool AccountSettingsModel::addOrUpdateProxyConfig ( ...@@ -136,7 +137,11 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
return false; return false;
} }
proxyConfig->setIdentityAddress(address); if (proxyConfig->setIdentityAddress(address)) {
qWarning() << QStringLiteral("Unable to set identity address: `%1`.")
.arg(::Utils::coreStringToAppString(address->asStringUriOnly()));
return false;
}
} }
// Server address. // Server address.
...@@ -164,7 +169,13 @@ bool AccountSettingsModel::addOrUpdateProxyConfig ( ...@@ -164,7 +169,13 @@ bool AccountSettingsModel::addOrUpdateProxyConfig (
} }
shared_ptr<linphone::ProxyConfig> AccountSettingsModel::createProxyConfig () { shared_ptr<linphone::ProxyConfig> AccountSettingsModel::createProxyConfig () {
return CoreManager::getInstance()->getCore()->createProxyConfig(); shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->getConfig()->loadFromXmlFile(
Paths::getAssistantConfigDirPath() + "create-linphone-sip-account.rc"
);
return core->createProxyConfig();
} }
void AccountSettingsModel::addAuthInfo ( void AccountSettingsModel::addAuthInfo (
......
...@@ -175,12 +175,19 @@ QString SipAddressesModel::interpretUrl (const QUrl &sipAddress) { ...@@ -175,12 +175,19 @@ QString SipAddressesModel::interpretUrl (const QUrl &sipAddress) {
return sipAddress.toString(); return sipAddress.toString();
} }
bool SipAddressesModel::sipAddressIsValid (const QString &sipAddress) { bool SipAddressesModel::addressIsValid (const QString &address) {
return !!linphone::Factory::get()->createAddress( return !!linphone::Factory::get()->createAddress(
::Utils::appStringToCoreString(sipAddress) ::Utils::appStringToCoreString(address)
); );
} }
bool SipAddressesModel::sipAddressIsValid (const QString &sipAddress) {
shared_ptr<linphone::Address> address = linphone::Factory::get()->createAddress(
::Utils::appStringToCoreString(sipAddress)
);
return address && !address->getUsername().empty();
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool SipAddressesModel::removeRow (int row, const QModelIndex &parent) { bool SipAddressesModel::removeRow (int row, const QModelIndex &parent) {
......
...@@ -59,6 +59,7 @@ public: ...@@ -59,6 +59,7 @@ public:
Q_INVOKABLE static QString interpretUrl (const QString &sipAddress); Q_INVOKABLE static QString interpretUrl (const QString &sipAddress);
Q_INVOKABLE static QString interpretUrl (const QUrl &sipAddress); Q_INVOKABLE static QString interpretUrl (const QUrl &sipAddress);
Q_INVOKABLE static bool addressIsValid (const QString &address);
Q_INVOKABLE static bool sipAddressIsValid (const QString &sipAddress); Q_INVOKABLE static bool sipAddressIsValid (const QString &sipAddress);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
......
/*
* TestUtils.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 18, 2017
* Author: Ronan Abhamon
*/
#ifdef QT_NO_DEBUG
#undef QT_NO_DEBUG
#endif // ifdef QT_NO_DEBUG
#include <QTest>
#include <QtGlobal>
#include "../app/App.hpp"
#include "TestUtils.hpp"
// =============================================================================
void TestUtils::executeKeySequence (QQuickWindow *window, QKeySequence sequence) {
for (int i = 0; i < sequence.count(); ++i) {
int key = sequence[i];
QTest::keyClick(
window,
Qt::Key(key & ~Qt::KeyboardModifierMask),
Qt::KeyboardModifiers(key & Qt::KeyboardModifierMask)
);
}
}
// -----------------------------------------------------------------------------
static void printItemTree (const QQuickItem *item, QString &output, int spaces) {
output.append(QString().leftJustified(spaces, ' '));
output.append(item->metaObject()->className());
output.append("\n");
for (const auto &childItem : item->childItems())
printItemTree(childItem, output, spaces + 2);
}
void TestUtils::printItemTree (const QQuickItem *item) {
QString output;
::printItemTree(item, output, 0);
qInfo().noquote() << output;
}
// -----------------------------------------------------------------------------
QQuickItem *TestUtils::getMainLoaderFromMainWindow () {
QList<QQuickItem *> items = App::getInstance()->getMainWindow()->contentItem()->childItems();
Q_ASSERT(!items.empty());
for (int i = 0; i < 3; ++i) {
items = items.at(0)->childItems();
Q_ASSERT(!items.empty());
}
QQuickItem *loader = items.at(0);
Q_ASSERT(!strcmp(loader->metaObject()->className(), "QQuickLoader"));
return loader;
}
// -----------------------------------------------------------------------------
QQuickItem *TestUtils::getVirtualWindowContent (const QQuickWindow *window) {
Q_CHECK_PTR(window);
QList<QQuickItem *> items = window->contentItem()->childItems();
Q_ASSERT(!items.empty());
items = items.at(0)->childItems();
Q_ASSERT(!items.empty());
items = items.at(0)->childItems();
Q_ASSERT(items.size() == 2);
const char name[] = "VirtualWindow_QMLTYPE_";
QQuickItem *virtualWindow = items.at(1);
Q_ASSERT(!strncmp(virtualWindow->metaObject()->className(), name, sizeof name - 1));
items = virtualWindow->childItems();
Q_ASSERT(items.size() == 2);
items = items.at(1)->childItems();
return items.empty() ? nullptr : items.at(0);
}
/*
* TestUtils.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 18, 2017
* Author: Ronan Abhamon
*/
#ifndef TEST_UTILS_H_
#define TEST_UTILS_H_
#include <QQuickItem>
#include <QQuickWindow>
// =============================================================================
#define CHECK_VIRTUAL_WINDOW_CONTENT_INFO(WINDOW, TYPE, NAME) \
do { \
QQuickItem *virtualWindowContent = TestUtils::getVirtualWindowContent(WINDOW); \
QVERIFY(virtualWindowContent); \
QVERIFY(!strncmp(virtualWindowContent->metaObject()->className(), TYPE, sizeof TYPE - 1)); \
QCOMPARE(virtualWindowContent->objectName(), QStringLiteral(NAME)); \
} while (0)
namespace TestUtils {
void executeKeySequence (QQuickWindow *window, QKeySequence sequence);
void printItemTree (const QQuickItem *item);
QQuickItem *getMainLoaderFromMainWindow ();
QQuickItem *getVirtualWindowContent (const QQuickWindow *window);
}
#endif // ifndef TEST_UTILS_H_
/*
* AssistantViewTest.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 20, 2017
* Author: Ronan Abhamon
*/
#include <QQmlProperty>
#include <QQuickItem>
#include <QSignalSpy>
#include <QTest>
#include "../../app/App.hpp"
#include "AssistantViewTest.hpp"
// =============================================================================
void AssistantViewTest::showAssistantView () {
QQuickWindow *mainWindow = App::getInstance()->getMainWindow();
// Ensure home view is selected.
QQuickItem *contentLoader = mainWindow->findChild<QQuickItem *>("__contentLoader");
QVERIFY(contentLoader);
QTest::mouseClick(mainWindow, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(110, 100));
// Show assistant view.
QSignalSpy spyLoaderReady(contentLoader, SIGNAL(loaded()));
QTest::mouseClick(mainWindow, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(705, 485));
QVERIFY(spyLoaderReady.count() == 1);
QCOMPARE(
QQmlProperty::read(contentLoader, "source").toString(),
QStringLiteral("qrc:/ui/views/App/Main/Assistant.qml")
);
}
/*
* AssistantViewTest.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 20, 2017
* Author: Ronan Abhamon
*/
#ifndef ASSISTANT_VIEW_TEST_H_
#define ASSISTANT_VIEW_TEST_H_
#include <QObject>
// =============================================================================
class AssistantViewTest : public QObject {
Q_OBJECT;
public:
AssistantViewTest () = default;
~AssistantViewTest () = default;
private slots:
void showAssistantView ();
};
#endif // ifndef ASSISTANT_VIEW_TEST_H_
/*
* MainViewTest.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 18, 2017
* Author: Ronan Abhamon
*/
#include <QQmlProperty>
#include <QSignalSpy>
#include <QTest>
#include "../../app/App.hpp"
#include "../TestUtils.hpp"
#include "MainViewTest.hpp"
// =============================================================================
void MainViewTest::showAboutPopup () {
QQuickWindow *mainWindow = App::getInstance()->getMainWindow();
// Open popup.
TestUtils::executeKeySequence(mainWindow, QKeySequence::HelpContents);
CHECK_VIRTUAL_WINDOW_CONTENT_INFO(mainWindow, "DialogPlus_QMLTYPE_", "__about");
// Close popup.
QTest::mouseClick(mainWindow, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(476, 392));
QVERIFY(!TestUtils::getVirtualWindowContent(mainWindow));
}
// -----------------------------------------------------------------------------
void MainViewTest::showManageAccountsPopup () {
QQuickWindow *mainWindow = App::getInstance()->getMainWindow();
// Open popup.
QTest::mouseClick(mainWindow, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(100, 35));
CHECK_VIRTUAL_WINDOW_CONTENT_INFO(mainWindow, "DialogPlus_QMLTYPE_", "__manageAccounts");
// Close popup.
QTest::mouseClick(mainWindow, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(476, 392));
QVERIFY(!TestUtils::getVirtualWindowContent(mainWindow));
}
// -----------------------------------------------------------------------------
void MainViewTest::showSettingsWindow () {
App *app = App::getInstance();
// Open window.
QTest::keyClick(app->getMainWindow(), Qt::Key_P, Qt::ControlModifier);
QQuickWindow *settingsWindow = app->getSettingsWindow();
QVERIFY(QTest::qWaitForWindowExposed(settingsWindow));
// Hide window.
TestUtils::executeKeySequence(settingsWindow, QKeySequence::Close);
QVERIFY(!settingsWindow->isVisible());
}
// -----------------------------------------------------------------------------
void MainViewTest::testMainMenuEntries_data () {
QTest::addColumn<int>("y");
QTest::addColumn<QString>("source");
QTest::newRow("home view 1") << 100 << "qrc:/ui/views/App/Main/Home.qml";
QTest::newRow("contacts view 1") << 150 << "qrc:/ui/views/App/Main/Contacts.qml";
QTest::newRow("home view 2") << 100 << "qrc:/ui/views/App/Main/Home.qml";
QTest::newRow("contacts view 2") << 150 << "qrc:/ui/views/App/Main/Contacts.qml";
}
void MainViewTest::testMainMenuEntries () {
QQuickWindow *mainWindow = App::getInstance()->getMainWindow();
QQuickItem *contentLoader = mainWindow->findChild<QQuickItem *>("__contentLoader");
QVERIFY(contentLoader);
QSignalSpy spyLoaderReady(contentLoader, SIGNAL(loaded()));
QFETCH(int, y);
QTest::mouseClick(mainWindow, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(110, y));
QVERIFY(spyLoaderReady.count() == 1);
QFETCH(QString, source);
QCOMPARE(QQmlProperty::read(contentLoader, "source").toString(), source);
}
/*
* MainViewTest.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 18, 2017
* Author: Ronan Abhamon
*/
#ifndef MAIN_VIEW_TEST_H_
#define MAIN_VIEW_TEST_H_
#include <QObject>
// =============================================================================
class MainViewTest : public QObject {
Q_OBJECT;
public:
MainViewTest () = default;
~MainViewTest () = default;
private slots:
void showAboutPopup ();
void showManageAccountsPopup ();
void showSettingsWindow ();
void testMainMenuEntries_data ();
void testMainMenuEntries ();
};
#endif // ifndef MAIN_VIEW_TEST_H_
/*
* main.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 17, 2017
* Author: Ronan Abhamon
*/
#include <QTest>
#include <QTimer>
#include "../app/AppController.hpp"
#include "../utils/Utils.hpp"
#include "assistant-view/AssistantViewTest.hpp"
#include "main-view/MainViewTest.hpp"
#include "self-test/SelfTest.hpp"
// =============================================================================
static QHash<QString, QObject *> initializeTests () {
QHash<QString, QObject *> hash;
hash["assistant-view"] = new AssistantViewTest();
hash["main-view"] = new MainViewTest();
return hash;
}
// -----------------------------------------------------------------------------
int main (int argc, char *argv[]) {
int fakeArgc = 1;
AppController controller(fakeArgc, argv);
App *app = controller.getApp();
if (app->isSecondary())
qFatal("Unable to run test with secondary app.");
int testsRet = 0;
const QHash<QString, QObject *> tests = initializeTests();
QObject *test = nullptr;
if (argc > 1) {
if (!strcmp(argv[1], "self-test"))
// Execute only self-test.
QTimer::singleShot(0, [app, &testsRet] {
testsRet = QTest::qExec(new SelfTest(app));
QCoreApplication::quit();
});
else {
// Execute only one test.
const QString testName = ::Utils::coreStringToAppString(argv[1]);
test = tests[testName];
if (!test) {
qWarning() << QStringLiteral("Unable to run invalid test: `%1`.").arg(testName);
return EXIT_FAILURE;
}
QTimer::singleShot(0, [app, &testsRet, test, argc, argv] {
testsRet = QTest::qExec(new SelfTest(app));
if (!testsRet)
QTest::qExec(test, argc - 1, argv + 1);
QCoreApplication::quit();
});
}
} else
// Execute all tests.
QTimer::singleShot(0, [app, &testsRet, &tests] {
testsRet = QTest::qExec(new SelfTest(app));
if (!testsRet)
for (const auto &test : tests) {
testsRet |= QTest::qExec(test);
}
QCoreApplication::quit();
});
app->initContentApp();
int ret = app->exec();
for (auto &test : tests)
delete test;
if (testsRet)
qWarning() << QStringLiteral("One or many tests are failed. :(");
else
qInfo() << QStringLiteral("Tests seems OK. :)");
return testsRet || ret;
}
/*
* SelfTest.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 17, 2017
* Author: Ronan Abhamon
*/
#include <QQmlProperty>
#include <QSignalSpy>
#include <QTest>
#include "../../app/App.hpp"
#include "../../components/core/CoreManager.hpp"
#include "../TestUtils.hpp"
#include "SelfTest.hpp"
// =============================================================================
void SelfTest::checkAppStartup () {
CoreManager *coreManager = CoreManager::getInstance();
QQuickItem *mainLoader = TestUtils::getMainLoaderFromMainWindow();
QSignalSpy spyCoreStarted(coreManager->getHandlers().get(), &CoreHandlers::coreStarted);
QSignalSpy spyLoaderReady(mainLoader, SIGNAL(loaded()));
if (!coreManager->started())
QVERIFY(spyCoreStarted.wait(5000));
if (!QQmlProperty::read(mainLoader, "item").value<QObject *>())
QVERIFY(spyLoaderReady.wait(1000));
QVERIFY(QTest::qWaitForWindowExposed(App::getInstance()->getMainWindow()));
}
/*
* SelfTest.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: July 17, 2017
* Author: Ronan Abhamon
*/
#ifndef SELF_TEST_H_
#define SELF_TEST_H_
#include <QObject>
// =============================================================================
class SelfTest : public QObject {
Q_OBJECT;
public:
SelfTest (QObject *parent = Q_NULLPTR) : QObject(parent) {}
private slots:
void checkAppStartup ();
};
#endif // ifndef SELF_TEST_H_
...@@ -26,7 +26,10 @@ ComboBox { ...@@ -26,7 +26,10 @@ ComboBox {
width: ComboBoxStyle.background.border.width width: ComboBoxStyle.background.border.width
} }
color: ComboBoxStyle.background.color color: comboBox.enabled
? ComboBoxStyle.background.color.normal
: ComboBoxStyle.background.color.readOnly
radius: ComboBoxStyle.background.radius radius: ComboBoxStyle.background.radius
implicitHeight: ComboBoxStyle.background.height implicitHeight: ComboBoxStyle.background.height
......
...@@ -8,7 +8,6 @@ import Units 1.0 ...@@ -8,7 +8,6 @@ import Units 1.0
QtObject { QtObject {
property QtObject background: QtObject { property QtObject background: QtObject {
property color color: Colors.k
property int height: 36 property int height: 36
property int iconSize: 10 property int iconSize: 10
property int radius: 4 property int radius: 4
...@@ -18,6 +17,11 @@ QtObject { ...@@ -18,6 +17,11 @@ QtObject {
property color color: Colors.c property color color: Colors.c
property int width: 1 property int width: 1
} }
property QtObject color: QtObject {
property color normal: Colors.k
property color readOnly: Colors.e
}
} }
property QtObject contentItem: QtObject { property QtObject contentItem: QtObject {
......
...@@ -109,7 +109,7 @@ ColumnLayout { ...@@ -109,7 +109,7 @@ ColumnLayout {
onEditingFinished: Logic.setUsername(text) onEditingFinished: Logic.setUsername(text)
onReadOnlyChanged: { onReadOnlyChanged: {
if (!readOnly) { if (!readOnly) {
focus = true forceActiveFocus()
} }
} }
} }
......
...@@ -19,6 +19,7 @@ DialogPlus { ...@@ -19,6 +19,7 @@ DialogPlus {
] ]
centeredButtons: true centeredButtons: true
objectName: '__about'
height: AboutStyle.height height: AboutStyle.height
width: AboutStyle.width width: AboutStyle.width
......
...@@ -18,6 +18,7 @@ DialogPlus { ...@@ -18,6 +18,7 @@ DialogPlus {
] ]
centeredButtons: true centeredButtons: true
objectName: '__manageAccounts'
height: ManageAccountsStyle.height height: ManageAccountsStyle.height
width: ManageAccountsStyle.width width: ManageAccountsStyle.width
......
...@@ -231,6 +231,8 @@ ApplicationWindow { ...@@ -231,6 +231,8 @@ ApplicationWindow {
Loader { Loader {
id: contentLoader id: contentLoader
objectName: '__contentLoader'
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
......
...@@ -73,7 +73,7 @@ function validProxyConfig () { ...@@ -73,7 +73,7 @@ function validProxyConfig () {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function handleRouteChanged (route) { function handleRouteChanged (route) {
dialog._routeOk = route.length === 0 || Linphone.SipAddressesModel.sipAddressIsValid(route) dialog._routeOk = route.length === 0 || Linphone.SipAddressesModel.addressIsValid(route)
} }
function handleServerAddressChanged (address) { function handleServerAddressChanged (address) {
......
...@@ -52,6 +52,8 @@ DialogPlus { ...@@ -52,6 +52,8 @@ DialogPlus {
TextField { TextField {
id: sipAddress id: sipAddress
error: dialog._sipAddressOk ? '' : qsTr('invalidSipAddress')
onTextChanged: Logic.handleSipAddressChanged(text) onTextChanged: Logic.handleSipAddressChanged(text)
} }
} }
...@@ -64,6 +66,8 @@ DialogPlus { ...@@ -64,6 +66,8 @@ DialogPlus {
TextField { TextField {
id: serverAddress id: serverAddress
error: dialog._serverAddressOk ? '' : qsTr('invalidServerAddress')
onTextChanged: Logic.handleServerAddressChanged(text) onTextChanged: Logic.handleServerAddressChanged(text)
} }
} }
...@@ -101,6 +105,8 @@ DialogPlus { ...@@ -101,6 +105,8 @@ DialogPlus {
TextField { TextField {
id: route id: route
error: dialog._routeOk ? '' : qsTr('invalidRoute')
onTextChanged: Logic.handleRouteChanged(text) onTextChanged: Logic.handleRouteChanged(text)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment