diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..ea6db76d8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,27 @@ +# 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.) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a417fbb4..ac973d582 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,16 @@ ################################################################################ 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(TESTER_EXECUTABLE_NAME "${EXECUTABLE_NAME}-tester") + set(TARGET_NAME linphone-qt) +set(TESTER_TARGET_NAME "${TARGET_NAME}-tester") + set(CMAKE_CXX_STANDARD 11) set(ASSETS_DIR assets) @@ -98,6 +104,7 @@ endif () set(SOURCES src/app/App.cpp + src/app/AppController.cpp src/app/cli/Cli.cpp src/app/logger/Logger.cpp src/app/paths/Paths.cpp @@ -144,7 +151,6 @@ set(SOURCES src/components/telephone-numbers/TelephoneNumbersModel.cpp src/components/timeline/TimelineModel.cpp src/components/url-handlers/UrlHandlers.cpp - src/main.cpp src/utils/LinphoneUtils.cpp src/utils/Utils.cpp src/utils/QExifImageHeader.cpp @@ -152,6 +158,7 @@ set(SOURCES set(HEADERS src/app/App.hpp + src/app/AppController.hpp src/app/cli/Cli.hpp src/app/logger/Logger.hpp src/app/paths/Paths.hpp @@ -205,6 +212,20 @@ set(HEADERS 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) list(APPEND SOURCES src/components/core/MessagesCountNotifierMacOS.m) endif() @@ -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_OPTIONAL} QUIET) +find_package(Qt5 COMPONENTS Test REQUIRED) if (CMAKE_INSTALL_RPATH) get_target_property(LUPDATE_PATH Qt5::lupdate LOCATION) @@ -304,46 +326,44 @@ list(APPEND QRC_RESOURCES "${CMAKE_CURRENT_BINARY_DIR}/${LANGUAGES_DIRECTORY}/${ qt5_add_resources(RESOURCES ${QRC_RESOURCES}) # 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) - add_executable(${TARGET_NAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} assets/linphone.rc) + add_executable(${TARGET_NAME} WIN32 $ assets/linphone.rc ${MAIN_FILE}) + add_executable(${TESTER_TARGET_NAME} WIN32 $ assets/linphone.rc ${TESTER_MAIN_FILE} ${TESTS}) else () - add_executable(${TARGET_NAME} ${SOURCES} ${HEADERS} ${RESOURCES} ${QML_SOURCES}) + add_executable(${TARGET_NAME} $ ${MAIN_FILE}) + add_executable(${TESTER_TARGET_NAME} $ ${TESTER_MAIN_FILE} ${TESTS}) 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) add_dependencies(update_translations check_qml) endif () 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. -source_group( - "Qml" REGULAR_EXPRESSION ".+\.qml$" -) -source_group( - "Js" REGULAR_EXPRESSION ".+\.js)$" -) -source_group( - "Svg" REGULAR_EXPRESSION ".+\.svg$" -) +set(INCLUDED_DIRECTORIES "${LINPHONECXX_INCLUDE_DIRS}" "${LINPHONE_INCLUDE_DIRS}" "${BELCARD_INCLUDE_DIRS}" "${BCTOOLBOX_INCLUDE_DIRS}") +set(LIBRARIES ${BCTOOLBOX_CORE_LIBRARIES} ${BELCARD_LIBRARIES} ${LINPHONE_LIBRARIES} ${LINPHONECXX_LIBRARIES}) 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. # But the `Qt5::LinguistTools` lib does not exist. Remove it. if (NOT (${package} STREQUAL LinguistTools)) - target_link_libraries(${TARGET_NAME} ${Qt5${package}_LIBRARIES}) + list(APPEND LIBRARIES ${Qt5${package}_LIBRARIES}) endif () endforeach () foreach (package ${QT5_PACKAGES_OPTIONAL}) if ("${Qt5${package}_FOUND}") message("Optional package ${package} found.") - target_include_directories(${TARGET_NAME} SYSTEM PRIVATE "${Qt5${package}_INCLUDE_DIRS}") - target_link_libraries(${TARGET_NAME} ${Qt5${package}_LIBRARIES}) + list(APPEND INCLUDED_DIRECTORIES "${Qt5${package}_INCLUDE_DIRS}") + list(APPEND LIBRARIES ${Qt5${package}_LIBRARIES}) string(TOUPPER "${package}" INCLUDE_NAME) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${INCLUDE_NAME}_ENABLED") @@ -352,17 +372,25 @@ foreach (package ${QT5_PACKAGES_OPTIONAL}) endif () endforeach () -target_link_libraries(${TARGET_NAME} ${BCTOOLBOX_CORE_LIBRARIES} ${BELCARD_LIBRARIES} ${LINPHONE_LIBRARIES} ${LINPHONECXX_LIBRARIES}) -if(APPLE) - target_link_libraries(${TARGET_NAME} "-framework Cocoa") -endif() +if (APPLE) + list(APPEND LIBRARIES "-framework Cocoa") +endif () -install(TARGETS ${TARGET_NAME} - 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 -) +target_include_directories(${APP_LIBRARY} SYSTEM PRIVATE ${INCLUDED_DIRECTORIES}) +target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDED_DIRECTORIES}) +target_include_directories(${TESTER_TARGET_NAME} SYSTEM PRIVATE ${INCLUDED_DIRECTORIES}) + +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" DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" @@ -393,7 +421,6 @@ install(FILES "${ASSETS_ASSISTANT_DIR}/use-linphone-sip-account.rc" DESTINATION "${ASSISTANT_INSTALL_DATADIR}" ) - # ------------------------------------------------------------------------------ # CPack settings. # ------------------------------------------------------------------------------ @@ -401,12 +428,26 @@ install(FILES "${ASSETS_ASSISTANT_DIR}/use-linphone-sip-account.rc" set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}") set(CPACK_SOURCE_IGNORE_FILES - "^${CMAKE_BINARY_DIR}" - "/\\\\..+" - "OUTPUT" - "WORK" - "cmake_builder" - "submodules" + "^${CMAKE_BINARY_DIR}" + "/\\\\..+" + "OUTPUT" + "WORK" + "cmake_builder" + "submodules" ) 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$" +) diff --git a/assets/languages/en.ts b/assets/languages/en.ts index 6b7d385cc..5e4627089 100644 --- a/assets/languages/en.ts +++ b/assets/languages/en.ts @@ -40,10 +40,6 @@ App - - selfTestResult - Linphone seems to be running correctly. - commandLineOptionVerbose log to stdout some debug information while running @@ -52,10 +48,6 @@ commandLineOptionConfig specify the linphone configuration file to be used - - commandLineOptionSelfTest - run self test and exit 0 if it succeeded - applicationDescription A free (libre) SIP video-phone. @@ -1327,6 +1319,18 @@ your friend's SIP address or username. confirm CONFIRM + + invalidSipAddress + Invalid sip address. + + + invalidServerAddress + Invalid server address. + + + invalidRoute + Invalid route. + SettingsUi diff --git a/assets/languages/fr.ts b/assets/languages/fr.ts index 350620590..b77ec8b69 100644 --- a/assets/languages/fr.ts +++ b/assets/languages/fr.ts @@ -40,10 +40,6 @@ App - - selfTestResult - Linphone semble fonctionner normalement. - commandLineOptionVerbose afficher sur stdout les informations de debug @@ -52,10 +48,6 @@ commandLineOptionConfig spécifier un fichier de configuration à utiliser - - commandLineOptionSelfTest - éxécuter un test automatique et retourner 0 en cas de succès - applicationDescription Un logiciel libre de voix sur IP SIP. @@ -1325,6 +1317,18 @@ Cliquez ici : <a href="%1">%1</a> confirm CONFIRMER + + invalidSipAddress + Adresse sip invalide. + + + invalidServerAddress + Adresse du serveur invalide. + + + invalidRoute + Route invalide. + SettingsUi diff --git a/src/app/App.cpp b/src/app/App.cpp index f6b684171..aa029324b 100644 --- a/src/app/App.cpp +++ b/src/app/App.cpp @@ -55,8 +55,6 @@ #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. using namespace std; @@ -104,6 +102,8 @@ App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::U if (mParser->isSet("version")) mParser->showVersion(); + + qInfo() << QStringLiteral("Use locale: %1").arg(mLocale); } App::~App () { @@ -202,19 +202,12 @@ void App::initContentApp () { mNotifier = new Notifier(mEngine); // Load splashscreen. - bool selfTest = mParser->isSet("self-test"); - if (!selfTest) { - #ifdef Q_OS_MACOS + #ifdef Q_OS_MACOS + ::activeSplashScreen(mEngine); + #else + if (!mParser->isSet("iconified")) ::activeSplashScreen(mEngine); - #else - 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. :("); - }); + #endif // ifdef Q_OS_MACOS // Load main view. qInfo() << QStringLiteral("Loading main view..."); @@ -225,7 +218,7 @@ void App::initContentApp () { QObject::connect( CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::coreStarted, - this, selfTest ? &App::quit : &App::openAppAfterInit + this, &App::openAppAfterInit ); } @@ -308,7 +301,6 @@ void App::createParser () { #ifndef Q_OS_MACOS { "iconified", tr("commandLineOptionIconified") }, #endif // ifndef Q_OS_MACOS - { "self-test", tr("commandLineOptionSelfTest") }, { { "V", "verbose" }, tr("commandLineOptionVerbose") } // TODO: Enable me in future version! // , @@ -331,11 +323,6 @@ void App::createParser () { "Linphone", 1, 0, NAME, NAME " is uncreatable." \ ) -template -void registerMetaType (const char *name) { - qRegisterMetaType(name); -} - template void registerSingletonType (const char *name) { qmlRegisterSingletonType("Linphone", 1, 0, name, [](QQmlEngine *engine, QJSEngine *) -> QObject *{ @@ -367,6 +354,9 @@ void registerToolType (const char *name) { void App::registerTypes () { qInfo() << QStringLiteral("Registering types..."); + qRegisterMetaType >(); + qRegisterMetaType(); + registerType("AssistantModel"); registerType("AuthenticationNotifier"); registerType("CallsListProxyModel"); @@ -387,8 +377,6 @@ void App::registerTypes () { registerSingletonType("UrlHandlers"); registerSingletonType("VideoCodecsModel"); - registerMetaType("ChatModel::EntryType"); - registerUncreatableType(CallModel, "CallModel"); registerUncreatableType(ChatModel, "ChatModel"); registerUncreatableType(ConferenceHelperModel::ConferenceAddModel, "ConferenceAddModel"); @@ -476,7 +464,6 @@ void App::initLocale (const shared_ptr &config) { if (!locale.isEmpty() && ::installLocale(*this, *mTranslator, QLocale(locale))) { mLocale = locale; - qInfo() << QStringLiteral("Use preferred locale: %1").arg(locale); return; } @@ -484,7 +471,6 @@ void App::initLocale (const shared_ptr &config) { QLocale sysLocale = QLocale::system(); if (::installLocale(*this, *mTranslator, sysLocale)) { mLocale = sysLocale.name(); - qInfo() << QStringLiteral("Use system locale: %1").arg(mLocale); return; } @@ -492,7 +478,6 @@ void App::initLocale (const shared_ptr &config) { mLocale = DEFAULT_LOCALE; if (!::installLocale(*this, *mTranslator, QLocale(mLocale))) qFatal("Unable to install default translator."); - qInfo() << QStringLiteral("Use default locale: %1").arg(mLocale); } QString App::getConfigLocale () const { @@ -569,12 +554,3 @@ void App::checkForUpdate () { ::Utils::appStringToCoreString(applicationVersion()) ); } - -// ----------------------------------------------------------------------------- - -void App::quit () { - if (mParser->isSet("self-test")) - cout << tr("selfTestResult").toStdString() << endl; - - QApplication::quit(); -} diff --git a/src/app/App.hpp b/src/app/App.hpp index 8bfa69522..06d825e40 100644 --- a/src/app/App.hpp +++ b/src/app/App.hpp @@ -71,8 +71,6 @@ public: bool hasFocus () const; - void quit () override; - static App *getInstance () { return static_cast(QApplication::instance()); } diff --git a/src/main.cpp b/src/app/AppController.cpp similarity index 81% rename from src/main.cpp rename to src/app/AppController.cpp index 36fdb5e30..7453b3e6f 100644 --- a/src/main.cpp +++ b/src/app/AppController.cpp @@ -1,5 +1,5 @@ /* - * main.cpp + * AppController.cpp * Copyright (C) 2017 Belledonne Communications, Grenoble, France * * This program is free software; you can redistribute it and/or @@ -16,7 +16,7 @@ * 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 + * Created on: July 17, 2017 * Author: Ronan Abhamon */ @@ -26,7 +26,7 @@ #include "gitversion.h" -#include "app/App.hpp" +#include "AppController.hpp" // Must be unique. Used by `SingleApplication` and `Paths`. #define APPLICATION_NAME "linphone" @@ -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); + Q_ASSERT(!mApp); // Disable QML cache. Avoid malformed cache. qputenv("QML_DISABLE_DISK_CACHE", "true"); @@ -81,12 +82,11 @@ int main (int argc, char *argv[]) { QCoreApplication::setApplicationName(APPLICATION_NAME); QCoreApplication::setApplicationVersion(APPLICATION_VERSION); - App app(argc, argv); - - if (app.isSecondary()) { - QString command = app.getCommandArgument(); - app.sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1); - return 0; + mApp = new App(argc, argv); + if (mApp->isSecondary()) { + QString command = mApp->getCommandArgument(); + mApp->sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1); + return; } // --------------------------------------------------------------------------- @@ -104,18 +104,9 @@ int main (int argc, char *argv[]) { } } - app.setFont(QFont(DEFAULT_FONT)); - - // --------------------------------------------------------------------------- - // Init and run! - // --------------------------------------------------------------------------- - - qInfo() << QStringLiteral("Running app..."); - - int ret; - do { - app.initContentApp(); - ret = app.exec(); - } while (ret == APP_CODE_RESTART); - return ret; + mApp->setFont(QFont(DEFAULT_FONT)); +} + +AppController::~AppController () { + delete mApp; } diff --git a/src/app/AppController.hpp b/src/app/AppController.hpp new file mode 100644 index 000000000..2fe9729c2 --- /dev/null +++ b/src/app/AppController.hpp @@ -0,0 +1,39 @@ +/* + * 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; +}; diff --git a/src/app/main.cpp b/src/app/main.cpp new file mode 100644 index 000000000..9d483face --- /dev/null +++ b/src/app/main.cpp @@ -0,0 +1,41 @@ +/* + * 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; +} diff --git a/src/components/core/CoreManager.cpp b/src/components/core/CoreManager.cpp index 1774c3584..9f1994f02 100644 --- a/src/components/core/CoreManager.cpp +++ b/src/components/core/CoreManager.cpp @@ -63,6 +63,8 @@ CoreManager::CoreManager (QObject *parent, const QString &configPath) : mInstance->mSettingsModel = new SettingsModel(mInstance); mInstance->mAccountSettingsModel = new AccountSettingsModel(mInstance); + mInstance->mStarted = true; + emit mInstance->coreStarted(); }); diff --git a/src/components/core/CoreManager.hpp b/src/components/core/CoreManager.hpp index 2de5786eb..b8474b9b4 100644 --- a/src/components/core/CoreManager.hpp +++ b/src/components/core/CoreManager.hpp @@ -47,6 +47,10 @@ class CoreManager : public QObject { public: ~CoreManager () = default; + bool started () const { + return mStarted; + } + std::shared_ptr getCore () { Q_CHECK_PTR(mCore); return mCore; @@ -151,6 +155,8 @@ private: std::shared_ptr mCore; std::shared_ptr mHandlers; + bool mStarted = false; + CallsListModel *mCallsListModel = nullptr; ContactsListModel *mContactsListModel = nullptr; SipAddressesModel *mSipAddressesModel = nullptr; diff --git a/src/components/notifier/Notifier.cpp b/src/components/notifier/Notifier.cpp index d06657bd4..cffdae7cc 100644 --- a/src/components/notifier/Notifier.cpp +++ b/src/components/notifier/Notifier.cpp @@ -43,7 +43,7 @@ #define NOTIFICATION_PROPERTY_X "popupX" #define NOTIFICATION_PROPERTY_Y "popupY" -#define NOTIFICATION_PROPERTY_WINDOW "__internalWindow" +#define NOTIFICATION_PROPERTY_WINDOW "internalWindow" #define NOTIFICATION_PROPERTY_TIMER "__timer" diff --git a/src/components/settings/AccountSettingsModel.cpp b/src/components/settings/AccountSettingsModel.cpp index 97f110aeb..af1dc735e 100644 --- a/src/components/settings/AccountSettingsModel.cpp +++ b/src/components/settings/AccountSettingsModel.cpp @@ -20,6 +20,7 @@ * Author: Ronan Abhamon */ +#include "../../app/paths/Paths.hpp" #include "../../utils/Utils.hpp" #include "../core/CoreManager.hpp" @@ -136,7 +137,11 @@ bool AccountSettingsModel::addOrUpdateProxyConfig ( 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. @@ -164,7 +169,13 @@ bool AccountSettingsModel::addOrUpdateProxyConfig ( } shared_ptr AccountSettingsModel::createProxyConfig () { - return CoreManager::getInstance()->getCore()->createProxyConfig(); + shared_ptr core = CoreManager::getInstance()->getCore(); + + core->getConfig()->loadFromXmlFile( + Paths::getAssistantConfigDirPath() + "create-linphone-sip-account.rc" + ); + + return core->createProxyConfig(); } void AccountSettingsModel::addAuthInfo ( diff --git a/src/components/sip-addresses/SipAddressesModel.cpp b/src/components/sip-addresses/SipAddressesModel.cpp index c2fcaf0d8..091afbd28 100644 --- a/src/components/sip-addresses/SipAddressesModel.cpp +++ b/src/components/sip-addresses/SipAddressesModel.cpp @@ -175,12 +175,19 @@ QString SipAddressesModel::interpretUrl (const QUrl &sipAddress) { return sipAddress.toString(); } -bool SipAddressesModel::sipAddressIsValid (const QString &sipAddress) { +bool SipAddressesModel::addressIsValid (const QString &address) { return !!linphone::Factory::get()->createAddress( - ::Utils::appStringToCoreString(sipAddress) + ::Utils::appStringToCoreString(address) ); } +bool SipAddressesModel::sipAddressIsValid (const QString &sipAddress) { + shared_ptr address = linphone::Factory::get()->createAddress( + ::Utils::appStringToCoreString(sipAddress) + ); + return address && !address->getUsername().empty(); +} + // ----------------------------------------------------------------------------- bool SipAddressesModel::removeRow (int row, const QModelIndex &parent) { diff --git a/src/components/sip-addresses/SipAddressesModel.hpp b/src/components/sip-addresses/SipAddressesModel.hpp index dacee0566..90111865e 100644 --- a/src/components/sip-addresses/SipAddressesModel.hpp +++ b/src/components/sip-addresses/SipAddressesModel.hpp @@ -59,6 +59,7 @@ public: Q_INVOKABLE static QString interpretUrl (const QString &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); // --------------------------------------------------------------------------- diff --git a/src/tests/TestUtils.cpp b/src/tests/TestUtils.cpp new file mode 100644 index 000000000..30aae8410 --- /dev/null +++ b/src/tests/TestUtils.cpp @@ -0,0 +1,104 @@ +/* + * 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 +#include + +#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 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 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); +} diff --git a/src/tests/TestUtils.hpp b/src/tests/TestUtils.hpp new file mode 100644 index 000000000..75ba72d8f --- /dev/null +++ b/src/tests/TestUtils.hpp @@ -0,0 +1,49 @@ +/* + * 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 +#include + +// ============================================================================= + +#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_ diff --git a/src/tests/assistant-view/AssistantViewTest.cpp b/src/tests/assistant-view/AssistantViewTest.cpp new file mode 100644 index 000000000..f883814d4 --- /dev/null +++ b/src/tests/assistant-view/AssistantViewTest.cpp @@ -0,0 +1,50 @@ +/* + * 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 +#include +#include +#include + +#include "../../app/App.hpp" + +#include "AssistantViewTest.hpp" + +// ============================================================================= + +void AssistantViewTest::showAssistantView () { + QQuickWindow *mainWindow = App::getInstance()->getMainWindow(); + + // Ensure home view is selected. + QQuickItem *contentLoader = mainWindow->findChild("__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") + ); +} diff --git a/src/tests/assistant-view/AssistantViewTest.hpp b/src/tests/assistant-view/AssistantViewTest.hpp new file mode 100644 index 000000000..de660577c --- /dev/null +++ b/src/tests/assistant-view/AssistantViewTest.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +// ============================================================================= + +class AssistantViewTest : public QObject { + Q_OBJECT; + +public: + AssistantViewTest () = default; + ~AssistantViewTest () = default; + +private slots: + void showAssistantView (); +}; + +#endif // ifndef ASSISTANT_VIEW_TEST_H_ diff --git a/src/tests/main-view/MainViewTest.cpp b/src/tests/main-view/MainViewTest.cpp new file mode 100644 index 000000000..e5520b790 --- /dev/null +++ b/src/tests/main-view/MainViewTest.cpp @@ -0,0 +1,104 @@ +/* + * 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 +#include +#include + +#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("y"); + QTest::addColumn("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("__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); +} diff --git a/src/tests/main-view/MainViewTest.hpp b/src/tests/main-view/MainViewTest.hpp new file mode 100644 index 000000000..82d37e0c6 --- /dev/null +++ b/src/tests/main-view/MainViewTest.hpp @@ -0,0 +1,46 @@ +/* + * 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 + +// ============================================================================= + +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_ diff --git a/src/tests/main.cpp b/src/tests/main.cpp new file mode 100644 index 000000000..8aa02129e --- /dev/null +++ b/src/tests/main.cpp @@ -0,0 +1,103 @@ +/* + * 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 +#include + +#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 initializeTests () { + QHash 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 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; +} diff --git a/src/tests/self-test/SelfTest.cpp b/src/tests/self-test/SelfTest.cpp new file mode 100644 index 000000000..006988adc --- /dev/null +++ b/src/tests/self-test/SelfTest.cpp @@ -0,0 +1,49 @@ +/* + * 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 +#include +#include + +#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()) + QVERIFY(spyLoaderReady.wait(1000)); + + QVERIFY(QTest::qWaitForWindowExposed(App::getInstance()->getMainWindow())); +} diff --git a/src/tests/self-test/SelfTest.hpp b/src/tests/self-test/SelfTest.hpp new file mode 100644 index 000000000..3eab7c6c6 --- /dev/null +++ b/src/tests/self-test/SelfTest.hpp @@ -0,0 +1,40 @@ +/* + * 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 + +// ============================================================================= + +class SelfTest : public QObject { + Q_OBJECT; + +public: + SelfTest (QObject *parent = Q_NULLPTR) : QObject(parent) {} + +private slots: + void checkAppStartup (); +}; + +#endif // ifndef SELF_TEST_H_ diff --git a/ui/modules/Common/Form/ComboBox.qml b/ui/modules/Common/Form/ComboBox.qml index e208714c6..f1c45bc9b 100644 --- a/ui/modules/Common/Form/ComboBox.qml +++ b/ui/modules/Common/Form/ComboBox.qml @@ -26,7 +26,10 @@ ComboBox { width: ComboBoxStyle.background.border.width } - color: ComboBoxStyle.background.color + color: comboBox.enabled + ? ComboBoxStyle.background.color.normal + : ComboBoxStyle.background.color.readOnly + radius: ComboBoxStyle.background.radius implicitHeight: ComboBoxStyle.background.height diff --git a/ui/modules/Common/Styles/Form/ComboBoxStyle.qml b/ui/modules/Common/Styles/Form/ComboBoxStyle.qml index f1df642a9..e2567976b 100644 --- a/ui/modules/Common/Styles/Form/ComboBoxStyle.qml +++ b/ui/modules/Common/Styles/Form/ComboBoxStyle.qml @@ -8,7 +8,6 @@ import Units 1.0 QtObject { property QtObject background: QtObject { - property color color: Colors.k property int height: 36 property int iconSize: 10 property int radius: 4 @@ -18,6 +17,11 @@ QtObject { property color color: Colors.c property int width: 1 } + + property QtObject color: QtObject { + property color normal: Colors.k + property color readOnly: Colors.e + } } property QtObject contentItem: QtObject { diff --git a/ui/views/App/Main/ContactEdit.qml b/ui/views/App/Main/ContactEdit.qml index d0f69a41c..24746d6d5 100644 --- a/ui/views/App/Main/ContactEdit.qml +++ b/ui/views/App/Main/ContactEdit.qml @@ -109,7 +109,7 @@ ColumnLayout { onEditingFinished: Logic.setUsername(text) onReadOnlyChanged: { if (!readOnly) { - focus = true + forceActiveFocus() } } } diff --git a/ui/views/App/Main/Dialogs/About.qml b/ui/views/App/Main/Dialogs/About.qml index e9f40b5d9..2deffe785 100644 --- a/ui/views/App/Main/Dialogs/About.qml +++ b/ui/views/App/Main/Dialogs/About.qml @@ -19,6 +19,7 @@ DialogPlus { ] centeredButtons: true + objectName: '__about' height: AboutStyle.height width: AboutStyle.width diff --git a/ui/views/App/Main/Dialogs/ManageAccounts.qml b/ui/views/App/Main/Dialogs/ManageAccounts.qml index 98f6319fe..f20adba52 100644 --- a/ui/views/App/Main/Dialogs/ManageAccounts.qml +++ b/ui/views/App/Main/Dialogs/ManageAccounts.qml @@ -18,6 +18,7 @@ DialogPlus { ] centeredButtons: true + objectName: '__manageAccounts' height: ManageAccountsStyle.height width: ManageAccountsStyle.width diff --git a/ui/views/App/Main/MainWindow.qml b/ui/views/App/Main/MainWindow.qml index 931d3cc23..b3a01fc22 100644 --- a/ui/views/App/Main/MainWindow.qml +++ b/ui/views/App/Main/MainWindow.qml @@ -231,6 +231,8 @@ ApplicationWindow { Loader { id: contentLoader + objectName: '__contentLoader' + Layout.fillHeight: true Layout.fillWidth: true diff --git a/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.js b/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.js index 46aab78c4..15461fa6c 100644 --- a/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.js +++ b/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.js @@ -73,7 +73,7 @@ function validProxyConfig () { // ----------------------------------------------------------------------------- function handleRouteChanged (route) { - dialog._routeOk = route.length === 0 || Linphone.SipAddressesModel.sipAddressIsValid(route) + dialog._routeOk = route.length === 0 || Linphone.SipAddressesModel.addressIsValid(route) } function handleServerAddressChanged (address) { diff --git a/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.qml b/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.qml index 596fe2ad2..e9f252166 100644 --- a/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.qml +++ b/ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.qml @@ -52,6 +52,8 @@ DialogPlus { TextField { id: sipAddress + error: dialog._sipAddressOk ? '' : qsTr('invalidSipAddress') + onTextChanged: Logic.handleSipAddressChanged(text) } } @@ -64,6 +66,8 @@ DialogPlus { TextField { id: serverAddress + error: dialog._serverAddressOk ? '' : qsTr('invalidServerAddress') + onTextChanged: Logic.handleServerAddressChanged(text) } } @@ -101,6 +105,8 @@ DialogPlus { TextField { id: route + error: dialog._routeOk ? '' : qsTr('invalidRoute') + onTextChanged: Logic.handleRouteChanged(text) } }