diff --git a/.gitmodules b/.gitmodules index 7aeea8bc252..50f28716873 100644 --- a/.gitmodules +++ b/.gitmodules @@ -142,3 +142,9 @@ [submodule "Modules/jaspSurvival"] path = Modules/jaspSurvival url = https://github.com/jasp-stats/jaspSurvival +[submodule "jaspCommonLib"] + path = jaspCommonLib + url = https://github.com/jasp-stats/jaspCommonLib +[submodule "jaspQMLControlsPlugin"] + path = jaspQMLControlsPlugin + url = https://github.com/jasp-stats/jaspQMLControlsPlugin diff --git a/CMakeLists.txt b/CMakeLists.txt index 3581123801f..c72f9306ae3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,9 +123,9 @@ if(WIN32) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) endif() -add_subdirectory(Common) +add_subdirectory(jaspCommonLib) add_subdirectory(CommonData) -add_subdirectory(QMLComponents) +add_subdirectory(jaspQMLControlsPlugin) if(NOT WIN32) add_subdirectory(R-Interface) diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt deleted file mode 100644 index a29d4c3d0ea..00000000000 --- a/Common/CMakeLists.txt +++ /dev/null @@ -1,102 +0,0 @@ -# This will build the Common library -# -# On Linux, -# - We need to link to the `librt.so`, and for some reason, CMake cannot find it -# easily, so, Libraries module tries to find it and provides it to Common here. -# - Since we are not using Conan, I link to the libjsoncpp, using the PkgConfig variables -# -# -list(APPEND CMAKE_MESSAGE_CONTEXT Common) - -configure_file(${CMAKE_CURRENT_LIST_DIR}/appinfo.cpp.in - ${CMAKE_CURRENT_LIST_DIR}/appinfo.cpp) -message(STATUS "appinfo.cpp is successfully generated...") - -configure_file(${CMAKE_CURRENT_LIST_DIR}/QtUtils/appdirs.h.in - ${CMAKE_CURRENT_LIST_DIR}/QtUtils//appdirs.h) -message(STATUS "appdirs.h is successfully generated...") - -file(GLOB HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/*.h" "${CMAKE_CURRENT_LIST_DIR}/json/*.h") -file(GLOB SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/*.cpp" "${CMAKE_CURRENT_LIST_DIR}/json/*.cpp") -file(GLOB QT_UTILS_HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/QtUtils/*.h") -file(GLOB QT_UTILS_SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/QtUtils/*.cpp") - -add_library(Common SHARED ${SOURCE_FILES} ${HEADER_FILES}) -add_library(CommonWithQt SHARED ${SOURCE_FILES} ${HEADER_FILES} ${QT_UTILS_HEADER_FILES} ${QT_UTILS_SOURCE_FILES}) - -if(LINUX) - target_link_libraries(Common PUBLIC ${_LIB_RT}) - target_link_options(Common PUBLIC -lrt) - target_link_libraries(CommonWithQt PUBLIC ${_LIB_RT}) - target_link_options(CommonWithQt PUBLIC -lrt) -endif() - -target_include_directories( - Common PUBLIC - # R - ${R_INCLUDE_PATH} - ${R_HOME_PATH}/include - ${RCPP_PATH}/include -) - -target_include_directories( - CommonWithQt PUBLIC - # R - ${R_INCLUDE_PATH} - ${R_HOME_PATH}/include - ${RCPP_PATH}/include -) - -target_link_libraries( - Common PUBLIC - Boost::system - Boost::date_time - Boost::timer - Boost::chrono - $<$:ntdll> -) - -target_link_libraries( - CommonWithQt PUBLIC - Boost::system - Boost::date_time - Boost::timer - Boost::chrono - $<$:ntdll> - Qt::Core - Qt::Qml - Qt::Quick -) - -target_compile_definitions( - Common PUBLIC - $<$:PROFILE_JASP> - JSONCPP_NO_LOCALE_SUPPORT -) - -target_compile_definitions( - CommonWithQt PUBLIC - $<$:JASP_USES_QT_HERE> - $<$:PROFILE_JASP> - JSONCPP_NO_LOCALE_SUPPORT -) - -if(WINDOWS) - target_compile_definitions( - Common PUBLIC - NOMINMAX - WIN32_LEAN_AND_MEAN - ) - target_compile_definitions( - CommonWithQt PUBLIC - NOMINMAX - WIN32_LEAN_AND_MEAN - ) -endif() - -if(IWYU_EXECUTABLE AND RUN_IWYU) - set_target_properties(Common PROPERTIES CXX_INCLUDE_WHAT_YOU_USE ${IWYU_EXECUTABLE}) - set_target_properties(CommonWithQt PROPERTIES CXX_INCLUDE_WHAT_YOU_USE ${IWYU_EXECUTABLE}) -endif() - -list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/Common/QtUtils/appdirs.cpp b/Common/QtUtils/appdirs.cpp deleted file mode 100644 index b588b0892d0..00000000000 --- a/Common/QtUtils/appdirs.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "appdirs.h" - -#include - - -#ifdef _WIN32 -#include -#include "dynamicruntimeinfo.h" -#endif -#include "qutils.h" -#include "utils.h" - -#include "dirs.h" -#include -#include "appinfo.h" - -#include "log.h" - -using namespace std; - -QString AppDirs::examples() -{ - static QString dir = QDir(tq(Dirs::resourcesDir()) + tq("Data Sets")).canonicalPath(); - return dir; -} - -QString AppDirs::help() -{ - static QString dir = QDir(tq(Dirs::resourcesDir()) + tq("Help")).canonicalPath(); - - return dir; -} - -QString AppDirs::analysisDefaultsDir() -{ - QString path = appData() + "/AnalysisDefaults"; - QDir dir(path); - dir.mkpath("."); - - return path; -} - -QString AppDirs::userRLibrary() -{ - QString path = appData(); - path += "/libraryR/"; - - return path; -} - -QString AppDirs::userModulesDir() -{ - QString path = appData(); - path += "/Modules/"; - - return path; -} - -QString AppDirs::bundledModulesDir() -{ - static QString folder; -#ifdef _WIN32 - auto env = DynamicRuntimeInfo::getInstance()->getRuntimeEnvironment(); - bool useAppdata = env != DynamicRuntimeInfo::MSIX; - folder = useAppdata ? programDir().absoluteFilePath("Modules") + '/' : appData(false) + "/BundledJASPModules_" + QString(AppInfo::version.asString(4).c_str()) + "_" + QString(AppInfo::gitCommit.substr(0, 7).c_str()) + "_" + QString(AppInfo::builddate.c_str()).replace(":", "-").replace(" ", "") + "/"; -#elif __APPLE__ - folder = programDir().absoluteFilePath("../Modules/"); -#elif FLATPAK_USED - folder = "/app/bin/../Modules/"; -#else //Normal linux build - folder = programDir().absoluteFilePath("../Modules") + '/'; -#endif - // @Joris, I think these guys should be one level up, - // they are not binaries, so, they should not be in - // the binary folder in my opinion. - return folder; -} - -QString AppDirs::processPath(const QString & path) -{ -#ifdef _WIN32 - return QString::fromStdWString(Utils::getShortPathWin(path.toStdWString())); -#else - return path; -#endif -} - - -QString AppDirs::documents() -{ - return processPath(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); -} - -QString AppDirs::logDir() -{ - QString path = appData(); - path += "/Logs/"; - - QDir log(path); - - if(!log.exists()) - log.mkpath("."); - - return path; -} - -QString AppDirs::appData(bool roaming) -{ - if(roaming) - return processPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); - else - return processPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); -} - -/** - * @brief This returns the path to R home directory, where `bin/`, `lib/`, `library/`, etc. - * are located. - * - * @details On macOS, R lives inside the Frameworks folder, both on build and inside the - * the App Bundle, that's a level up from JASP, and JASPEngine. On Windows, R is in the same - * level as JASP binaries, and on Linux, R might lives in different location, that's why we - * have a bit of a logic there to figure out where it is. - * - * @note The Linux logic is most likely not necessary since rHomeDir is being set at config - * time by CMake and that should always point to the right place no matter what. I will - * revisit this as soon as we have a working Flatpak build. - * - * @return Path to R home directory - */ -QString AppDirs::rHome() -{ - - QString rHomePath; - -#ifdef _WIN32 - rHomePath = programDir().absoluteFilePath("R"); -#endif - -#if defined(__APPLE__) - rHomePath = programDir().absoluteFilePath("../Frameworks/R.framework/Versions/" + QString::fromStdString(AppInfo::getRDirName()) + "/Resources"); -#endif - -#ifdef linux - -if (AppDirs::rHomeDir().isEmpty()) -{ - rHomePath = programDir().absoluteFilePath("R/lib/libR.so"); - if (QFileInfo(rHomePath).exists() == false) -#ifdef FLATPAK_USED - rHomePath = "/app/lib64/R/"; //Tools/flatpak/org.jaspstats.JASP.json also sets R_HOME to /app/lib64 for 32bits... -#else - rHomePath = "/usr/lib/R/"; -#endif -} else { - Log::log() << "AppDirs::rHomeDir() is set " << AppDirs::rHomeDir() << std::endl; - rHomePath = QDir::isRelativePath(AppDirs::rHomeDir()) ? programDir().absoluteFilePath(AppDirs::rHomeDir()) : AppDirs::rHomeDir(); -} -#endif - - return rHomePath; -} - -QDir AppDirs::programDir() -{ - return QFileInfo( QCoreApplication::applicationFilePath() ).absoluteDir(); -} - -//After getting an error on giving "consent" to renv to do stuff I checked the page https://rstudio.github.io/renv/reference/paths.html -//I think it would be good to make sure the root-renv folder is also within the appdata of JASP and not in their own, because then we would be partially clobbering users own renv stuff -QString AppDirs::renvRootLocation() -{ - const char * renvRootName = "renv"; - - QDir(appData()).mkpath(renvRootName); //create it if missing - - return appData() + "/" + renvRootName; -} - -QString AppDirs::renvCacheLocations() -{ - const char * renvCacheName = "cache"; - - QDir(renvRootLocation()).mkpath(renvCacheName); //create it if missing - - QString dynamicCache = renvRootLocation() + "/" + renvCacheName, - staticCache = processPath(programDir().absoluteFilePath("Modules/renv-cache")); - - const QChar separator = -#ifdef WIN32 - ';'; -#else - ':'; -#endif - - return dynamicCache + separator + staticCache; - -} diff --git a/Common/QtUtils/appdirs.h b/Common/QtUtils/appdirs.h deleted file mode 100644 index 5b01693e42d..00000000000 --- a/Common/QtUtils/appdirs.h +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . - - -// -// NOTICE: -// `appdirs.h` is generated from `appdirs.h.in` and you should edit -// that file instead if you want your changes to reflect in the app -// - -#ifndef APPDIRS_H -#define APPDIRS_H - -#include -#include - -/// collector class with functions that make the locations of relevannt folders available -/// Uses Qt so can't be used in R-Interface. -class AppDirs -{ -public: - - static QString examples(); - static QString help(); - static QString analysisDefaultsDir(); - static QString userRLibrary(); - static QString userModulesDir(); - static QString bundledModulesDir(); - static QString documents(); - static QString logDir(); - static QString appData(bool roaming = true); - static QString rHome(); - static QDir programDir(); - static QString renvRootLocation(); - static QString renvCacheLocations(); - -private: - static QString processPath(const QString & path); - -#ifdef linux - static QString rHomeDir() { - return QString("/Users/brunoboutin/JASP/source/build-jasp-desktop-Qt_6_5_2_for_macOS-Debug/Frameworks/R.framework/Versions/4.3-arm64/Resources"); - } -#endif -}; - -#endif // APPDIRS_H diff --git a/Common/QtUtils/appdirs.h.in b/Common/QtUtils/appdirs.h.in deleted file mode 100644 index 5ca774eb7a6..00000000000 --- a/Common/QtUtils/appdirs.h.in +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . - - -// -// NOTICE: -// `appdirs.h` is generated from `appdirs.h.in` and you should edit -// that file instead if you want your changes to reflect in the app -// - -#ifndef APPDIRS_H -#define APPDIRS_H - -#include -#include - -/// collector class with functions that make the locations of relevannt folders available -/// Uses Qt so can't be used in R-Interface. -class AppDirs -{ -public: - - static QString examples(); - static QString help(); - static QString analysisDefaultsDir(); - static QString userRLibrary(); - static QString userModulesDir(); - static QString bundledModulesDir(); - static QString documents(); - static QString logDir(); - static QString appData(bool roaming = true); - static QString rHome(); - static QDir programDir(); - static QString renvRootLocation(); - static QString renvCacheLocations(); - -private: - static QString processPath(const QString & path); - -#ifdef linux - static QString rHomeDir() { - return QString("@R_HOME_PATH@"); - } -#endif -}; - -#endif // APPDIRS_H diff --git a/Common/QtUtils/dynamicruntimeinfo.cpp b/Common/QtUtils/dynamicruntimeinfo.cpp deleted file mode 100644 index ea31e54e589..00000000000 --- a/Common/QtUtils/dynamicruntimeinfo.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "dynamicruntimeinfo.h" -#include "json/json.h" -#include "appinfo.h" -#include "appdirs.h" -#include "log.h" -#include "qutils.h" - -#include -#include - - -DynamicRuntimeInfo* DynamicRuntimeInfo::_instance = nullptr; -const std::string DynamicRuntimeInfo::staticInfoFileName = "staticRuntimeInfo.json"; -const std::string DynamicRuntimeInfo::dynamicInfoFileName = "dynamicRuntimeInfo.json"; - -DynamicRuntimeInfo *DynamicRuntimeInfo::getInstance() -{ - if(!_instance) - _instance = new DynamicRuntimeInfo(); - return _instance; -} - -bool DynamicRuntimeInfo::bundledModulesInitialized() -{ - bool res = true; - - if(_environment == RuntimeEnvironment::MSI || _environment == RuntimeEnvironment::MSIX || _environment == RuntimeEnvironment::ZIP) - res = _bundledModulesInitializedSet - && _initializedByCommit == AppInfo::gitCommit - && _initializedByBuildDate == AppInfo::builddate - && _initializedForRVersion == AppInfo::getRVersion() - && _initializedForJaspVersion == AppInfo::version.asString(4); - - return res; -} - -DynamicRuntimeInfo::DynamicRuntimeInfo() -{ -#ifdef FLATPAK_USED - _environment = RuntimeEnvironment::FLATPAK; -#elif __APPLE__ - _environment = RuntimeEnvironment::MAC; -#elif linux - _environment = RuntimeEnvironment::LINUX_LOCAL; -#elif _WIN32 - parseStaticRuntimeInfoFile(staticRuntimeInfoFilePath()); //will set runtime env info - parseDynamicRuntimeInfoFile(dynamicRuntimeInfoFilePath()); -#else - _environment = RuntimeEnvironment::UNKNOWN; -#endif - - -#if defined(__aarch64__) - _arch = MicroArch::AARCH64; -#elif defined(__x86_64__) || defined(_M_X64) - _arch = MicroArch::X86_64; -#else - _arch = MicroArch::UNSUPPORTED; -#endif -} - -bool DynamicRuntimeInfo::parseStaticRuntimeInfoFile(const std::string &path) -{ - Log::log() << "Attempting to read static runtime information from: " + path << std::endl; - std::ifstream in(path, std::ifstream::in); - if(!in) - { - _environment = RuntimeEnvironment::UNKNOWN; - Log::log() << "Failed to open specified static runtime file" << std::endl; - return false; - } - - Json::Value root; - in >> root; - - std::string runtimeEnvironmentString = root.get("runtimeEnvironment", "").asString(); - auto it = StringToRuntimeEnvironmentMap.find(runtimeEnvironmentString); - if(it == StringToRuntimeEnvironmentMap.end()) - _environment = RuntimeEnvironment::UNKNOWN; - else - _environment = it->second; - - return true; -} - -bool DynamicRuntimeInfo::parseDynamicRuntimeInfoFile(const std::string &path) -{ - Log::log() << "Attempting to read dynamic runtime information from: " + path << std::endl; - std::ifstream in(path, std::ifstream::in); - if(!in) - { - _bundledModulesInitializedSet = false; - Log::log() << "Failed to open specified dynamic runtime file or it may simply not exist yes" << std::endl; - return false; - } - - Json::Value root; - in >> root; - - _bundledModulesInitializedSet = root.get("initialized", false).asBool(); - _initializedByCommit = root.get("commit", "").asString(); - _initializedByBuildDate = root.get("buildDate", "").asString(); - _initializedForRVersion = root.get("RVersion", "").asString(); - _initializedForJaspVersion = root.get("jaspVersion", "").asString(); - _initializedOn = root.get("initTimestamp", 0).asUInt64(); - - return true; - -} - -std::string DynamicRuntimeInfo::staticRuntimeInfoFilePath() -{ - return fq(AppDirs::programDir().absoluteFilePath(tq(staticInfoFileName))); -} - -std::string DynamicRuntimeInfo::dynamicRuntimeInfoFilePath() -{ - switch (getRuntimeEnvironment()) { - case ZIP: - return fq(AppDirs::programDir().absoluteFilePath(tq(dynamicInfoFileName))); - case MSIX: - return fq(AppDirs::appData(false) + "/" + tq(dynamicInfoFileName)); - default: - return ""; - } -} - -bool DynamicRuntimeInfo::writeDynamicRuntimeInfoFile() -{ - std::string path = dynamicRuntimeInfoFilePath(); - std::ofstream out(path, std::ofstream::out); - if(!out) - { - Log::log() << "Failed to open specified path for writing dynamic runtime info file" << std::endl; - return false; - } - - Json::Value root; - root["jaspVersion"] = AppInfo::version.asString(4); - root["initialized"] = true; - root["commit"] = AppInfo::gitCommit; - root["buildDate"] = AppInfo::builddate; - root["RVersion"] = AppInfo::getRVersion(); - uint64_t timestamp = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1); - root["initTimestamp"] = timestamp; - - out << root; - return true; -} - -DynamicRuntimeInfo::RuntimeEnvironment DynamicRuntimeInfo::getRuntimeEnvironment() -{ - return _environment; -} - -std::string DynamicRuntimeInfo::getRuntimeEnvironmentAsString() -{ - auto x = RuntimeEnvironmentToStringMap.find(_environment); - return x != RuntimeEnvironmentToStringMap.end() ? x->second : RuntimeEnvironmentToStringMap.find(UNKNOWN)->second; -} - -uint64_t DynamicRuntimeInfo::bundledModulesInitializedOnTimestamp() -{ - return _initializedOn; -} - -std::string DynamicRuntimeInfo::bundledModulesInitializedByCommit() -{ - return _initializedByCommit; -} - -std::string DynamicRuntimeInfo::bundledModulesInitializedByBuildDate() -{ - return _initializedByBuildDate; -} - -std::string DynamicRuntimeInfo::bundledModulesInitializedRVersion() -{ - return _initializedForRVersion; -} - -std::string DynamicRuntimeInfo::bundledModulesInitializedJaspVersion() -{ - return _initializedForJaspVersion; -} diff --git a/Common/QtUtils/dynamicruntimeinfo.h b/Common/QtUtils/dynamicruntimeinfo.h deleted file mode 100644 index d24e8580f8a..00000000000 --- a/Common/QtUtils/dynamicruntimeinfo.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef DYNRUNTIMEINFO_H -#define DYNRUNTIMEINFO_H - -/*! - * Simple class that parses Runtime information from staticRuntimeInfo.json located in the install folder - * and dynamicRuntimeInfo.json located in a user directory defined by Appdirs. - * staticRuntimeInfo.json containts information on install type. - * dynamicRuntimeInfo.json is used to log various information regarding the initialization of the environment. e.g. at first run - * This class is used to query runtime information and to determine if there has been proper initialization for this JASP version. -*/ - -#include -#include -#include - -class DynamicRuntimeInfo -{ -public: - enum RuntimeEnvironment{ ZIP, MSIX, MSI, R, FLATPAK, MAC, LINUX_LOCAL, UNKNOWN }; - const std::map StringToRuntimeEnvironmentMap = { - {"ZIP", RuntimeEnvironment::ZIP}, {"MSIX", RuntimeEnvironment::MSIX}, - {"MSI", RuntimeEnvironment::MSI}, {"R", RuntimeEnvironment::R}, - {"FLATPAK", RuntimeEnvironment::FLATPAK}, {"MAC", RuntimeEnvironment::MAC}, - {"LINUX_LOCAL", RuntimeEnvironment::LINUX_LOCAL}, {"UNKNOWN", RuntimeEnvironment::UNKNOWN}, - }; - const std::map RuntimeEnvironmentToStringMap = { - {RuntimeEnvironment::ZIP, "ZIP"}, {RuntimeEnvironment::MSIX, "MSIX"}, - {RuntimeEnvironment::MSI, "MSI"}, {RuntimeEnvironment::R, "R"}, - {RuntimeEnvironment::FLATPAK, "FLATPAK"}, {RuntimeEnvironment::MAC, "MAC"}, - {RuntimeEnvironment::LINUX_LOCAL, "LINUX_LOCAL"}, {RuntimeEnvironment::UNKNOWN, "UNKNOWN"}, - }; - - enum MicroArch{ AARCH64, X86_64, UNSUPPORTED }; - - bool bundledModulesInitialized(); - - RuntimeEnvironment getRuntimeEnvironment(); - std::string getRuntimeEnvironmentAsString(); - RuntimeEnvironment getMicroArch(); - uint64_t bundledModulesInitializedOnTimestamp(); - std::string bundledModulesInitializedByCommit(); - std::string bundledModulesInitializedByBuildDate(); - std::string bundledModulesInitializedRVersion(); - std::string bundledModulesInitializedJaspVersion(); - - bool writeDynamicRuntimeInfoFile(); - - //singleton stuff - static DynamicRuntimeInfo* getInstance(); - DynamicRuntimeInfo(DynamicRuntimeInfo& other) = delete; - void operator=(const DynamicRuntimeInfo&) = delete; - -protected: - DynamicRuntimeInfo(); - - bool parseStaticRuntimeInfoFile(const std::string& path); - bool parseDynamicRuntimeInfoFile(const std::string& path); - -private: - std::string staticRuntimeInfoFilePath(); - std::string dynamicRuntimeInfoFilePath(); - - RuntimeEnvironment _environment; - MicroArch _arch; - - bool _bundledModulesInitializedSet = true; - std::string _initializedByCommit = "build"; - std::string _initializedForRVersion = "build"; - std::string _initializedByBuildDate = "build"; - std::string _initializedForJaspVersion = "build"; - uint64_t _initializedOn = 0; - - static DynamicRuntimeInfo* _instance; - - static const std::string staticInfoFileName; - static const std::string dynamicInfoFileName; -}; - -#endif // DYNRUNTIMEINFO_H diff --git a/Common/QtUtils/jsonutilities.cpp b/Common/QtUtils/jsonutilities.cpp deleted file mode 100644 index a46b56964a4..00000000000 --- a/Common/QtUtils/jsonutilities.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "jsonutilities.h" - -std::set JsonUtilities::convertDragNDropFilterJSONToSet(std::string jsonStr) -{ - std::set returnThis; - - Json::Value json; - Json::Reader().parse(jsonStr, json); - - std::stack jsonStack; - jsonStack.push(json); - - while(jsonStack.size() > 0) - { - Json::Value cur = jsonStack.top(); - jsonStack.pop(); - - if(cur.isArray()) - for(int i=0; i & columnNames) -{ - return removeColumnsFromDragNDropFilterJSONStr(jsonStr, std::set(columnNames.begin(), columnNames.end())); -} - -std::string JsonUtilities::removeColumnsFromDragNDropFilterJSONStr(const std::string & jsonStr, const std::set & columnNames) -{ - Json::Value json; - Json::Reader().parse(jsonStr, json); - - removeColumnsFromDragNDropFilterJSON(json, columnNames); - - return json.toStyledString(); -} - -void JsonUtilities::removeColumnsFromDragNDropFilterJSONRef(Json::Value & json, const std::vector & columnNames) -{ - removeColumnsFromDragNDropFilterJSONRef(json, std::set(columnNames.begin(), columnNames.end())); -} - -void JsonUtilities::removeColumnsFromDragNDropFilterJSONRef(Json::Value & json, const std::set & columnNames) -{ - if(json.isArray()) - for(int i=0; i 0) - json = Json::nullValue; - else - for(auto & key : json.getMemberNames()) - removeColumnsFromDragNDropFilterJSONRef(json[key], columnNames); - } -} - -Json::Value JsonUtilities::removeColumnsFromDragNDropFilterJSON(const Json::Value &json, const stringset &columnNames) -{ - Json::Value changeThisThen = json; - removeColumnsFromDragNDropFilterJSONRef(changeThisThen, columnNames); - return changeThisThen; -} - -Json::Value JsonUtilities::removeColumnsFromDragNDropFilterJSON(const Json::Value &json, const stringvec &columnNames) -{ - Json::Value changeThisThen = json; - removeColumnsFromDragNDropFilterJSONRef(changeThisThen, columnNames); - return changeThisThen; -} - -std::string JsonUtilities::replaceColumnNamesInDragNDropFilterJSONStr(const std::string & jsonStr, const std::map & changeNameColumns) -{ - Json::Value json; - Json::Reader().parse(jsonStr, json); - - replaceColumnNamesInDragNDropFilterJSON(json, changeNameColumns); - - return json.toStyledString(); -} - -void JsonUtilities::replaceColumnNamesInDragNDropFilterJSONRef(Json::Value & json, const std::map & changeNameColumns) -{ - if(json.isArray()) - for(int i=0; i 0) - json["columnName"] = changeNameColumns.at(json["columnName"].asString()); - else - for(auto & key : json.getMemberNames()) - replaceColumnNamesInDragNDropFilterJSONRef(json[key], changeNameColumns); - } -} - -Json::Value JsonUtilities::replaceColumnNamesInDragNDropFilterJSON(const Json::Value &json, const strstrmap &changeNameColumns) -{ - Json::Value changeThisThen = json; - replaceColumnNamesInDragNDropFilterJSONRef(changeThisThen, changeNameColumns); - return changeThisThen; -} - -stringvec JsonUtilities::jsonStringArrayToVec(const Json::Value & jsonStrings) -{ - if(!jsonStrings.isArray()) throw std::runtime_error("jsonStringArrayToVec expected array!"); - - stringvec out; - out.reserve(jsonStrings.size()); - - for(const Json::Value & entry: jsonStrings) - if(!entry.isString()) throw std::runtime_error("jsonStringArrayToVec expected array of strings!"); - else out.push_back(entry.asString()); - - return out; -} diff --git a/Common/QtUtils/jsonutilities.h b/Common/QtUtils/jsonutilities.h deleted file mode 100644 index 2dc3df09a99..00000000000 --- a/Common/QtUtils/jsonutilities.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef JSONUTILITIES_H -#define JSONUTILITIES_H - -#include -#include -#include -#include -#include "utils.h" -#include "qutils.h" - -/// There are recurring needs when working with Json::Value etc and these are collected here. -/// For instance converting from and to a std::vector is useful and might as well be written here. -/// The function vecToJsonArray for instance handles inf or nan occuring in double, because json doesn't support it... -class JsonUtilities -{ -public: - static std::set convertDragNDropFilterJSONToSet(std::string jsonStr); - - static std::string removeColumnsFromDragNDropFilterJSONStr( const std::string & jsonStr, const stringset & columnNames); - static void removeColumnsFromDragNDropFilterJSONRef( Json::Value & json, const stringset & columnNames); - static Json::Value removeColumnsFromDragNDropFilterJSON( const Json::Value & json, const stringset & columnNames); - static std::string removeColumnsFromDragNDropFilterJSONStr( const std::string & jsonStr, const stringvec & columnNames); - static void removeColumnsFromDragNDropFilterJSONRef( Json::Value & json, const stringvec & columnNames); - static Json::Value removeColumnsFromDragNDropFilterJSON( const Json::Value & json, const stringvec & columnNames); - - static std::string replaceColumnNamesInDragNDropFilterJSONStr( const std::string & jsonStr, const strstrmap & changeNameColumns); - static void replaceColumnNamesInDragNDropFilterJSONRef( Json::Value & json, const strstrmap & changeNameColumns); - static Json::Value replaceColumnNamesInDragNDropFilterJSON( const Json::Value & json, const strstrmap & changeNameColumns); - - static stringvec jsonStringArrayToVec(const Json::Value & jsonStrings); - - template - static Json::Value vecToJsonArray(const std::vector & vec) - { - Json::Value out = Json::arrayValue; - - for(const T & e : vec) out.append(e); - - return out; - } - - static Json::Value vecToJsonArray(const std::vector vec) - { - Json::Value out = Json::arrayValue; - - for(const double & v : vec) - if(std::isnan(v) || std::isinf(v)) out.append(Json::nullValue); //Json does not support inf or nan... Sigh... - else out.append(v); - - return out; - } - - static Json::Value vecToJsonArray(const std::vector & vec) - { - Json::Value out = Json::arrayValue; - - for(const QString & e : vec) out.append(fq(e)); - - return out; - } - - -private: - JsonUtilities() {} -}; - -#endif // JSONUTILITIES_H diff --git a/Common/QtUtils/knownissues.cpp b/Common/QtUtils/knownissues.cpp deleted file mode 100644 index 589d5bc5a3b..00000000000 --- a/Common/QtUtils/knownissues.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "knownissues.h" -//#include "messageforwarder.h" -#include "appinfo.h" -#include "jsonutilities.h" -#include "log.h" -#include "appdirs.h" -#include "utils.h" -#include - - -//Check every day? -#define EXPIRATION_TIME_SEC 60 * 60 * 24 - -// https://www.youtube.com/watch?v=REWeBzGuzCc -KnownIssues * KnownIssues::_knownIssues = nullptr; - -KnownIssues::KnownIssues(QObject * parent) : QObject(parent) -{ - assert(!_knownIssues); - _knownIssues = this; -} - -void KnownIssues::loadLocalJson(const std::string & filePath, bool saveIt) -{ - std::ifstream readMe(filePath); - - Json::Value json; - Json::Reader().parse(readMe, json); - - loadJson(json, saveIt); -} - -void KnownIssues::loadJson(const std::string & jsonTxt, bool saveIt) -{ - if(jsonTxt == "") - { - Log::log() << "## " << tr("Problem loading known issues") << "\n" << tr("JASP ran into a problem downloading the known issues for this version, it probably could not connect to the server. Don't worry, JASP will work fine it just might not tell you about a few small known issues.") << std::endl; -#if JASP_DEBUG -// MessageForwarder::showWarning("Known issues from server was empty!"); -#endif - return; - } - - Json::Value known; - if(Json::Reader().parse(jsonTxt, known)) - loadJson(known, saveIt); - else - { - Log::log() << "## " << tr("Problem loading known issues") << "\n" << tr("JASP ran into a problem loading the known issues for this version, this isn't necessarily a problem but if it keeps occuring you could contact the JASP team for assistance.") << std::endl; -#if JASP_DEBUG -// MessageForwarder::showWarning("Known issues could not be parsed!"); -#endif - } -} - - -void KnownIssues::loadJson(const Json::Value & json, bool saveIt) -{ - _issues.clear(); - - try - { - if(!json.isObject()) throw std::runtime_error("expected issues json to be an object"); - - const std::string version = AppInfo::version.asString(); - - if(json.isMember(version)) - for( const std::string & module : json[version] .getMemberNames()) - for( const std::string & analysis : json[version][module] .getMemberNames()) - { - const Json::Value & perAnalysis = json[version][module][analysis]; - - if(perAnalysis.isObject()) addIssue(module, analysis, perAnalysis); - if(perAnalysis.isArray()) - for(const Json::Value & entry : perAnalysis) - addIssue(module, analysis, entry); - } - } - catch(const std::exception & e) - { - Log::log() << "## " << tr("Problem loading known issues") << "\n" << tr("JASP ran into a problem ('%1') loading the known issues for this version, this isn't necessarily a problem but if it keeps occuring you could contact the JASP team for assistance.").arg(e.what()) << std::endl; -#if JASP_DEBUG -// MessageForwarder::showWarning(QString("Loading known issues had exception: '%1'!").arg(e.what())); -#endif - } - - emit knownIssuesUpdated(); - - if(saveIt) - { - std::ofstream saveHere(knownJsonPath()); - saveHere << json; - saveHere.close(); - } -} - -std::string KnownIssues::knownJsonPath() const -{ - return fq(AppDirs::appData()) + "/knownIssues.json"; -} - -void KnownIssues::loadKnownJson() -{ - loadLocalJson(knownJsonPath(), false); -} - -bool KnownIssues::knownJsonExpired() const -{ - std::filesystem::path knownJson = std::filesystem::path(knownJsonPath()); - - if(!std::filesystem::exists(knownJson)) - return true; - - long modTime = Utils::getFileModificationTime(Utils::osPath(knownJson)); - long now = Utils::currentSeconds(); - - return now - modTime > EXPIRATION_TIME_SEC; -} - -void KnownIssues::addIssue(const std::string & module, const std::string & analysis, const Json::Value & issueJson) -{ - issue newIssue; - - newIssue.info = issueJson["info"].asString(); - Json::Value options = issueJson.get("options", Json::arrayValue); - - switch(options.type()) - { - case Json::stringValue: newIssue.options.insert(options.asString()); break; - case Json::arrayValue: - { - stringvec vec = JsonUtilities::jsonStringArrayToVec(options); - newIssue.options = stringset(vec.begin(), vec.end()); - break; - } - default: Log::log() << "KnownIssues::addIssue got unexpected type for \"options\", so ignoring it." << std::endl; - } - - _issues[module][analysis].push_back(newIssue); -} - -bool KnownIssues::hasIssues(const std::string & module, const std::string & analysis) -{ - return _issues.count(module) > 0 && _issues[module].count(analysis) > 0; -} - -bool KnownIssues::hasIssues(const std::string & module, const std::string & analysis, const std::string & option) -{ - if(!hasIssues(module, analysis)) return false; - - for(const issue & anIssue : _issues[module][analysis]) - if(anIssue.options.count(option) > 0) - return true; - - return false; -} - -std::string KnownIssues::issuesForAnalysis(const std::string & module, const std::string & analysis) -{ - if(!hasIssues(module, analysis)) return ""; - - std::stringstream out; - - out << "
    "; - - for(const issue & anIssue : _issues[module][analysis]) - out << "
  • " << anIssue.info << "
  • \n"; - - out << "
"; - - return out.str(); -} - -bool KnownIssues::downloadNeededOrLoad() -{ - if(knownJsonExpired()) - return true; - - loadKnownJson(); - return false; -} diff --git a/Common/QtUtils/knownissues.h b/Common/QtUtils/knownissues.h deleted file mode 100644 index cfbd2ef4972..00000000000 --- a/Common/QtUtils/knownissues.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef KNOWNISSUES_H -#define KNOWNISSUES_H - -#include -#include -#include "qutils.h" -#include "stringutils.h" - -/// -/// This class stores information per module and analysis that is pulled from the server occasionally (in JaspVersionChecker) -/// When the user adds an analysis it checks whether we have found a serious issue and posted it to our server. Which allows us to show a message in the qml form -/// Mentioning the problem and that we are working on it. -/// This way people can be informed of problems with an analysis and they won't try to publish faulty results (in the worst case). -class KnownIssues : public QObject -{ - Q_OBJECT - -public: - struct issue - { - std::string info; - stringset options; - }; - - typedef std::map> issuesPerAnalysis; - typedef std::map issuesPerModule; - - explicit KnownIssues(QObject *parent = nullptr); - - static KnownIssues * issues() { return _knownIssues; } - - bool downloadNeededOrLoad(); - - void loadJson(const Json::Value & json, bool saveIt); - void loadJson(const std::string & jsonTxt, bool saveIt); - void loadJson(const QString & jsonTxt, bool saveIt) { loadJson(fq(jsonTxt), saveIt); } - - bool hasIssues( const std::string & module, const std::string & analysis); - bool hasIssues( const std::string & module, const std::string & analysis, const std::string & option); - std::string issuesForAnalysis( const std::string & module, const std::string & analysis); - - bool hasIssues( const QString & module, const QString & analysis) { return hasIssues( fq(module), fq(analysis) ); } - bool hasIssues( const QString & module, const QString & analysis, const QString & option) { return hasIssues( fq(module), fq(analysis), fq(option) ); } - QString issuesForAnalysis( const QString & module, const QString & analysis) { return tq(issuesForAnalysis( fq(module), fq(analysis) )); } - - const std::vector & getIssues( const std::string & module, const std::string & analysis) { return _issues[module][analysis]; } - const std::vector & getIssues( const QString & module, const QString & analysis) { return getIssues(fq(module), fq(analysis)); } - -signals: - void knownIssuesUpdated(); - -private: - bool knownJsonExpired() const; - std::string knownJsonPath() const; - void loadKnownJson(); - - void loadLocalJson( const std::string & filePath, bool saveIt); - void addIssue( const std::string & module, const std::string & analysis, const Json::Value & issue); - -private: - issuesPerModule _issues; - static KnownIssues * _knownIssues; -}; - -#endif // KNOWNISSUES_H diff --git a/Common/QtUtils/qutils.cpp b/Common/QtUtils/qutils.cpp deleted file mode 100644 index caadf06c2ad..00000000000 --- a/Common/QtUtils/qutils.cpp +++ /dev/null @@ -1,275 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "qutils.h" -#include -#include -#include -#include -#include -#include "log.h" -#include "appinfo.h" -#include "simplecrypt.h" -#include "log.h" -#include "utils.h" - - -using namespace std; - -QStringList tql(const std::vector &from) -{ - QStringList result; - - for(const std::string &str : from) - result.append(tq(str)); - - return result; -} - -QString stripFirstAndLastChar(QString result, const QString &strip) -{ - if (result.left(1) == strip) result.remove(0,1); - if (result.right(1) == strip) result.remove(result.length()-1,1); - return result; -} - -QString getShortCutKey() -{ -#ifdef __APPLE__ - QString shortCutKey = "\u2318"; -#else - QString shortCutKey = "Ctrl"; -#endif - return shortCutKey; -} - -QString encrypt(const QString &input) -{ - long long key = AppInfo::getSimpleCryptKey(); - SimpleCrypt crypto(key); //some random number - - return crypto.encryptToString(input); -} - -QString decrypt(const QString &input) -{ - long long key = AppInfo::getSimpleCryptKey(); - SimpleCrypt crypto(key); //some random number - - return crypto.decryptToString(input); -} - -QString getSortableTimestamp() -{ - return QDateTime::currentDateTime().toString("yyyy-MM-dd hh_mm_ss"); //This order gets an easy alphanumeric sort by default and sadly enough the character : is not allowed on unix/macx -} - -QVector tq(const std::vector & vec) -{ - std::vector out; - out.reserve(vec.size()); - for(const std::string & s : vec) - out.push_back(tq(s)); - - return QVector{out.begin(), out.end()}; -} - -std::vector fq(const QVector & vec) -{ - std::vector out; - out.reserve(static_cast(vec.size())); - - for(const QString & s : vec) - out.push_back(fq(s)); - - return out; - -} - -std::map fq(const QMap & map) -{ - std::map out; - - for(const auto & keyval : map.toStdMap()) - out[fq(keyval.first)] = fq(keyval.second); - - return out; -} - -QMap tq(const std::map & map) -{ - QMap out; - - for(const auto & keyval : map) - out[tq(keyval.first)] = tq(keyval.second); - - return out; -} - - -const char * QProcessErrorToString(QProcess::ProcessError error) -{ - switch(error) - { - case QProcess::ProcessError::Crashed: return "Crashed"; - case QProcess::ProcessError::Timedout: return "Timedout"; - case QProcess::ProcessError::ReadError: return "ReadError"; - case QProcess::ProcessError::WriteError: return "WriteError"; - case QProcess::ProcessError::UnknownError: return "UnknownError"; - case QProcess::ProcessError::FailedToStart: return "FailedToStart"; - }; - return "???"; -} - -bool pathIsSafeForR(const QString & checkThis) -{ - return checkThis.toLocal8Bit() == checkThis.toUtf8(); -} - -Json::Value fqj(const QJSValue & jsVal) -{ - if(jsVal.isNull()) return Json::nullValue; - if(jsVal.isBool()) return jsVal.toBool(); - if(jsVal.isNumber()) return jsVal.toNumber(); - if(jsVal.isString()) return fq(jsVal.toString()); - - if(jsVal.isArray()) - { - Json::Value json = Json::arrayValue; - const size_t length = jsVal.property("length").toUInt(); - - for(size_t i=0; iengine()->newArray(json.size()); - - for(auto i=0; iengine()->newObject(); - - for(const std::string & member : json.getMemberNames()) - obj.setProperty(tq(member), tqj(json[member], qItem)); - - return obj; - } - } - - return QJSValue(QJSValue::SpecialValue::NullValue); //In case some compiler doesnt get that I covered everything already. -} - -QString QJSErrorToString(QJSValue::ErrorType errorType) -{ - switch(errorType) - { - default: - case QJSValue::ErrorType::GenericError: return "A non-specific error..."; - case QJSValue::ErrorType::RangeError: return "A value did not match the expected set or range."; - case QJSValue::ErrorType::ReferenceError: return "A non-existing variable referenced."; - case QJSValue::ErrorType::SyntaxError: return "An invalid token or sequence of tokens was encountered that does not conform with the syntax of the language."; - case QJSValue::ErrorType::TypeError: return "An operand or argument is incompatible with the type expected."; - case QJSValue::ErrorType::URIError: return "A URI handling function was used incorrectly or the URI provided is malformed."; - } - - return "Could not determine error from type."; -} - -QString shortenWinPaths(QString in) -{ -#ifdef _WIN32 - return QString::fromStdWString(Utils::getShortPathWin(in.toStdWString())); -#else - return in; -#endif -} - -void copyQDirRecursively(QDir copyThis, QDir toHere) -{ - toHere.mkpath("."); - - const QString copyThisRootPath = copyThis.absolutePath() + "/"; - - - QDirIterator goDeep(copyThis, QDirIterator::Subdirectories); - - QString filePath, postfix; - QFileInfo fileInfo; - - while(goDeep.hasNext()) - { - fileInfo = goDeep.nextFileInfo(); - filePath = fileInfo.absoluteFilePath(); - postfix = filePath.right(filePath.size() - copyThisRootPath.size()); - - if(fileInfo.isFile()) - { - QFile nextFile(filePath); - - if(filePath.size() <= copyThis.absolutePath().size()) - Log::log() << "copyQDirRecursively 'toHere' filePath was smaller than 'copyThis' path... ???" << std::endl; - else - { - nextFile.copy(toHere.absoluteFilePath(postfix)); - } - } - else if(fileInfo.isDir() && !fileInfo.isHidden()) - { - toHere.mkpath(postfix); - } - - } - - -} diff --git a/Common/QtUtils/qutils.h b/Common/QtUtils/qutils.h deleted file mode 100644 index 8d1b89c8102..00000000000 --- a/Common/QtUtils/qutils.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef QUTILS_H -#define QUTILS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/// This file collect a set of useful functions for interop between Qt and stdlib, like `fq` and `tq` for easily converting to and fro normal strings and whatnot -/// These could have been collected into a class but because we use `fq` and `tq` in so many places that would probably not have made our life easier anyway. - -enum Encryption { NoEncryption, SimpleCryptEncryption }; - -//fq -> fromQt, tq -> toQt -//tql -> toQtList (the tql is reasonable for going from a set to a vector because Qt no doubt has a QSet or something as well, which would then be reached through tq if we ever need it) -//fqj and tqj are for from/to QtJson -inline std::string fq (const QString & from) { return from.toUtf8().toStdString(); } - std::vector fq (const QVector & vec); - std::map fq (const QMap & map); - QMap tq (const std::map & map); -inline QString tq (const std::string & from) { return QString::fromUtf8(from.c_str(), from.length()); } - QVector tq (const std::vector & vec); -inline QStringList tql(const std::set & from) { return tq(std::vector(from.begin(), from.end())); } - - //These need to have a different name because otherwise the default Json::Value(const std::string & str) constructor steals any fq(std::string()) call... - Json::Value fqj(const QJSValue & jsVal); - QJSValue tqj(const Json::Value & json, const QQuickItem * qItem); - -template inline std::vector fq(QVector in) { return in.toStdVector(); } -template inline QVector tq(std::vector in) { return QVector::fromStdVector(in); } - -QString stripFirstAndLastChar(QString in, const QString &strip); -QString getShortCutKey(); -QString encrypt(const QString &input); -QString decrypt(const QString &input); -QString getSortableTimestamp(); -QString QJSErrorToString(QJSValue::ErrorType errorType); - -void copyQDirRecursively(QDir copyThis, QDir toHere); - -QString shortenWinPaths(QString); - -bool pathIsSafeForR(const QString & checkThis); - -const char * QProcessErrorToString(QProcess::ProcessError error); - -inline std::ostream& operator<<(std::ostream& os, const QString & qStr) { return (os << qStr.toStdString()); } - -#define GENERIC_SET_FUNCTION(WHAT_TO_SET, VARIABLE_TO_SET, EMIT_THIS, TYPE) \ -void set##WHAT_TO_SET(TYPE new##WHAT_TO_SET) \ -{ \ - if(new##WHAT_TO_SET != VARIABLE_TO_SET) \ - { \ - VARIABLE_TO_SET = new##WHAT_TO_SET; \ - emit EMIT_THIS(); \ - } \ -} - - - -#endif // QUTILS_H diff --git a/Common/QtUtils/simplecrypt.cpp b/Common/QtUtils/simplecrypt.cpp deleted file mode 100644 index bb407d1c448..00000000000 --- a/Common/QtUtils/simplecrypt.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* -Copyright (c) 2011, Andre Somers -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Rathenau Instituut, Andre Somers nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR #######; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#include "simplecrypt.h" -#include -#include -#include -#include -#include -#include - -SimpleCrypt::SimpleCrypt(): - m_key(0), - m_compressionMode(CompressionAuto), - m_protectionMode(ProtectionChecksum), - m_lastError(ErrorNoError) -{ - std::srand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF)); -} - -SimpleCrypt::SimpleCrypt(quint64 key): - m_key(key), - m_compressionMode(CompressionAuto), - m_protectionMode(ProtectionChecksum), - m_lastError(ErrorNoError) -{ - std::srand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF)); - splitKey(); -} - -void SimpleCrypt::setKey(quint64 key) -{ - m_key = key; - splitKey(); -} - -void SimpleCrypt::splitKey() -{ - m_keyParts.clear(); - m_keyParts.resize(8); - for (int i=0;i<8;i++) { - quint64 part = m_key; - for (int j=i; j>0; j--) - part = part >> 8; - part = part & 0xff; - m_keyParts[i] = static_cast(part); - } -} - -QByteArray SimpleCrypt::encryptToByteArray(const QString& plaintext) -{ - QByteArray plaintextArray = plaintext.toUtf8(); - return encryptToByteArray(plaintextArray); -} - -QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) -{ - if (m_keyParts.isEmpty()) { - qWarning() << "No key set."; - m_lastError = ErrorNoKeySet; - return QByteArray(); - } - - - QByteArray ba = plaintext; - - CryptoFlags flags = CryptoFlagNone; - if (m_compressionMode == CompressionAlways) { - ba = qCompress(ba, 9); //maximum compression - flags |= CryptoFlagCompression; - } else if (m_compressionMode == CompressionAuto) { - QByteArray compressed = qCompress(ba, 9); - if (compressed.length() < ba.length()) { - ba = compressed; - flags |= CryptoFlagCompression; - } - } - - QByteArray integrityProtection; - if (m_protectionMode == ProtectionChecksum) { - flags |= CryptoFlagChecksum; - QDataStream s(&integrityProtection, QIODeviceBase::WriteOnly); - QByteArrayView v(ba); - s << qChecksum(v); - } else if (m_protectionMode == ProtectionHash) { - flags |= CryptoFlagHash; - QCryptographicHash hash(QCryptographicHash::Sha1); - hash.addData(ba); - - integrityProtection += hash.result(); - } - - //prepend a random char to the string - char randomChar = char(std::rand() & 0xFF); - ba = randomChar + integrityProtection + ba; - - int pos(0); - char lastChar(0); - - int cnt = ba.length(); - - while (pos < cnt) { - ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar; - lastChar = ba.at(pos); - ++pos; - } - - QByteArray resultArray; - resultArray.append(char(0x03)); //version for future updates to algorithm - resultArray.append(char(flags)); //encryption flags - resultArray.append(ba); - - m_lastError = ErrorNoError; - return resultArray; -} - -QString SimpleCrypt::encryptToString(const QString& plaintext) -{ - QByteArray plaintextArray = plaintext.toUtf8(); - QByteArray cypher = encryptToByteArray(plaintextArray); - QString cypherString = QString::fromLatin1(cypher.toBase64()); - return cypherString; -} - -QString SimpleCrypt::encryptToString(QByteArray plaintext) -{ - QByteArray cypher = encryptToByteArray(plaintext); - QString cypherString = QString::fromLatin1(cypher.toBase64()); - return cypherString; -} - -QString SimpleCrypt::decryptToString(const QString &cyphertext) -{ - QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); - QByteArray plaintextArray = decryptToByteArray(cyphertextArray); - QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size()); - - return plaintext; -} - -QString SimpleCrypt::decryptToString(QByteArray cypher) -{ - QByteArray ba = decryptToByteArray(cypher); - QString plaintext = QString::fromUtf8(ba, ba.size()); - - return plaintext; -} - -QByteArray SimpleCrypt::decryptToByteArray(const QString& cyphertext) -{ - QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); - QByteArray ba = decryptToByteArray(cyphertextArray); - - return ba; -} - -QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) -{ - if (m_keyParts.isEmpty()) { - qWarning() << "No key set."; - m_lastError = ErrorNoKeySet; - return QByteArray(); - } - - QByteArray ba = cypher; - - if( cypher.length() < 3 ) - return QByteArray(); - - char version = ba.at(0); - - if (version !=3) { //we only work with version 3 - m_lastError = ErrorUnknownVersion; - qWarning() << "Invalid version or not a cyphertext."; - return QByteArray(); - } - - CryptoFlags flags = CryptoFlags(ba.at(1)); - - ba = ba.mid(2); - int pos(0); - int cnt(ba.length()); - char lastChar = 0; - - while (pos < cnt) { - char currentChar = ba[pos]; - ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8); - lastChar = currentChar; - ++pos; - } - - ba = ba.mid(1); //chop off the random number at the start - - bool integrityOk(true); - if (flags.testFlag(CryptoFlagChecksum)) { - if (ba.length() < 2) { - m_lastError = ErrorIntegrityFailed; - return QByteArray(); - } - quint16 storedChecksum; - { - QDataStream s(&ba, QIODeviceBase::ReadOnly); - s >> storedChecksum; - } - ba = ba.mid(2); - QByteArrayView v(ba); - quint16 checksum = qChecksum(v); - integrityOk = (checksum == storedChecksum); - } else if (flags.testFlag(CryptoFlagHash)) { - if (ba.length() < 20) { - m_lastError = ErrorIntegrityFailed; - return QByteArray(); - } - QByteArray storedHash = ba.left(20); - ba = ba.mid(20); - QCryptographicHash hash(QCryptographicHash::Sha1); - hash.addData(ba); - integrityOk = (hash.result() == storedHash); - } - - if (!integrityOk) { - m_lastError = ErrorIntegrityFailed; - return QByteArray(); - } - - if (flags.testFlag(CryptoFlagCompression)) - ba = qUncompress(ba); - - m_lastError = ErrorNoError; - return ba; -} diff --git a/Common/QtUtils/simplecrypt.h b/Common/QtUtils/simplecrypt.h deleted file mode 100644 index 1fcf784a210..00000000000 --- a/Common/QtUtils/simplecrypt.h +++ /dev/null @@ -1,225 +0,0 @@ -/* -Copyright (c) 2011, Andre Somers -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Rathenau Instituut, Andre Somers nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR #######; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef SIMPLECRYPT_H -#define SIMPLECRYPT_H -#include -#include -#include - -/** - @short Simple encryption and decryption of strings and byte arrays - - This class provides a simple implementation of encryption and decryption - of strings and byte arrays. - - @warning The encryption provided by this class is NOT strong encryption. It may - help to shield things from curious eyes, but it will NOT stand up to someone - determined to break the encryption. Don't say you were not warned. - - The class uses a 64 bit key. Simply create an instance of the class, set the key, - and use the encryptToString() method to calculate an encrypted version of the input string. - To decrypt that string again, use an instance of SimpleCrypt initialized with - the same key, and call the decryptToString() method with the encrypted string. If the key - matches, the decrypted version of the string will be returned again. - - If you do not provide a key, or if something else is wrong, the encryption and - decryption function will return an empty string or will return a string containing nonsense. - lastError() will return a value indicating if the method was succesful, and if not, why not. - - SimpleCrypt is prepared for the case that the encryption and decryption - algorithm is changed in a later version, by prepending a version identifier to the cypertext. - */ -class SimpleCrypt -{ -public: - /** - CompressionMode describes if compression will be applied to the data to be - encrypted. - */ - enum CompressionMode { - CompressionAuto, /*!< Only apply compression if that results in a shorter plaintext. */ - CompressionAlways, /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */ - CompressionNever /*!< Never apply compression. */ - }; - /** - IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data - or wrong decryption keys. - - Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This - increases the length of the resulting cypertext, but makes it possible to check if the plaintext - appears to be valid after decryption. - */ - enum IntegrityProtectionMode { - ProtectionNone, /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */ - ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */ - ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */ - }; - /** - Error describes the type of error that occured. - */ - enum Error { - ErrorNoError, /*!< No error occurred. */ - ErrorNoKeySet, /*!< No key was set. You can not encrypt or decrypt without a valid key. */ - ErrorUnknownVersion, /*!< The version of this data is unknown, or the data is otherwise not valid. */ - ErrorIntegrityFailed, /*!< The integrity check of the data failed. Perhaps the wrong key was used. */ - }; - - /** - Constructor. - - Constructs a SimpleCrypt instance without a valid key set on it. - */ - SimpleCrypt(); - /** - Constructor. - - Constructs a SimpleCrypt instance and initializes it with the given @arg key. - */ - explicit SimpleCrypt(quint64 key); - - /** - (Re-) initializes the key with the given @arg key. - */ - void setKey(quint64 key); - /** - Returns true if SimpleCrypt has been initialized with a key. - */ - bool hasKey() const {return !m_keyParts.isEmpty();} - - /** - Sets the compression mode to use when encrypting data. The default mode is Auto. - - Note that decryption is not influenced by this mode, as the decryption recognizes - what mode was used when encrypting. - */ - void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;} - /** - Returns the CompressionMode that is currently in use. - */ - CompressionMode compressionMode() const {return m_compressionMode;} - - /** - Sets the integrity mode to use when encrypting data. The default mode is Checksum. - - Note that decryption is not influenced by this mode, as the decryption recognizes - what mode was used when encrypting. - */ - void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;} - /** - Returns the IntegrityProtectionMode that is currently in use. - */ - IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;} - - /** - Returns the last error that occurred. - */ - Error lastError() const {return m_lastError;} - - /** - Encrypts the @arg plaintext string with the key the class was initialized with, and returns - a cyphertext the result. The result is a base64 encoded version of the binary array that is the - actual result of the string, so it can be stored easily in a text format. - */ - QString encryptToString(const QString& plaintext) ; - /** - Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns - a cyphertext the result. The result is a base64 encoded version of the binary array that is the - actual result of the encryption, so it can be stored easily in a text format. - */ - QString encryptToString(QByteArray plaintext) ; - /** - Encrypts the @arg plaintext string with the key the class was initialized with, and returns - a binary cyphertext in a QByteArray the result. - - This method returns a byte array, that is useable for storing a binary format. If you need - a string you can store in a text file, use encryptToString() instead. - */ - QByteArray encryptToByteArray(const QString& plaintext) ; - /** - Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns - a binary cyphertext in a QByteArray the result. - - This method returns a byte array, that is useable for storing a binary format. If you need - a string you can store in a text file, use encryptToString() instead. - */ - QByteArray encryptToByteArray(QByteArray plaintext) ; - - /** - Decrypts a cyphertext string encrypted with this class with the set key back to the - plain text version. - - If an error occured, such as non-matching keys between encryption and decryption, - an empty string or a string containing nonsense may be returned. - */ - QString decryptToString(const QString& cyphertext) ; - /** - Decrypts a cyphertext string encrypted with this class with the set key back to the - plain text version. - - If an error occured, such as non-matching keys between encryption and decryption, - an empty string or a string containing nonsense may be returned. - */ - QByteArray decryptToByteArray(const QString& cyphertext) ; - /** - Decrypts a cyphertext binary encrypted with this class with the set key back to the - plain text version. - - If an error occured, such as non-matching keys between encryption and decryption, - an empty string or a string containing nonsense may be returned. - */ - QString decryptToString(QByteArray cypher) ; - /** - Decrypts a cyphertext binary encrypted with this class with the set key back to the - plain text version. - - If an error occured, such as non-matching keys between encryption and decryption, - an empty string or a string containing nonsense may be returned. - */ - QByteArray decryptToByteArray(QByteArray cypher) ; - - //enum to describe options that have been used for the encryption. Currently only one, but - //that only leaves room for future extensions like adding a cryptographic hash... - enum CryptoFlag{CryptoFlagNone = 0, - CryptoFlagCompression = 0x01, - CryptoFlagChecksum = 0x02, - CryptoFlagHash = 0x04 - }; - Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag); -private: - - void splitKey(); - - quint64 m_key; - QVector m_keyParts; - CompressionMode m_compressionMode; - IntegrityProtectionMode m_protectionMode; - Error m_lastError; -}; -Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags) - -#endif // SimpleCrypt_H diff --git a/Common/appinfo.cpp.in b/Common/appinfo.cpp.in deleted file mode 100644 index bd8b1b1afc0..00000000000 --- a/Common/appinfo.cpp.in +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (C) 2018 University of Amsterdam -// -// 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, see . - - -// -// NOTICE: -// `appinfo.cpp` is generated from `appinfo.cpp.in` and you should edit -// that file instead if you want your changes to reflect in the app -// - -#include "appinfo.h" -#include - -const Version AppInfo::version = Version(@JASP_VERSION_MAJOR@, @JASP_VERSION_MINOR@, @JASP_VERSION_PATCH@, @JASP_VERSION_TWEAK@); -const std::string AppInfo::name = "JASP"; -const std::string AppInfo::builddate = __DATE__ " " __TIME__ " (Netherlands)" ; - -const std::string AppInfo::gitBranch = "@GIT_CURRENT_BRANCH@"; -const std::string AppInfo::gitCommit = "@GIT_CURRENT_COMMIT@"; - -std::string AppInfo::getShortDesc() -{ - return AppInfo::name + " " + AppInfo::version.asString(); -} - -std::string AppInfo::getBuildYear() -{ - std::string datum = __DATE__; - return datum.substr(datum.length() - 4); -} - -std::string AppInfo::getRVersion() -{ - return "@CURRENT_R_VERSION@"; -} - -std::string AppInfo::getRDirName() -{ - return "@R_DIR_NAME@"; -} - -std::string AppInfo::getSigningIdentity() -{ - return "@APPLE_CODESIGN_IDENTITY@"; -} - -std::string AppInfo::getArchLabel() -{ - return "@ARCH_LABEL@"; -} - -long long AppInfo::getSimpleCryptKey() -{ - return @CRYPT_KEY@; -} \ No newline at end of file diff --git a/Common/appinfo.h b/Common/appinfo.h deleted file mode 100644 index 9de0e3f997b..00000000000 --- a/Common/appinfo.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (C) 2018 University of Amsterdam -// -// 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, see . -// - -#ifndef APPINFO_H -#define APPINFO_H - -#include "version.h" - - -/// -/// Some useful static information about JASP, when was it build and from what. Etc. -/// -class AppInfo -{ -public: - static const Version version; - static const std::string name; - static const std::string builddate; - static const std::string gitBranch; - static const std::string gitCommit; - - static std::string getShortDesc(); - static std::string getBuildYear(); - static std::string getRVersion(); - static std::string getRDirName(); - static std::string getSigningIdentity(); - static std::string getArchLabel(); - static long long getSimpleCryptKey(); -}; - -#endif // APPINFO_H - diff --git a/Common/columnencoder.cpp b/Common/columnencoder.cpp deleted file mode 100644 index 8fffac3dfb9..00000000000 --- a/Common/columnencoder.cpp +++ /dev/null @@ -1,557 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#include "columnencoder.h" -#include -#ifdef BUILDING_JASP -#include "log.h" -#define LOGGER Log::log() -#else -#include -#define LOGGER Rcpp::Rcout -#endif - - - -ColumnEncoder * ColumnEncoder::_columnEncoder = nullptr; -std::set * ColumnEncoder::_otherEncoders = nullptr; -bool ColumnEncoder::_encodingMapInvalidated = true; -bool ColumnEncoder::_decodingMapInvalidated = true; -bool ColumnEncoder::_originalNamesInvalidated = true; -bool ColumnEncoder::_encodedNamesInvalidated = true; - - -ColumnEncoder * ColumnEncoder::columnEncoder() -{ - if(!_columnEncoder) - _columnEncoder = new ColumnEncoder(); - - return _columnEncoder; -} - -void ColumnEncoder::invalidateAll() -{ - _encodingMapInvalidated = true; - _decodingMapInvalidated = true; - _originalNamesInvalidated = true; - _encodedNamesInvalidated = true; -} - -ColumnEncoder::ColumnEncoder(std::string prefix, std::string postfix) - : _encodePrefix(prefix), _encodePostfix(postfix) -{ - if(!_otherEncoders) - { - _otherEncoders = new ColumnEncoder::ColumnEncoders(); - invalidateAll(); - } - - _otherEncoders->insert(this); -} - -ColumnEncoder::ColumnEncoder(const std::map & decodeDifferently) - : _encodePrefix("JASPColumn_"), _encodePostfix("_For_Replacement") -{ - - std::vector originalNames; - originalNames.reserve(decodeDifferently.size()); - - for(const auto & oriNew : decodeDifferently) - originalNames.push_back(oriNew.first); - - setCurrentNames(originalNames); - - for(const std::string & encodedName : _encodedNames) - if(decodeDifferently.count(_decodingMap[encodedName]) > 0) - _decodingMap[encodedName] = decodeDifferently.at(_decodingMap[encodedName]); -} - -ColumnEncoder::~ColumnEncoder() -{ - if(this != _columnEncoder) - { - if(_otherEncoders && _otherEncoders->count(this) > 0) //The special "replacer-encoder" doesn't add itself to otherEncoders. - _otherEncoders->erase(this); - } - else - { - _columnEncoder = nullptr; - - ColumnEncoders others = *_otherEncoders; - - for(ColumnEncoder * colEnc : others) - delete colEnc; - - if(_otherEncoders->size() > 0) - LOGGER << "Something went wrong removing other ColumnEncoders..." << std::endl; - - delete _otherEncoders; - _otherEncoders = nullptr; - - invalidateAll(); - } -} - -std::string ColumnEncoder::encode(const std::string &in) -{ - if(in == "") return ""; - - if(encodingMap().count(in) == 0) - throw std::runtime_error("Trying to encode columnName but '" + in + "' is not a columnName!"); - - return encodingMap().at(in); -} - -std::string ColumnEncoder::decode(const std::string &in) -{ - if(in == "") return ""; - - if(decodingMap().count(in) == 0) - throw std::runtime_error("Trying to decode columnName but '" + in + "' is not an encoded columnName!"); - - return decodingMap().at(in); -} - -void ColumnEncoder::setCurrentNames(const std::vector & names) -{ - LOGGER << "ColumnEncoder::setCurrentNames(#"<< names.size() << ")" << std::endl; - - _encodingMap.clear(); - _decodingMap.clear(); - - _encodedNames.clear(); - _encodedNames.reserve(names.size()); - - for(size_t col = 0; col < names.size(); col++) - { - std::string newName = _encodePrefix + std::to_string(col) + _encodePostfix; //Slightly weird (but R-syntactically valid) name to avoid collisions with user stuff. - _encodingMap[names[col]] = newName; - _decodingMap[newName] = names[col]; - - _encodedNames.push_back(newName); - } - - _originalNames = names; - sortVectorBigToSmall(_originalNames); - invalidateAll(); -} - -void ColumnEncoder::sortVectorBigToSmall(std::vector & vec) -{ - std::sort(vec.begin(), vec.end(), [](std::string & a, std::string & b) { return a.size() > b.size(); }); //We need this to make sure smaller columnNames do not bite chunks off of larger ones -} - -const ColumnEncoder::colMap & ColumnEncoder::encodingMap() -{ - static ColumnEncoder::colMap map; - - if(_encodingMapInvalidated) - { - map = _columnEncoder->_encodingMap; - - if(_otherEncoders) - for(const ColumnEncoder * other : *_otherEncoders) - for(const auto & keyVal : other->_encodingMap) - if(map.count(keyVal.first) == 0) - map[keyVal.first] = keyVal.second; - - _encodingMapInvalidated = false; - } - - return map; -} - -const ColumnEncoder::colMap & ColumnEncoder::decodingMap() -{ - static ColumnEncoder::colMap map; - - if(_decodingMapInvalidated) - { - map = _columnEncoder->_decodingMap; - - if(_otherEncoders) - for(const ColumnEncoder * other : *_otherEncoders) - for(const auto & keyVal : other->_decodingMap) - if(map.count(keyVal.first) == 0) - map[keyVal.first] = keyVal.second; - - _decodingMapInvalidated = false; - } - - return map; -} - -const ColumnEncoder::colVec & ColumnEncoder::originalNames() -{ - static ColumnEncoder::colVec vec; - - if(_originalNamesInvalidated) - { - vec = _columnEncoder->_originalNames; - - if(_otherEncoders) - for(const ColumnEncoder * other : *_otherEncoders) - for(const std::string & name : other->_originalNames) - vec.push_back(name); - - _originalNamesInvalidated = false; - } - - sortVectorBigToSmall(vec); - - return vec; -} - -const ColumnEncoder::colVec & ColumnEncoder::encodedNames() -{ - static ColumnEncoder::colVec vec; - - if(_encodedNamesInvalidated) - { - vec = _columnEncoder->_encodedNames; - - if(_otherEncoders) - for(const ColumnEncoder * other : *_otherEncoders) - for(const std::string & name : other->_encodedNames) - vec.push_back(name); - - _encodedNamesInvalidated = false; - } - - sortVectorBigToSmall(vec); - - return vec; -} - -bool ColumnEncoder::shouldEncode(const std::string & in) -{ - return _encodingMap.count(in) > 0; -} - -bool ColumnEncoder::shouldDecode(const std::string & in) -{ - return _decodingMap.count(in) > 0; -} - -std::string ColumnEncoder::replaceAllStrict(const std::string & text, const std::map & map) -{ - if (map.count(text) > 0) - return map.at(text); - else - return text; -} - -std::string ColumnEncoder::replaceAll(std::string text, const std::map & map, const std::vector & names) -{ - size_t foundPos = 0; - - while(foundPos < std::string::npos) - { - size_t firstFoundPos = std::string::npos; - - std::string replaceThis; - - //First we find the first occurence of a replaceable text. - for(const std::string & replaceMe : names) //We follow names instead of keyvals from map because they ought to be sorted from largest to smallest string (_originalNames) to not make sub-replacements - { - size_t pos = text.find(replaceMe, foundPos); - if(pos < firstFoundPos) - { - firstFoundPos = pos; - replaceThis = replaceMe; - } - } - - //We found something to replace and this will be the first occurence of anything like that. Replace it! - if(firstFoundPos != std::string::npos) - { - foundPos = firstFoundPos; - const std::string & replacement = map.at(replaceThis); - text.replace(foundPos, replaceThis.length(), replacement); - foundPos += replacement.length(); //Let's make sure we start replacing from after where we just replaced - } - else - foundPos = std::string::npos; - } - - return text; -} - -std::string ColumnEncoder::encodeRScript(std::string text, std::set * columnNamesFound) -{ - return encodeRScript(text, encodingMap(), originalNames(), columnNamesFound); -} - -std::string ColumnEncoder::encodeRScript(std::string text, const std::map & map, const std::vector & names, std::set * columnNamesFound) -{ - if(columnNamesFound) - columnNamesFound->clear(); - - static std::regex nonNameChar("[^\\.A-Za-z0-9_]"); - - //for now we simply replace any found columnname by its Base64 variant if found - for(const std::string & oldCol : names) - { - std::string newCol = map.at(oldCol); - - std::vector foundColPositions = getPositionsColumnNameMatches(text, oldCol); - std::reverse(foundColPositions.begin(), foundColPositions.end()); - - for (size_t foundPos : foundColPositions) - { - size_t foundPosEnd = foundPos + oldCol.length(); - - //First check if it is a "free columnname" aka is there some space or a kind in front of it. We would not want to replace a part of another term (Imagine what happens when you use a columname such as "E" and a filter that includes the term TRUE, it does not end well..) - bool startIsFree = foundPos == 0 || std::regex_match(text.substr(foundPos - 1, 1), nonNameChar); - bool endIsFree = foundPosEnd == text.length() || std::regex_match(text.substr(foundPosEnd, 1), nonNameChar); - - //Check for "(" as well because maybe someone has a columnname such as rep or if or something weird like that. This might however have some whitespace in between... - bool keepGoing = true; - - for(size_t bracePos = foundPosEnd; bracePos < text.size() && endIsFree && keepGoing; bracePos++) - if(text[bracePos] == '(') - endIsFree = false; - else if(text[bracePos] != '\t' && text[bracePos] != ' ') - keepGoing = false; //Aka something else than whitespace or a brace and that means that we can replace it! - - if(startIsFree && endIsFree) - { - text.replace(foundPos, oldCol.length(), newCol); - - if(columnNamesFound) - columnNamesFound->insert(oldCol); - } - } - } - - return text; -} - -std::vector ColumnEncoder::getPositionsColumnNameMatches(const std::string & text, const std::string & columnName) -{ - std::vector positions; - - bool inString = false; - char delim = '?'; - - for (std::string::size_type pos = 0; pos < text.length(); ++pos) - if (!inString && text.substr(pos, columnName.length()) == columnName) - positions.push_back(int(pos)); - else if (text[pos] == '"' || text[pos] == '\'') //string starts or ends. This does not take into account escape characters though... - { - if (!inString) - { - delim = text[pos]; - inString = true; - } - else if(text[pos] == delim) - inString = false; - } - - return positions; -} - - -void ColumnEncoder::encodeJson(Json::Value & json, bool replaceNames, bool replaceStrict) -{ - //std::cout << "Json before encoding:\n" << json.toStyledString(); - replaceAll(json, encodingMap(), originalNames(), replaceNames, replaceStrict); - //std::cout << "Json after encoding:\n" << json.toStyledString() << std::endl; -} - -void ColumnEncoder::decodeJson(Json::Value & json, bool replaceNames) -{ - //std::cout << "Json before encoding:\n" << json.toStyledString(); - replaceAll(json, decodingMap(), encodedNames(), replaceNames, false); - //std::cout << "Json after encoding:\n" << json.toStyledString() << std::endl; -} - - -void ColumnEncoder::replaceAll(Json::Value & json, const std::map & map, const std::vector & names, bool replaceNames, bool replaceStrict) -{ - switch(json.type()) - { - case Json::arrayValue: - for(Json::Value & option : json) - replaceAll(option, map, names, replaceNames, replaceStrict); - return; - - case Json::objectValue: - { - std::map changedMembers; - - for(const std::string & optionName : json.getMemberNames()) - { - replaceAll(json[optionName], map, names, replaceNames, replaceStrict); - - if(replaceNames) - { - std::string replacedName = replaceStrict ? replaceAllStrict(optionName, map) : replaceAll(optionName, map, names); - - if(replacedName != optionName) - changedMembers[optionName] = replacedName; - } - } - - for(const auto & origNew : changedMembers) //map is empty if !replaceNames - { - json[origNew.second] = json[origNew.first]; - json.removeMember(origNew.first); - } - - return; - } - - case Json::stringValue: - json = replaceStrict ? replaceAllStrict(json.asString(), map) : replaceAll(json.asString(), map, names); - return; - - default: - return; - } -} - -void ColumnEncoder::setCurrentNamesFromOptionsMeta(const Json::Value & options) -{ - std::vector namesFound; - - if(!options.isNull() && options.isMember(".meta")) - collectExtraEncodingsFromMetaJson(options[".meta"], namesFound); - - setCurrentNames(namesFound); -} - -void ColumnEncoder::collectExtraEncodingsFromMetaJson(const Json::Value & json, std::vector & namesCollected) const -{ - switch(json.type()) - { - case Json::arrayValue: - for(const Json::Value & option : json) - collectExtraEncodingsFromMetaJson(option, namesCollected); - return; - - case Json::objectValue: - if(json.isMember("encodeThis")) - { - if(json["encodeThis"].isString()) - namesCollected.push_back(json["encodeThis"].asString()); - else if(json["encodeThis"].isArray()) - for(const Json::Value & enc : json["encodeThis"]) - namesCollected.push_back(enc.asString()); - } - else - for(const std::string & optionName : json.getMemberNames()) - collectExtraEncodingsFromMetaJson(json[optionName], namesCollected); - return; - - default: - return; - } -} - -std::string ColumnEncoder::removeColumnNamesFromRScript(const std::string & rCode, const std::vector & colsToRemove) -{ - std::map replaceBy; - - for(const std::string & col : colsToRemove) - replaceBy[col] = "stop('column " + col + " was removed from this RScript')"; - - return replaceColumnNamesInRScript(rCode, replaceBy); -} - -std::string ColumnEncoder::replaceColumnNamesInRScript(const std::string & rCode, const std::map & changedNames) -{ - //Ok the trick here is to reuse the encoding code, we will first encode the original names and then change the encodings to point back to the replaced names. - ColumnEncoder tempEncoder(changedNames); - - return - tempEncoder.replaceAll( - tempEncoder.encodeRScript( - rCode, - tempEncoder._encodingMap, - tempEncoder._originalNames - ), - tempEncoder._decodingMap, - tempEncoder._encodedNames - ); -} - -ColumnEncoder::colVec ColumnEncoder::columnNames() -{ - return _columnEncoder ? _columnEncoder->_originalNames : colVec(); -} - -ColumnEncoder::colVec ColumnEncoder::columnNamesEncoded() -{ - return _columnEncoder ? _columnEncoder->_encodedNames : colVec(); -} - - -void ColumnEncoder::encodeColumnNamesinOptions(Json::Value & options) -{ - _encodeColumnNamesinOptions(options, options[".meta"]); -} - -void ColumnEncoder::_encodeColumnNamesinOptions(Json::Value & options, Json::Value & meta) -{ - if(meta.isNull()) - return; - - bool encodePlease = meta.isObject() && meta.get("shouldEncode", false).asBool(), - isRCode = meta.isObject() && meta.get("rCode", false).asBool(); - - switch(options.type()) - { - case Json::arrayValue: - if(encodePlease) - columnEncoder()->encodeJson(options, false, true); //If we already think we have columnNames just change it all - - else if(meta.type() == Json::arrayValue) - for(int i=0; iencodeRScript(options[i].asString()); - - return; - - case Json::objectValue: - for(const std::string & memberName : options.getMemberNames()) - if(memberName != ".meta" && meta.isMember(memberName)) - _encodeColumnNamesinOptions(options[memberName], meta[memberName]); - - else if(isRCode && options[memberName].isString()) - options[memberName] = columnEncoder()->encodeRScript(options[memberName].asString()); - - else if(encodePlease) - columnEncoder()->encodeJson(options, false, true); //If we already think we have columnNames just change it all I guess? - - return; - - case Json::stringValue: - - if(isRCode) options = columnEncoder()->encodeRScript(options.asString()); - else if(encodePlease) options = columnEncoder()->encodeAll(options.asString()); - - return; - - default: - return; - } -} diff --git a/Common/columnencoder.h b/Common/columnencoder.h deleted file mode 100644 index e959f1b0e3a..00000000000 --- a/Common/columnencoder.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#ifndef COLUMNENCODER_H -#define COLUMNENCODER_H - -#include -#include -#include -#include - -#ifdef BUILDING_JASP -#include -#else -#include "json/json.h" -#endif - -/// Class to "encode" the names of columns -/// It can be used both directly, through columnEncoder()->, in that scenario it only en- and decodes actual columnNames from the dataset. -/// If you want to en- or decode other names then you instantiate a separate copy and use it's functions. -/// It will then also use the columnnames if they are set btw. -class ColumnEncoder -{ - typedef std::map colMap; - typedef std::vector colVec; - typedef std::set ColumnEncoders; - -private: ColumnEncoder() { invalidateAll(); } -public: - ColumnEncoder(std::string prefix, std::string postfix = "_Encoded"); - ColumnEncoder(const std::map & decodeDifferently); - ~ColumnEncoder(); - static ColumnEncoder * columnEncoder(); - - static bool isColumnName(const std::string & in) { return columnEncoder()->shouldEncode(in); } - static bool isEncodedColumnName(const std::string & in) { return columnEncoder()->shouldDecode(in); } - static void setCurrentColumnNames(const std::vector & names) { columnEncoder()->setCurrentNames(names); } - - static std::string replaceColumnNamesInRScript(const std::string & rCode, const std::map & changedNames); - static std::string removeColumnNamesFromRScript(const std::string & rCode, const std::vector & colsToRemove); - - static colVec columnNames(); - static colVec columnNamesEncoded(); - - bool shouldEncode(const std::string & in); - bool shouldDecode(const std::string & in); - void setCurrentNames(const std::vector & names); - void setCurrentNamesFromOptionsMeta(const Json::Value & json); - - std::string encode(const std::string &in); - std::string decode(const std::string &in); - - - ///Replace all occurences of columnNames in a string by their encoded versions, taking into account the presence of word boundaries and parentheses. - std::string encodeRScript(std::string text, std::set * columnNamesFound = nullptr); - std::string encodeRScript(std::string text, const std::map & map, const std::vector & names, std::set * columnNamesFound = nullptr); - - ///Replace all occurences of columnNames in a string by their encoded versions, regardless of word boundaries or parentheses. - static std::string encodeAll(const std::string & text) { return replaceAll(text, encodingMap(), originalNames()); } - - ///Replace all occurences of encoded columnNames in a string by their decoded versions, regardless of word boundaries or parentheses. - static std::string decodeAll(const std::string & text) { return replaceAll(text, decodingMap(), encodedNames()); } - - ///Replace all occurences of columnNames in a string by their encoded versions in all json-names and string-values, regardless of word boundaries or parentheses. - static void encodeJson(Json::Value & json, bool replaceNames = false, bool replaceStrict = false); - - ///Replace all occurences of encoded columnNames in a string by their decoded versions in all json-names and string-values, regardless of word boundaries or parentheses. - static void decodeJson(Json::Value & json, bool replaceNames = true); - - static void encodeColumnNamesinOptions(Json::Value & options); - -private: - static void _encodeColumnNamesinOptions(Json::Value & options, Json::Value & meta); - -private: - static std::string replaceAll(std::string text, const std::map & map, const std::vector & names); - static std::string replaceAllStrict(const std::string & text, const std::map & map); - - static void replaceAll(Json::Value & json, const std::map & map, const std::vector & names, bool replaceNames, bool replaceStrict); - static std::vector getPositionsColumnNameMatches(const std::string & text, const std::string & columnName); - void collectExtraEncodingsFromMetaJson(const Json::Value & in, std::vector & namesCollected) const; - static void sortVectorBigToSmall(std::vector & vec); - static const colMap & encodingMap(); - static const colMap & decodingMap(); - static const colVec & originalNames(); - static const colVec & encodedNames(); - static void invalidateAll(); - - static bool _encodingMapInvalidated, - _decodingMapInvalidated, - _originalNamesInvalidated, - _encodedNamesInvalidated; - - static ColumnEncoder * _columnEncoder; - static ColumnEncoders * _otherEncoders; - - colMap _encodingMap, - _decodingMap; - colVec _originalNames, - _encodedNames; - - std::string _encodePrefix = "JaspColumn_", - _encodePostfix = "_Encoded"; -}; - -#endif // COLUMNENCODER_H diff --git a/Common/columntype.cpp b/Common/columntype.cpp deleted file mode 100644 index 5e042567877..00000000000 --- a/Common/columntype.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#define ENUM_DECLARATION_CPP -#include "columntype.h" - diff --git a/Common/columntype.h b/Common/columntype.h deleted file mode 100644 index 3af60ffe662..00000000000 --- a/Common/columntype.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COLUMNTYPE_H -#define COLUMNTYPE_H -#include "enumutilities.h" - -DECLARE_ENUM(columnType, unknown = 0, nominal = 1, nominalText = 2, ordinal = 3, scale = 4); -DECLARE_ENUM(columnTypeChangeResult, changed, cannotConvertStringValueToInteger, cannotConvertStringValueToDouble, cannotConvertDoubleValueToInteger, generatedFromAnalysis, unknownError); -DECLARE_ENUM(computedColumnType, notComputed, rCode, constructorCode, analysis, analysisNotComputed); -DECLARE_ENUM(dbDbl, nan, inf, neg_inf); - -#endif // COLUMNTYPE_H diff --git a/Common/common.h b/Common/common.h deleted file mode 100644 index 0039be126a8..00000000000 --- a/Common/common.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -/// -/// Just some common defines -/// - -#ifndef COMMON_H -#define COMMON_H - -#if __GNUC__ == 4 && __GNUC_MINOR__ == 6 -#define OVERRIDE -#else -#define OVERRIDE override -#endif - -#if _WIN64 || __amd64__ -#define ARCH_64 -#else -#define ARCH_32 -#endif - -typedef unsigned int uint; - -#endif // COMMON_H diff --git a/Common/dirs.cpp b/Common/dirs.cpp deleted file mode 100644 index 72dd72f6417..00000000000 --- a/Common/dirs.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#include "dirs.h" - - -#include - -#ifdef _WIN32 -#include -#include -#include -#elif defined(__APPLE__) -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#endif - -#include "processinfo.h" -#include "utils.h" -#include "appinfo.h" -#include - -using namespace std; - -string Dirs::_reportingDir = ""; - -string Dirs::tempDir() -{ - static string p = ""; - - if (p != "") - return p; - - string dir; - std::filesystem::path pa; - - if(reportingDir() != "") - { - //There is a reportingDir, which means JASP is running in reporting mode and we might want to show results on a dashboard or something. - //To be able to do this the results need to be at a relative position to index.html (which we need to make available somewhere) - //So lets place it in the reportingDir where the user will be able to find it easily - - dir = reportingDir() + "/jaspTemp/"; - pa = dir; - } - else - { - -#ifdef _WIN32 - char buffer[MAX_PATH]; - if ( ! SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, buffer))) - throw Exception("App Data directory could not be retrieved"); - - dir = std::string(buffer); - dir += "/JASP/temp"; -#else - - dir = string(getpwuid(getuid())->pw_dir); - dir += "/.JASP/temp"; -#endif - - pa = dir; - } - - if (!std::filesystem::exists(pa)) - { - std::error_code ec; - std::filesystem::create_directories(pa, ec); - - if (ec) - { - stringstream ss; - ss << "Temp Data directory could not be created (" << ec << ") : " << dir; - throw Exception(ss.str()); - } - } - - p = std::filesystem::path(dir).generic_string(); - - return p; -} - -string Dirs::exeDir() -{ - static string p = ""; - if (p != "") - return p; - -#ifdef _WIN32 - HMODULE hModule = GetModuleHandleW(NULL); - CHAR path[MAX_PATH]; - - int ret = GetModuleFileNameA(hModule, path, MAX_PATH); - - if (ret == 0) - { - stringstream ss; - ss << "Executable directory could not be retrieved (" << ret << ")"; - throw Exception(ss.str()); - } - - string r = (path); - - char pathbuf[MAX_PATH]; - r.copy(pathbuf, MAX_PATH); - - int last = 0; - - for (int i = 0; i < r.length(); i++) - { - if (pathbuf[i] == '\\') - { - pathbuf[i] = '/'; - last = i; - } - } - - r = string(pathbuf, last); - - p = r; - - return r; - -#elif defined(__APPLE__) - - unsigned long pid = ProcessInfo::currentPID(); - - char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; - int ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf)); - - if (ret <= 0) - { - throw Exception("Executable directory could not be retrieved"); - } - else - { - int last = strlen(pathbuf); - - for (int i = last - 1; i > 0; i--) - { - if (pathbuf[i] == '/') - { - pathbuf[i] = '\0'; - break; - } - } - - p = string(pathbuf); - - return p; - } -#else - - char buf[512]; - char linkname[512]; /* /proc//exe */ - pid_t pid; - int ret; - - pid = getpid(); - - if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0) - throw Exception("Executable directory could not be retrieved"); - - ret = readlink(linkname, buf, sizeof(buf)); - - if (ret == -1) - throw Exception("Executable directory could not be retrieved"); - - if (ret >= sizeof(buf)) - throw Exception("Executable directory could not be retrieved: insufficient buffer size"); - - buf[ret] = '\0'; - - //std::cout << "looking for exeDir in buff: '" << buf << "'\n" << std::flush; - - for (int i = ret-1; i > 0; i--) - { - if (buf[i] == '/') - { - buf[i] = '\0'; // add null terminator - break; - } - } - - std::string exe = string(buf); - - //std::cout << "exeDir found: '" << exe << "'\n" << std::flush; - - return exe; - -#endif - -} - -string Dirs::resourcesDir() -{ - static string dir; - - if(dir == "") - { - dir = exeDir(); - -#ifdef __APPLE__ - dir += "/.."; -#elif __linux__ - dir += "/.."; -#endif - - dir += "/Resources/"; - } - - return dir; -} diff --git a/Common/dirs.h b/Common/dirs.h deleted file mode 100644 index ac5035e4c0b..00000000000 --- a/Common/dirs.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#ifndef DIRS_H -#define DIRS_H - -#include -#include - -/// -/// Some default folders so that they are accesible even without Qt (unlike Desktop/utilities/appdirs.h) -/// -class Dirs -{ -public: - static std::string tempDir(); - static std::string exeDir(); - static std::string resourcesDir(); - - static void setReportingDir(const std::string & dir) { _reportingDir = dir; } - static const std::string & reportingDir() { return _reportingDir; } - - - class Exception : public std::runtime_error - { - public: - Exception(const std::string &message, std::runtime_error &) - : runtime_error(message.c_str()) { } - - Exception(const std::string &message) - : runtime_error(message.c_str()) { } - }; - -private: - static std::string _reportingDir; -}; - -#endif // DIRS_H diff --git a/Common/enginedefinitions.cpp b/Common/enginedefinitions.cpp deleted file mode 100644 index 687202187a9..00000000000 --- a/Common/enginedefinitions.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#define ENUM_DECLARATION_CPP -#include "enginedefinitions.h" - -const char * unexpectedEngineReply::what() const noexcept{ return std::runtime_error::what(); } - -void unexpectedEngineReply::checkIfExpected(engineState expectedReplyState, engineState currentState, int channelNo) -{ - if(expectedReplyState != currentState) - throw unexpectedEngineReply(expectedReplyState, channelNo, ", in state: " + engineStateToString(currentState)); -} diff --git a/Common/enginedefinitions.h b/Common/enginedefinitions.h deleted file mode 100644 index beef31b8127..00000000000 --- a/Common/enginedefinitions.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef ENGINEDEFINITIONS_H -#define ENGINEDEFINITIONS_H - -#include "enumutilities.h" - -/// -/// This file defines the necessary types for communication between Desktop and Engine -/// Using enumutilities templates to make sure we can easily and quickly go from enum -> string -> enum for json communication -/// - -DECLARE_ENUM(engineState, initializing, idle, analysis, filter, rCode, computeColumn, moduleInstallRequest, moduleLoadRequest, pauseRequested, paused, resuming, stopRequested, stopped, logCfg, settings, killed, reloadData); -DECLARE_ENUM(performType, run, abort, saveImg, editImg, rewriteImgs); -DECLARE_ENUM(analysisResultStatus, validationError, fatalError, imageSaved, imageEdited, imagesRewritten, complete, running, changed, waiting); -DECLARE_ENUM(moduleStatus, initializing, installNeeded, loading, installModPkgNeeded, readyForUse, error); -DECLARE_ENUM(engineAnalysisStatus, empty, toRun, running, changed, complete, error, exception, aborted, stopped, saveImg, editImg, rewriteImgs, synchingData); -DECLARE_ENUM(enginesListRoles, channel = 257, module, engineState, analysisStatus, runsWhat, running, idle, idleSoon); //hardcoded Qt::UserRole + 1, sue me. - -struct unexpectedEngineReply : public std::runtime_error -{ - unexpectedEngineReply(std::string msg) : std::runtime_error(msg) {} - unexpectedEngineReply(engineState unexpectedState, std::string msg = "Engine got unexpected") : std::runtime_error(msg + ": " + engineStateToString(unexpectedState)) {} - unexpectedEngineReply(engineState unexpectedState, int engineNo, std::string extra = "") : std::runtime_error("Engine " + std::to_string(engineNo) + " got unexpected reply: " + engineStateToString(unexpectedState) + extra) {} - const char* what() const noexcept override; //Put that - - static void checkIfExpected(engineState expectedReplyState, engineState currentState, int channelNo); -}; - -///How many milliseconds do we wait for an engine to be killed if it gets stuck in some analysis? -#define ENGINE_KILLTIME 750 - -///After how many seconds is an engine allowed to shutdown due to boredom? -#define ENGINE_BORED_SHUTDOWN (5 * 60) - -///Engines need some time between closing and starting to avoid problems with shared memory -#define ENGINE_COOLDOWN 50 - -#endif // ENGINEDEFINITIONS_H diff --git a/Common/enumutilities.h b/Common/enumutilities.h deleted file mode 100644 index 6126a9dc6be..00000000000 --- a/Common/enumutilities.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef ENUMUTILITIES_H -#define ENUMUTILITIES_H - -// See https://stackoverflow.com/a/48820063 -// I expanded it a bit and added from string -> enum and QString stuff -// Also made sure the methods and map and all are defined only in the cpp file (when defining ENUM_DECLARATION_CPP first that is) -// In case it isn't 100% clear what this file does, it basically generates a class enum with conversion to and from (q)strings and related utilities. -// -// To use, include this in the header and then in the sources" -// #define ENUM_DECLARATION_CPP -// #include "yourheaderhere> -// Thats all! - -#include "stringutils.h" -#include -#include -#include -#include -#include - -#ifdef JASP_USES_QT_HERE -#include -#endif - -struct missingEnumVal : public std::runtime_error -{ - missingEnumVal(std::string enumName, std::string missingValue) : std::runtime_error("Enum " + enumName + " does not contain value \"" + missingValue + "\"!") {} -}; - - -#define STRING_REMOVE_CHAR(str, ch) str.erase(std::remove(str.begin(), str.end(), ch), str.end()) - -#define DECLARE_ENUM_WITH_TYPE_BASE(E, T, ...) \ - enum class E : T \ - { \ - __VA_ARGS__ \ - }; \ - std::ostream &operator<<(std::ostream &os, E enumTmp); \ - size_t operator*(E enumTmp); \ - std::string operator~(E enumTmp); \ - std::string operator+(std::string &&str, E enumTmp); \ - std::string operator+(E enumTmp, std::string &&str); \ - std::string &operator+=(std::string &str, E enumTmp); \ - E operator++(E &enumTmp); \ - E E##FromString(std::string enumName); \ - E E##FromString(std::string enumName, E devaultValue); \ - std::string E##ToString(E enumVal); \ - const std::map & E##ToStringMap(); \ - const std::map & E##FromStringMap(); \ - bool E##Valid(T value); - -#define DECLARE_ENUM_METHODS_WITH_TYPE_BASE(E, T, ...) \ - std::map E##MapName(generateEnumMap(#__VA_ARGS__)); \ - std::map E##FromNameMap(generateEnumNameMap(#__VA_ARGS__)); \ - std::ostream &operator<<(std::ostream &os, E enumTmp) \ - { \ - os << E##MapName[static_cast(enumTmp)]; \ - return os; \ - } \ - size_t operator*(E enumTmp) { (void) enumTmp; return E##MapName.size(); } \ - std::string operator~(E enumTmp) { return E##MapName[static_cast(enumTmp)]; } \ - std::string operator+(std::string &&str, E enumTmp) { return str + E##MapName[static_cast(enumTmp)]; } \ - std::string operator+(E enumTmp, std::string &&str) { return E##MapName[static_cast(enumTmp)] + str; } \ - std::string &operator+=(std::string &str, E enumTmp) \ - { \ - str += E##MapName[static_cast(enumTmp)]; \ - return str; \ - } \ - E operator++(E &enumTmp) \ - { \ - auto iter = E##MapName.find(static_cast(enumTmp)); \ - if (iter == E##MapName.end() || std::next(iter) == E##MapName.end()) \ - iter = E##MapName.begin(); \ - else \ - { \ - ++iter; \ - } \ - enumTmp = static_cast(iter->first); \ - return enumTmp; \ - } \ - E E##FromString(std::string enumName) \ - { \ - if(E##FromNameMap.count(enumName) == 0) \ - throw missingEnumVal(#E, enumName); \ - return (E)E##FromNameMap.at(enumName); \ - } \ - E E##FromString(std::string enumName, E defaultValue) \ - { \ - if(E##FromNameMap.count(enumName) == 0) \ - return defaultValue; \ - return (E)E##FromNameMap.at(enumName); \ - } \ - std::string E##ToString(E enumVal) { return ~enumVal; } \ - const std::map & E##ToStringMap() { return E##MapName; } \ - const std::map & E##FromStringMap() { return E##FromNameMap; } \ - bool E##Valid(T value) { return (E##MapName.find(value) != E##MapName.end()); } - -#ifdef JASP_USES_QT_HERE - #define DECLARE_ENUM_WITH_TYPE_HEADER(E, T, ...) \ - DECLARE_ENUM_WITH_TYPE_BASE(E, T, __VA_ARGS__) \ - inline E E##FromQString(QString enumName) { return (E)E##FromString(enumName.toStdString()); } \ - inline E E##FromQString(QString enumName, E defaultValue) { return (E)E##FromString(enumName.toStdString(), defaultValue); } \ - inline QString E##ToQString(E enumVal) { return QString::fromStdString(~enumVal); } \ - inline QString operator+(QString &&str, E enumTmp) { return str + E##ToQString(enumTmp); } \ - inline QString operator+(E enumTmp, QString &&str) { return E##ToQString(enumTmp) + str; } \ - inline QString &operator+=(QString &str, E enumTmp) \ - { \ - str += E##ToQString(enumTmp); \ - return str; \ - } - -#define DECLARE_ENUM_WITH_TYPE_IMPLEMENTATION(E, T, ...) \ - DECLARE_ENUM_METHODS_WITH_TYPE_BASE(E, T, __VA_ARGS__) -#else - #define DECLARE_ENUM_WITH_TYPE_HEADER(E, T, ...) DECLARE_ENUM_WITH_TYPE_BASE(E, T, __VA_ARGS__) - #define DECLARE_ENUM_WITH_TYPE_IMPLEMENTATION(E, T, ...) DECLARE_ENUM_METHODS_WITH_TYPE_BASE(E, T, __VA_ARGS__) -#endif - -#ifdef ENUM_DECLARATION_CPP -#define DECLARE_ENUM(E, ...) \ - DECLARE_ENUM_WITH_TYPE_HEADER( E, int32_t, __VA_ARGS__) \ - DECLARE_ENUM_WITH_TYPE_IMPLEMENTATION( E, int32_t, __VA_ARGS__) - -#define DECLARE_ENUM_WITH_TYPE(E, T, ...) \ - DECLARE_ENUM_WITH_TYPE_HEADER( E, T, __VA_ARGS__) \ - DECLARE_ENUM_WITH_TYPE_IMPLEMENTATION( E, T, __VA_ARGS__) -#else -#define DECLARE_ENUM(E, ...) DECLARE_ENUM_WITH_TYPE_HEADER(E, int32_t, __VA_ARGS__) -#define DECLARE_ENUM_WITH_TYPE(E, T, ...) DECLARE_ENUM_WITH_TYPE_HEADER(E, T, __VA_ARGS__) -#endif - -template std::map generateEnumMap(std::string strMap) -{ - STRING_REMOVE_CHAR(strMap, ' '); - STRING_REMOVE_CHAR(strMap, '('); - - std::vector enumTokens(stringUtils::splitString(strMap)); - std::map retMap; - T inxMap; - - inxMap = 0; - for (auto & tokenString : enumTokens) - { - // Token: [EnumName | EnumName=EnumValue] - std::string enumName; - if (tokenString.find('=') == std::string::npos) - enumName = tokenString; - else - { - std::vector enumNameValue(stringUtils::splitString(tokenString, '=')); - enumName = enumNameValue[0]; - //inxMap = static_cast(enumNameValue[1]); -#ifdef JASP_USES_QT_HERE - if(stringUtils::trim(enumNameValue[1]) == "Qt::UserRole") inxMap = static_cast(Qt::UserRole); - else -#endif - if (std::is_unsigned::value) inxMap = static_cast(std::stoull(enumNameValue[1], 0, 0)); - else inxMap = static_cast(std::stoll(enumNameValue[1], 0, 0)); - } - retMap[inxMap++] = enumName; - } - - return retMap; -} - -template std::map generateEnumNameMap(std::string strMap) -{ - std::map opposite = generateEnumMap(strMap); - std::map retMap; - - for(auto keyval : opposite) - retMap[keyval.second] = keyval.first; - - return retMap; -} - -#endif //ENUMUTILITIES_H, because the rest *should* be allowed to be defined double if the specific enum class does not exist yet: diff --git a/Common/json/allocator.h b/Common/json/allocator.h deleted file mode 100644 index 75406428f54..00000000000 --- a/Common/json/allocator.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_ALLOCATOR_H_INCLUDED -#define JSON_ALLOCATOR_H_INCLUDED - -#include -#include - -#pragma pack(push) -#pragma pack() - -namespace Json { -template class SecureAllocator { -public: - // Type definitions - using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - /** - * Allocate memory for N items using the standard allocator. - */ - pointer allocate(size_type n) { - // allocate using "global operator new" - return static_cast(::operator new(n * sizeof(T))); - } - - /** - * Release memory which was allocated for N items at pointer P. - * - * The memory block is filled with zeroes before being released. - */ - void deallocate(pointer p, size_type n) { - // memset_s is used because memset may be optimized away by the compiler - memset_s(p, n * sizeof(T), 0, n * sizeof(T)); - // free using "global operator delete" - ::operator delete(p); - } - - /** - * Construct an item in-place at pointer P. - */ - template void construct(pointer p, Args&&... args) { - // construct using "placement new" and "perfect forwarding" - ::new (static_cast(p)) T(std::forward(args)...); - } - - size_type max_size() const { return size_t(-1) / sizeof(T); } - - pointer address(reference x) const { return std::addressof(x); } - - const_pointer address(const_reference x) const { return std::addressof(x); } - - /** - * Destroy an item in-place at pointer P. - */ - void destroy(pointer p) { - // destroy using "explicit destructor" - p->~T(); - } - - // Boilerplate - SecureAllocator() {} - template SecureAllocator(const SecureAllocator&) {} - template struct rebind { using other = SecureAllocator; }; -}; - -template -bool operator==(const SecureAllocator&, const SecureAllocator&) { - return true; -} - -template -bool operator!=(const SecureAllocator&, const SecureAllocator&) { - return false; -} - -} // namespace Json - -#pragma pack(pop) - -#endif // JSON_ALLOCATOR_H_INCLUDED diff --git a/Common/json/assertions.h b/Common/json/assertions.h deleted file mode 100644 index 666fa7f542c..00000000000 --- a/Common/json/assertions.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_ASSERTIONS_H_INCLUDED -#define JSON_ASSERTIONS_H_INCLUDED - -#include -#include - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -/** It should not be possible for a maliciously designed file to - * cause an abort() or seg-fault, so these macros are used only - * for pre-condition violations and internal logic errors. - */ -#if JSON_USE_EXCEPTION - -// @todo <= add detail about condition in exception -#define JSON_ASSERT(condition) \ - do { \ - if (!(condition)) { \ - Json::throwLogicError("assert json failed"); \ - } \ - } while (0) - -#define JSON_FAIL_MESSAGE(message) \ - do { \ - OStringStream oss; \ - oss << message; \ - Json::throwLogicError(oss.str()); \ - abort(); \ - } while (0) - -#else // JSON_USE_EXCEPTION - -#define JSON_ASSERT(condition) assert(condition) - -// The call to assert() will show the failure message in debug builds. In -// release builds we abort, for a core-dump or debugger. -#define JSON_FAIL_MESSAGE(message) \ - { \ - OStringStream oss; \ - oss << message; \ - assert(false && oss.str().c_str()); \ - abort(); \ - } - -#endif - -#define JSON_ASSERT_MESSAGE(condition, message) \ - do { \ - if (!(condition)) { \ - JSON_FAIL_MESSAGE(message); \ - } \ - } while (0) - -#endif // JSON_ASSERTIONS_H_INCLUDED diff --git a/Common/json/config.h b/Common/json/config.h deleted file mode 100644 index 6359273a222..00000000000 --- a/Common/json/config.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_CONFIG_H_INCLUDED -#define JSON_CONFIG_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include - -// If non-zero, the library uses exceptions to report bad input instead of C -// assertion macros. The default is to use exceptions. -#ifndef JSON_USE_EXCEPTION -#define JSON_USE_EXCEPTION 1 -#endif - -// Temporary, tracked for removal with issue #982. -#ifndef JSON_USE_NULLREF -#define JSON_USE_NULLREF 1 -#endif - -/// If defined, indicates that the source file is amalgamated -/// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgamated header. -// #define JSON_IS_AMALGAMATION - -// Export macros for DLL visibility -#if defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) || defined(__MINGW32__) -#define JSON_API __declspec(dllexport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#elif defined(__GNUC__) || defined(__clang__) -#define JSON_API __attribute__((visibility("default"))) -#endif // if defined(_MSC_VER) - -#elif defined(JSON_DLL) -#if defined(_MSC_VER) || defined(__MINGW32__) -#define JSON_API __declspec(dllimport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#endif // if defined(_MSC_VER) -#endif // ifdef JSON_DLL_BUILD - -#if !defined(JSON_API) -#define JSON_API -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1800 -#error \ - "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1900 -// As recommended at -// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 -extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, - const char* format, ...); -#define jsoncpp_snprintf msvc_pre1900_c99_snprintf -#else -#define jsoncpp_snprintf std::snprintf -#endif - -// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for -// integer -// Storages, and 64 bits integer support is disabled. -// #define JSON_NO_INT64 1 - -// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. -// C++11 should be used directly in JSONCPP. -#define JSONCPP_OVERRIDE override - -#ifdef __clang__ -#if __has_extension(attribute_deprecated_with_message) -#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) -#endif -#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc) -#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) -#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) -#endif // GNUC version -#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates - // MSVC) -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#endif // __clang__ || __GNUC__ || _MSC_VER - -#if !defined(JSONCPP_DEPRECATED) -#define JSONCPP_DEPRECATED(message) -#endif // if !defined(JSONCPP_DEPRECATED) - -#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -#endif - -#if !defined(JSON_IS_AMALGAMATION) - -#include "allocator.h" -#include "version.h" - -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { -using Int = int; -using UInt = unsigned int; -#if defined(JSON_NO_INT64) -using LargestInt = int; -using LargestUInt = unsigned int; -#undef JSON_HAS_INT64 -#else // if defined(JSON_NO_INT64) -// For Microsoft Visual use specific types as long long is not supported -#if defined(_MSC_VER) // Microsoft Visual Studio -using Int64 = __int64; -using UInt64 = unsigned __int64; -#else // if defined(_MSC_VER) // Other platforms, use long long -using Int64 = int64_t; -using UInt64 = uint64_t; -#endif // if defined(_MSC_VER) -using LargestInt = Int64; -using LargestUInt = UInt64; -#define JSON_HAS_INT64 -#endif // if defined(JSON_NO_INT64) - -template -using Allocator = - typename std::conditional, - std::allocator>::type; -using String = std::basic_string, Allocator>; -using IStringStream = - std::basic_istringstream; -using OStringStream = - std::basic_ostringstream; -using IStream = std::istream; -using OStream = std::ostream; -} // namespace Json - -// Legacy names (formerly macros). -using JSONCPP_STRING = Json::String; -using JSONCPP_ISTRINGSTREAM = Json::IStringStream; -using JSONCPP_OSTRINGSTREAM = Json::OStringStream; -using JSONCPP_ISTREAM = Json::IStream; -using JSONCPP_OSTREAM = Json::OStream; - -#endif // JSON_CONFIG_H_INCLUDED diff --git a/Common/json/forwards.h b/Common/json/forwards.h deleted file mode 100644 index affe33a7f9e..00000000000 --- a/Common/json/forwards.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FORWARDS_H_INCLUDED -#define JSON_FORWARDS_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -// writer.h -class StreamWriter; -class StreamWriterBuilder; -class Writer; -class FastWriter; -class StyledWriter; -class StyledStreamWriter; - -// reader.h -class Reader; -class CharReader; -class CharReaderBuilder; - -// json_features.h -class Features; - -// value.h -using ArrayIndex = unsigned int; -class StaticString; -class Path; -class PathArgument; -class Value; -class ValueIteratorBase; -class ValueIterator; -class ValueConstIterator; - -} // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED diff --git a/Common/json/json.h b/Common/json/json.h deleted file mode 100644 index 5c776a1609e..00000000000 --- a/Common/json/json.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_JSON_H_INCLUDED -#define JSON_JSON_H_INCLUDED - -#include "config.h" -#include "json_features.h" -#include "reader.h" -#include "value.h" -#include "writer.h" - -#endif // JSON_JSON_H_INCLUDED diff --git a/Common/json/json_features.h b/Common/json/json_features.h deleted file mode 100644 index e4a61d6f186..00000000000 --- a/Common/json/json_features.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FEATURES_H_INCLUDED -#define JSON_FEATURES_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -#pragma pack(push) -#pragma pack() - -namespace Json { - -/** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ -class JSON_API Features { -public: - /** \brief A configuration that allows all features and assumes all strings - * are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON - * specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_{true}; - - /// \c true if root must be either an array or an object value. Default: \c - /// false. - bool strictRoot_{false}; - - /// \c true if dropped null placeholders are allowed. Default: \c false. - bool allowDroppedNullPlaceholders_{false}; - - /// \c true if numeric object key are allowed. Default: \c false. - bool allowNumericKeys_{false}; -}; - -} // namespace Json - -#pragma pack(pop) - -#endif // JSON_FEATURES_H_INCLUDED diff --git a/Common/json/json_reader.cpp b/Common/json/json_reader.cpp deleted file mode 100644 index 9c3baf7e5c6..00000000000 --- a/Common/json/json_reader.cpp +++ /dev/null @@ -1,2007 +0,0 @@ -// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors -// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_tool.h" -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#if __cplusplus >= 201103L - -#if !defined(sscanf) -#define sscanf std::sscanf -#endif - -#endif //__cplusplus - -#if defined(_MSC_VER) -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES -#endif //_MSC_VER - -#if defined(_MSC_VER) -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile -// time to change the stack limit -#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) -#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 -#endif - -static size_t const stackLimit_g = - JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -using CharReaderPtr = std::unique_ptr; -#else -using CharReaderPtr = std::auto_ptr; -#endif - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() = default; - -Features Features::all() { return {}; } - -Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - -bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { - return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); -} - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() : features_(Features::all()) {} - -Reader::Reader(const Features& features) : features_(features) {} - -bool Reader::parse(const std::string& document, Value& root, - bool collectComments) { - document_.assign(document.begin(), document.end()); - const char* begin = document_.c_str(); - const char* end = begin + document_.length(); - return parse(begin, end, root, collectComments); -} - -bool Reader::parse(std::istream& is, Value& root, bool collectComments) { - // std::istream_iterator begin(is); - // std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since String is reference-counted, this at least does not - // create an extra copy. - String doc(std::istreambuf_iterator(is), {}); - return parse(doc.data(), doc.data() + doc.size(), root, collectComments); -} - -bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = nullptr; - lastValue_ = nullptr; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool Reader::readValue() { - // readValue() may call itself only if it calls readObject() or ReadArray(). - // These methods execute nodes_.push() just before and nodes_.pop)() just - // after calling readValue(). parse() executes one nodes_.push(), so > instead - // of >=. - if (nodes_.size() > stackLimit_g) - throwRuntimeError("Exceeded stackLimit in readValue()."); - - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenFalse: { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNull: { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void Reader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool Reader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return ok; -} - -void Reader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool Reader::match(const Char* pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool Reader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { - String normalized; - normalized.reserve(static_cast(end - begin)); - Reader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void Reader::addComment(Location begin, Location end, - CommentPlacement placement) { - assert(collectComments_); - const String& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != nullptr); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool Reader::readCStyleComment() { - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool Reader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void Reader::readNumber() { - Location p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } -} - -bool Reader::readString() { - Char c = '\0'; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool Reader::readObject(Token& token) { - Token tokenName; - String name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover("Missing ':' after object member name", colon, - tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover("Missing ',' or '}' in object declaration", - comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover("Missing '}' or object member name", tokenName, - tokenObjectEnd); -} - -bool Reader::readArray(Token& token) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - skipSpaces(); - if (current_ != end_ && *current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token currentToken; - // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } - bool badTokenType = (currentToken.type_ != tokenArraySeparator && - currentToken.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover("Missing ',' or ']' in array declaration", - currentToken, tokenArrayEnd); - } - if (currentToken.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool Reader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of - // them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - auto digit(static_cast(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative && value == maxIntegerValue) - decoded = Value::minLargestInt; - else if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool Reader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - String buffer(token.start_, token.end_); - buffer += '\0'; - IStringStream is(buffer); - - if (!(is >> value)) { - if (value == std::numeric_limits::max()) - value = std::numeric_limits::infinity(); - else if (value == std::numeric_limits::lowest()) - value = -std::numeric_limits::infinity(); - else if (!std::isinf(value)) - return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); - } - decoded = value; - return true; -} - -bool Reader::decodeString(Token& token) { - String decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeString(Token& token, String& decoded) { - decoded.reserve(static_cast(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool Reader::decodeUnicodeCodePoint(Token& token, Location& current, - Location end, unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, current); - if (*(current++) == '\\' && *(current++) == 'u') { - unsigned int surrogatePair; - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, current); - } - return true; -} - -bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, current); - } - ret_unicode = static_cast(unicode); - return true; -} - -bool Reader::addError(const String& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool Reader::recoverFromError(TokenType skipUntilToken) { - size_t const errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool Reader::addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& Reader::currentValue() { return *(nodes_.top()); } - -Reader::Char Reader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void Reader::getLocationLineAndColumn(Location location, int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -String Reader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -// Deprecated. Preserved for backward compatibility -String Reader::getFormatedErrorMessages() const { - return getFormattedErrorMessages(); -} - -String Reader::getFormattedErrorMessages() const { - String formattedMessage; - for (const auto& error : errors_) { - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector Reader::getStructuredErrors() const { - std::vector allErrors; - for (const auto& error : errors_) { - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const String& message) { - ptrdiff_t const length = end_ - begin_; - if (value.getOffsetStart() > length || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = nullptr; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const String& message, - const Value& extra) { - ptrdiff_t const length = end_ - begin_; - if (value.getOffsetStart() > length || value.getOffsetLimit() > length || - extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { return errors_.empty(); } - -// Originally copied from the Features class (now deprecated), used internally -// for features implementation. -class OurFeatures { -public: - static OurFeatures all(); - bool allowComments_; - bool allowTrailingCommas_; - bool strictRoot_; - bool allowDroppedNullPlaceholders_; - bool allowNumericKeys_; - bool allowSingleQuotes_; - bool failIfExtra_; - bool rejectDupKeys_; - bool allowSpecialFloats_; - bool skipBom_; - size_t stackLimit_; -}; // OurFeatures - -OurFeatures OurFeatures::all() { return {}; } - -// Implementation of class Reader -// //////////////////////////////// - -// Originally copied from the Reader class (now deprecated), used internally -// for implementing JSON reading. -class OurReader { -public: - using Char = char; - using Location = const Char*; - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - String message; - }; - - explicit OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments = true); - String getFormattedErrorMessages() const; - std::vector getStructuredErrors() const; - -private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl - - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenNaN, - tokenPosInf, - tokenNegInf, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - String message_; - Location extra_; - }; - - using Errors = std::deque; - - bool readToken(Token& token); - void skipSpaces(); - void skipBom(bool skipBom); - bool match(const Char* pattern, int patternLength); - bool readComment(); - bool readCStyleComment(bool* containsNewLineResult); - bool readCppStyleComment(); - bool readString(); - bool readStringSingleQuote(); - bool readNumber(bool checkInf); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, String& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, Location extra = nullptr); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void getLocationLineAndColumn(Location location, int& line, - int& column) const; - String getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - static String normalizeEOL(Location begin, Location end); - static bool containsNewLine(Location begin, Location end); - - using Nodes = std::stack; - - Nodes nodes_{}; - Errors errors_{}; - String document_{}; - Location begin_ = nullptr; - Location end_ = nullptr; - Location current_ = nullptr; - Location lastValueEnd_ = nullptr; - Value* lastValue_ = nullptr; - bool lastValueHasAComment_ = false; - String commentsBefore_{}; - - OurFeatures const features_; - bool collectComments_ = false; -}; // OurReader - -// complete copy of Read impl, for OurReader - -bool OurReader::containsNewLine(OurReader::Location begin, - OurReader::Location end) { - return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); -} - -OurReader::OurReader(OurFeatures const& features) : features_(features) {} - -bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = nullptr; - lastValue_ = nullptr; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - // skip byte order mark if it exists at the beginning of the UTF-8 text. - skipBom(features_.skipBom_); - bool successful = readValue(); - nodes_.pop(); - Token token; - skipCommentTokens(token); - if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool OurReader::readValue() { - // To preserve the old behaviour we cast size_t to int. - if (nodes_.size() > features_.stackLimit_) - throwRuntimeError("Exceeded stackLimit in readValue()."); - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenFalse: { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNull: { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNaN: { - Value v(std::numeric_limits::quiet_NaN()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenPosInf: { - Value v(std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNegInf: { - Value v(-std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // else, fall through ... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValueHasAComment_ = false; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void OurReader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool OurReader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '\'': - if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - } else { - // If we don't allow single quotes, this is a failure case. - ok = false; - } - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token.type_ = tokenNumber; - readNumber(false); - break; - case '-': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenNegInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case '+': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenPosInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case 'N': - if (features_.allowSpecialFloats_) { - token.type_ = tokenNaN; - ok = match("aN", 2); - } else { - ok = false; - } - break; - case 'I': - if (features_.allowSpecialFloats_) { - token.type_ = tokenPosInf; - ok = match("nfinity", 7); - } else { - ok = false; - } - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return ok; -} - -void OurReader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -void OurReader::skipBom(bool skipBom) { - // The default behavior is to skip BOM. - if (skipBom) { - if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { - begin_ += 3; - current_ = begin_; - } - } -} - -bool OurReader::match(const Char* pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool OurReader::readComment() { - const Location commentBegin = current_ - 1; - const Char c = getNextChar(); - bool successful = false; - bool cStyleWithEmbeddedNewline = false; - - const bool isCStyleComment = (c == '*'); - const bool isCppStyleComment = (c == '/'); - if (isCStyleComment) { - successful = readCStyleComment(&cStyleWithEmbeddedNewline); - } else if (isCppStyleComment) { - successful = readCppStyleComment(); - } - - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - - if (!lastValueHasAComment_) { - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (isCppStyleComment || !cStyleWithEmbeddedNewline) { - placement = commentAfterOnSameLine; - lastValueHasAComment_ = true; - } - } - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -String OurReader::normalizeEOL(OurReader::Location begin, - OurReader::Location end) { - String normalized; - normalized.reserve(static_cast(end - begin)); - OurReader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void OurReader::addComment(Location begin, Location end, - CommentPlacement placement) { - assert(collectComments_); - const String& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != nullptr); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool OurReader::readCStyleComment(bool* containsNewLineResult) { - *containsNewLineResult = false; - - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - if (c == '\n') - *containsNewLineResult = true; - } - - return getNextChar() == '/'; -} - -bool OurReader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -bool OurReader::readNumber(bool checkInf) { - Location p = current_; - if (checkInf && p != end_ && *p == 'I') { - current_ = ++p; - return false; - } - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - return true; -} -bool OurReader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool OurReader::readStringSingleQuote() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '\'') - break; - } - return c == '\''; -} - -bool OurReader::readObject(Token& token) { - Token tokenName; - String name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && - (name.empty() || - features_.allowTrailingCommas_)) // empty object or trailing comma - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - if (name.length() >= (1U << 30)) - throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - String msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover(msg, tokenName, tokenObjectEnd); - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover("Missing ':' after object member name", colon, - tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover("Missing ',' or '}' in object declaration", - comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover("Missing '}' or object member name", tokenName, - tokenObjectEnd); -} - -bool OurReader::readArray(Token& token) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - int index = 0; - for (;;) { - skipSpaces(); - if (current_ != end_ && *current_ == ']' && - (index == 0 || - (features_.allowTrailingCommas_ && - !features_.allowDroppedNullPlaceholders_))) // empty array or trailing - // comma - { - Token endArray; - readToken(endArray); - return true; - } - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token currentToken; - // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } - bool badTokenType = (currentToken.type_ != tokenArraySeparator && - currentToken.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover("Missing ',' or ']' in array declaration", - currentToken, tokenArrayEnd); - } - if (currentToken.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool OurReader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - const bool isNegative = *current == '-'; - if (isNegative) { - ++current; - } - - // We assume we can represent the largest and smallest integer types as - // unsigned integers with separate sign. This is only true if they can fit - // into an unsigned integer. - static_assert(Value::maxLargestInt <= Value::maxLargestUInt, - "Int must be smaller than UInt"); - - // We need to convert minLargestInt into a positive number. The easiest way - // to do this conversion is to assume our "threshold" value of minLargestInt - // divided by 10 can fit in maxLargestInt when absolute valued. This should - // be a safe assumption. - static_assert(Value::minLargestInt <= -Value::maxLargestInt, - "The absolute value of minLargestInt must be greater than or " - "equal to maxLargestInt"); - static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, - "The absolute value of minLargestInt must be only 1 magnitude " - "larger than maxLargest Int"); - - static constexpr Value::LargestUInt positive_threshold = - Value::maxLargestUInt / 10; - static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; - - // For the negative values, we have to be more careful. Since typically - // -Value::minLargestInt will cause an overflow, we first divide by 10 and - // then take the inverse. This assumes that minLargestInt is only a single - // power of 10 different in magnitude, which we check above. For the last - // digit, we take the modulus before negating for the same reason. - static constexpr auto negative_threshold = - Value::LargestUInt(-(Value::minLargestInt / 10)); - static constexpr auto negative_last_digit = - Value::UInt(-(Value::minLargestInt % 10)); - - const Value::LargestUInt threshold = - isNegative ? negative_threshold : positive_threshold; - const Value::UInt max_last_digit = - isNegative ? negative_last_digit : positive_last_digit; - - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - - const auto digit(static_cast(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, meaning value == threshold, - // b) this is the last digit, or - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > max_last_digit) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - - if (isNegative) { - // We use the same magnitude assumption here, just in case. - const auto last_digit = static_cast(value % 10); - decoded = -Value::LargestInt(value / 10) * 10 - last_digit; - } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { - decoded = Value::LargestInt(value); - } else { - decoded = value; - } - - return true; -} - -bool OurReader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const String buffer(token.start_, token.end_); - IStringStream is(buffer); - if (!(is >> value)) { - if (value == std::numeric_limits::max()) - value = std::numeric_limits::infinity(); - else if (value == std::numeric_limits::lowest()) - value = -std::numeric_limits::infinity(); - else if (!std::isinf(value)) - return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); - } - decoded = value; - return true; -} - -bool OurReader::decodeString(Token& token) { - String decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeString(Token& token, String& decoded) { - decoded.reserve(static_cast(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current, - Location end, unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, current); - if (*(current++) == '\\' && *(current++) == 'u') { - unsigned int surrogatePair; - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, current); - } - return true; -} - -bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, current); - } - ret_unicode = static_cast(unicode); - return true; -} - -bool OurReader::addError(const String& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool OurReader::recoverFromError(TokenType skipUntilToken) { - size_t errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool OurReader::addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& OurReader::currentValue() { return *(nodes_.top()); } - -OurReader::Char OurReader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void OurReader::getLocationLineAndColumn(Location location, int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -String OurReader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -String OurReader::getFormattedErrorMessages() const { - String formattedMessage; - for (const auto& error : errors_) { - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; - for (const auto& error : errors_) { - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; - -public: - OurCharReader(bool collectComments, OurFeatures const& features) - : collectComments_(collectComments), reader_(features) {} - bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) override { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); - } - return ok; - } -}; - -CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } -CharReaderBuilder::~CharReaderBuilder() = default; -CharReader* CharReaderBuilder::newCharReader() const { - bool collectComments = settings_["collectComments"].asBool(); - OurFeatures features = OurFeatures::all(); - features.allowComments_ = settings_["allowComments"].asBool(); - features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool(); - features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = - settings_["allowDroppedNullPlaceholders"].asBool(); - features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); - features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - - // Stack limit is always a size_t, so we get this as an unsigned int - // regardless of it we have 64-bit integer support enabled. - features.stackLimit_ = static_cast(settings_["stackLimit"].asUInt()); - features.failIfExtra_ = settings_["failIfExtra"].asBool(); - features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); - features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); - features.skipBom_ = settings_["skipBom"].asBool(); - return new OurCharReader(collectComments, features); -} - -bool CharReaderBuilder::validate(Json::Value* invalid) const { - static const auto& valid_keys = *new std::set{ - "collectComments", - "allowComments", - "allowTrailingCommas", - "strictRoot", - "allowDroppedNullPlaceholders", - "allowNumericKeys", - "allowSingleQuotes", - "stackLimit", - "failIfExtra", - "rejectDupKeys", - "allowSpecialFloats", - "skipBom", - }; - for (auto si = settings_.begin(); si != settings_.end(); ++si) { - auto key = si.name(); - if (valid_keys.count(key)) - continue; - if (invalid) - (*invalid)[key] = *si; - else - return false; - } - return invalid ? invalid->empty() : true; -} - -Value& CharReaderBuilder::operator[](const String& key) { - return settings_[key]; -} -// static -void CharReaderBuilder::strictMode(Json::Value* settings) { - //! [CharReaderBuilderStrictMode] - (*settings)["allowComments"] = false; - (*settings)["allowTrailingCommas"] = false; - (*settings)["strictRoot"] = true; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = true; - (*settings)["rejectDupKeys"] = true; - (*settings)["allowSpecialFloats"] = false; - (*settings)["skipBom"] = true; - //! [CharReaderBuilderStrictMode] -} -// static -void CharReaderBuilder::setDefaults(Json::Value* settings) { - //! [CharReaderBuilderDefaults] - (*settings)["collectComments"] = true; - (*settings)["allowComments"] = true; - (*settings)["allowTrailingCommas"] = true; - (*settings)["strictRoot"] = false; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = false; - (*settings)["rejectDupKeys"] = false; - (*settings)["allowSpecialFloats"] = false; - (*settings)["skipBom"] = true; - //! [CharReaderBuilderDefaults] -} - -////////////////////////////////// -// global functions - -bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, - String* errs) { - OStringStream ssin; - ssin << sin.rdbuf(); - String doc = ssin.str(); - char const* begin = doc.data(); - char const* end = begin + doc.size(); - // Note that we do not actually need a null-terminator. - CharReaderPtr const reader(fact.newCharReader()); - return reader->parse(begin, end, root, errs); -} - -IStream& operator>>(IStream& sin, Value& root) { - CharReaderBuilder b; - String errs; - bool ok = parseFromStream(b, sin, &root, &errs); - if (!ok) { - throwRuntimeError(errs); - } - return sin; -} - -} // namespace Json diff --git a/Common/json/json_tool.h b/Common/json/json_tool.h deleted file mode 100644 index b952c19167a..00000000000 --- a/Common/json/json_tool.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include -#endif - -// Also support old flag NO_LOCALE_SUPPORT -#ifdef NO_LOCALE_SUPPORT -#define JSONCPP_NO_LOCALE_SUPPORT -#endif - -#ifndef JSONCPP_NO_LOCALE_SUPPORT -#include -#endif - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { -static inline char getDecimalPoint() { -#ifdef JSONCPP_NO_LOCALE_SUPPORT - return '\0'; -#else - struct lconv* lc = localeconv(); - return lc ? *(lc->decimal_point) : '\0'; -#endif -} - -/// Converts a unicode code-point to UTF-8. -static inline String codePointToUTF8(unsigned int cp) { - String result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) { - result.resize(1); - result[0] = static_cast(cp); - } else if (cp <= 0x7FF) { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } else if (cp <= 0xFFFF) { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); - } else if (cp <= 0x10FFFF) { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - -enum { - /// Constant that specify the size of the buffer that must be passed to - /// uintToString. - uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 -}; - -// Defines a char buffer for use with uintToString(). -using UIntToStringBuffer = char[uintToStringBufferSize]; - -/** Converts an unsigned integer to string. - * @param value Unsigned integer to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void uintToString(LargestUInt value, char*& current) { - *--current = 0; - do { - *--current = static_cast(value % 10U + static_cast('0')); - value /= 10; - } while (value != 0); -} - -/** Change ',' to '.' everywhere in buffer. - * - * We had a sophisticated way, but it did not work in WinCE. - * @see https://github.com/open-source-parsers/jsoncpp/pull/9 - */ -template Iter fixNumericLocale(Iter begin, Iter end) { - for (; begin != end; ++begin) { - if (*begin == ',') { - *begin = '.'; - } - } - return begin; -} - -template void fixNumericLocaleInput(Iter begin, Iter end) { - char decimalPoint = getDecimalPoint(); - if (decimalPoint == '\0' || decimalPoint == '.') { - return; - } - for (; begin != end; ++begin) { - if (*begin == '.') { - *begin = decimalPoint; - } - } -} - -/** - * Return iterator that would be the new end of the range [begin,end), if we - * were to delete zeros in the end of string, but not the last zero before '.'. - */ -template -Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) { - for (; begin != end; --end) { - if (*(end - 1) != '0') { - return end; - } - // Don't delete the last zero before the decimal point. - if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') { - if (precision) { - return end; - } - return end - 2; - } - } - return end; -} - -} // namespace Json - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED diff --git a/Common/json/json_value.cpp b/Common/json/json_value.cpp deleted file mode 100644 index aa2b744ca83..00000000000 --- a/Common/json/json_value.cpp +++ /dev/null @@ -1,1634 +0,0 @@ -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include - -// Provide implementation equivalent of std::snprintf for older _MSC compilers -#if defined(_MSC_VER) && _MSC_VER < 1900 -#include -static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size, - const char* format, va_list ap) { - int count = -1; - if (size != 0) - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); - if (count == -1) - count = _vscprintf(format, ap); - return count; -} - -int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size, - const char* format, ...) { - va_list ap; - va_start(ap, format); - const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap); - va_end(ap); - return count; -} -#endif - -// Disable warning C4702 : unreachable code -#if defined(_MSC_VER) -#pragma warning(disable : 4702) -#endif - -#define JSON_ASSERT_UNREACHABLE assert(false) - -namespace Json { -template -static std::unique_ptr cloneUnique(const std::unique_ptr& p) { - std::unique_ptr r; - if (p) { - r = std::unique_ptr(new T(*p)); - } - return r; -} - -// This is a walkaround to avoid the static initialization of Value::null. -// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of -// 8 (instead of 4) as a bit of future-proofing. -#if defined(__ARMEL__) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#else -#define ALIGNAS(byte_alignment) -#endif - -// static -Value const& Value::nullSingleton() { - static Value const nullStatic; - return nullStatic; -} - -#if JSON_USE_NULLREF -// for backwards compatibility, we'll leave these global references around, but -// DO NOT use them in JSONCPP library code any more! -// static -Value const& Value::null = Value::nullSingleton(); - -// static -Value const& Value::nullRef = Value::nullSingleton(); -#endif - -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -template -static inline bool InRange(double d, T min, U max) { - // The casts can lose precision, but we are looking only for - // an approximate range. Might fail on edge cases though. ~cdunn - return d >= static_cast(min) && d <= static_cast(max); -} -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + - static_cast(Int64(value & 1)); -} - -template static inline double integerToDouble(T value) { - return static_cast(value); -} - -template -static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); -} -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char* duplicateStringValue(const char* value, size_t length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - if (length >= static_cast(Value::maxInt)) - length = Value::maxInt - 1; - - auto newString = static_cast(malloc(length + 1)); - if (newString == nullptr) { - throwRuntimeError("in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); - } - memcpy(newString, value, length); - newString[length] = 0; - return newString; -} - -/* Record the length as a prefix. - */ -static inline char* duplicateAndPrefixStringValue(const char* value, - unsigned int length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - - sizeof(unsigned) - 1U, - "in Json::Value::duplicateAndPrefixStringValue(): " - "length too big for prefixing"); - size_t actualLength = sizeof(length) + length + 1; - auto newString = static_cast(malloc(actualLength)); - if (newString == nullptr) { - throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); - } - *reinterpret_cast(newString) = length; - memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = - 0; // to avoid buffer over-run accidents by users later - return newString; -} -inline static void decodePrefixedString(bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) { - if (!isPrefixed) { - *length = static_cast(strlen(prefixed)); - *value = prefixed; - } else { - *length = *reinterpret_cast(prefixed); - *value = prefixed + sizeof(unsigned); - } -} -/** Free the string duplicated by - * duplicateStringValue()/duplicateAndPrefixStringValue(). - */ -#if JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - unsigned length = 0; - char const* valueDecoded; - decodePrefixedString(true, value, &length, &valueDecoded); - size_t const size = sizeof(unsigned) + length + 1U; - memset(value, 0, size); - free(value); -} -static inline void releaseStringValue(char* value, unsigned length) { - // length==0 => we allocated the strings memory - size_t size = (length == 0) ? strlen(value) : length; - memset(value, 0, size); - free(value); -} -#else // !JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { free(value); } -static inline void releaseStringValue(char* value, unsigned) { free(value); } -#endif // JSONCPP_USING_SECURE_MEMORY - -} // namespace Json - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) - -#include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -#if JSON_USE_EXCEPTION -Exception::Exception(String msg) : msg_(std::move(msg)) {} -Exception::~Exception() noexcept = default; -char const* Exception::what() const noexcept { return msg_.c_str(); } -RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} -LogicError::LogicError(String const& msg) : Exception(msg) {} -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { - throw RuntimeError(msg); -} -JSONCPP_NORETURN void throwLogicError(String const& msg) { - throw LogicError(msg); -} -#else // !JSON_USE_EXCEPTION -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { - std::cerr << msg << std::endl; - abort(); -} -JSONCPP_NORETURN void throwLogicError(String const& msg) { - std::cerr << msg << std::endl; - abort(); -} -#endif - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -// Notes: policy_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} - -Value::CZString::CZString(char const* str, unsigned length, - DuplicationPolicy allocate) - : cstr_(str) { - // allocate != duplicate - storage_.policy_ = allocate & 0x3; - storage_.length_ = length & 0x3FFFFFFF; -} - -Value::CZString::CZString(const CZString& other) { - cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); - storage_.policy_ = - static_cast( - other.cstr_ - ? (static_cast(other.storage_.policy_) == - noDuplication - ? noDuplication - : duplicate) - : static_cast(other.storage_.policy_)) & - 3U; - storage_.length_ = other.storage_.length_; -} - -Value::CZString::CZString(CZString&& other) noexcept - : cstr_(other.cstr_), index_(other.index_) { - other.cstr_ = nullptr; -} - -Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) { - releaseStringValue(const_cast(cstr_), - storage_.length_ + 1U); // +1 for null terminating - // character for sake of - // completeness but not actually - // necessary - } -} - -void Value::CZString::swap(CZString& other) { - std::swap(cstr_, other.cstr_); - std::swap(index_, other.index_); -} - -Value::CZString& Value::CZString::operator=(const CZString& other) { - cstr_ = other.cstr_; - index_ = other.index_; - return *this; -} - -Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { - cstr_ = other.cstr_; - index_ = other.index_; - other.cstr_ = nullptr; - return *this; -} - -bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) - return index_ < other.index_; - // return strcmp(cstr_, other.cstr_) < 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) - return true; - if (comp > 0) - return false; - return (this_len < other_len); -} - -bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) - return index_ == other.index_; - // return strcmp(cstr_, other.cstr_) == 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - if (this_len != other_len) - return false; - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, this_len); - return comp == 0; -} - -ArrayIndex Value::CZString::index() const { return index_; } - -// const char* Value::CZString::c_str() const { return cstr_; } -const char* Value::CZString::data() const { return cstr_; } -unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { - return storage_.policy_ == noDuplication; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value(ValueType type) { - static char const emptyString[] = ""; - initBasic(type); - switch (type) { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - // allocated_ == false, so this is safe. - value_.string_ = const_cast(static_cast(emptyString)); - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -Value::Value(Int value) { - initBasic(intValue); - value_.int_ = value; -} - -Value::Value(UInt value) { - initBasic(uintValue); - value_.uint_ = value; -} -#if defined(JSON_HAS_INT64) -Value::Value(Int64 value) { - initBasic(intValue); - value_.int_ = value; -} -Value::Value(UInt64 value) { - initBasic(uintValue); - value_.uint_ = value; -} -#endif // defined(JSON_HAS_INT64) - -Value::Value(double value) { - initBasic(realValue); - value_.real_ = value; -} - -Value::Value(const char* value) { - initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != nullptr, - "Null Value Passed to Value Constructor"); - value_.string_ = duplicateAndPrefixStringValue( - value, static_cast(strlen(value))); -} - -Value::Value(const char* begin, const char* end) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(begin, static_cast(end - begin)); -} - -Value::Value(const String& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue( - value.data(), static_cast(value.length())); -} - -Value::Value(const StaticString& value) { - initBasic(stringValue); - value_.string_ = const_cast(value.c_str()); -} - -Value::Value(bool value) { - initBasic(booleanValue); - value_.bool_ = value; -} - -Value::Value(const Value& other) { - dupPayload(other); - dupMeta(other); -} - -Value::Value(Value&& other) noexcept { - initBasic(nullValue); - swap(other); -} - -Value::~Value() { - releasePayload(); - value_.uint_ = 0; -} - -Value& Value::operator=(const Value& other) { - Value(other).swap(*this); - return *this; -} - -Value& Value::operator=(Value&& other) noexcept { - other.swap(*this); - return *this; -} - -void Value::swapPayload(Value& other) { - std::swap(bits_, other.bits_); - std::swap(value_, other.value_); -} - -void Value::copyPayload(const Value& other) { - releasePayload(); - dupPayload(other); -} - -void Value::swap(Value& other) { - swapPayload(other); - std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); -} - -void Value::copy(const Value& other) { - copyPayload(other); - dupMeta(other); -} - -ValueType Value::type() const { - return static_cast(bits_.value_type_); -} - -int Value::compare(const Value& other) const { - if (*this < other) - return -1; - if (*this > other) - return 1; - return 0; -} - -bool Value::operator<(const Value& other) const { - int typeDelta = type() - other.type(); - if (typeDelta) - return typeDelta < 0; - switch (type()) { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: { - if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { - return other.value_.string_ != nullptr; - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, - &other_str); - unsigned min_len = std::min(this_len, other_len); - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) - return true; - if (comp > 0) - return false; - return (this_len < other_len); - } - case arrayValue: - case objectValue: { - auto thisSize = value_.map_->size(); - auto otherSize = other.value_.map_->size(); - if (thisSize != otherSize) - return thisSize < otherSize; - return (*value_.map_) < (*other.value_.map_); - } - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator<=(const Value& other) const { return !(other < *this); } - -bool Value::operator>=(const Value& other) const { return !(*this < other); } - -bool Value::operator>(const Value& other) const { return other < *this; } - -bool Value::operator==(const Value& other) const { - if (type() != other.type()) - return false; - switch (type()) { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: { - if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { - return (value_.string_ == other.value_.string_); - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, - &other_str); - if (this_len != other_len) - return false; - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, this_len); - return comp == 0; - } - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() && - (*value_.map_) == (*other.value_.map_); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator!=(const Value& other) const { return !(*this == other); } - -const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type() == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == nullptr) - return nullptr; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return this_str; -} - -#if JSONCPP_USING_SECURE_MEMORY -unsigned Value::getCStringLength() const { - JSON_ASSERT_MESSAGE(type() == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) - return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return this_len; -} -#endif - -bool Value::getString(char const** begin, char const** end) const { - if (type() != stringValue) - return false; - if (value_.string_ == nullptr) - return false; - unsigned length; - decodePrefixedString(this->isAllocated(), this->value_.string_, &length, - begin); - *end = *begin + length; - return true; -} - -String Value::asString() const { - switch (type()) { - case nullValue: - return ""; - case stringValue: { - if (value_.string_ == nullptr) - return ""; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return String(this_str, this_len); - } - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - return valueToString(value_.int_); - case uintValue: - return valueToString(value_.uint_); - case realValue: - return valueToString(value_.real_); - default: - JSON_FAIL_MESSAGE("Type is not convertible to string"); - } -} - -Value::Int Value::asInt() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), - "double out of Int range"); - return Int(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int."); -} - -Value::UInt Value::asUInt() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), - "double out of UInt range"); - return UInt(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt."); -} - -#if defined(JSON_HAS_INT64) - -Value::Int64 Value::asInt64() const { - switch (type()) { - case intValue: - return Int64(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); - return Int64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), - "double out of Int64 range"); - return Int64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int64."); -} - -Value::UInt64 Value::asUInt64() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); - return UInt64(value_.int_); - case uintValue: - return UInt64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), - "double out of UInt64 range"); - return UInt64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); -} -#endif // if defined(JSON_HAS_INT64) - -LargestInt Value::asLargestInt() const { -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - -LargestUInt Value::asLargestUInt() const { -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - -double Value::asDouble() const { - switch (type()) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to double."); -} - -float Value::asFloat() const { - switch (type()) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - // This can fail (silently?) if the value is bigger than MAX_FLOAT. - return static_cast(integerToDouble(value_.uint_)); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast(value_.real_); - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0F : 0.0F; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to float."); -} - -bool Value::asBool() const { - switch (type()) { - case booleanValue: - return value_.bool_; - case nullValue: - return false; - case intValue: - return value_.int_ != 0; - case uintValue: - return value_.uint_ != 0; - case realValue: { - // According to JavaScript language zero or NaN is regarded as false - const auto value_classification = std::fpclassify(value_.real_); - return value_classification != FP_ZERO && value_classification != FP_NAN; - } - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to bool."); -} - -bool Value::isConvertibleTo(ValueType other) const { - switch (other) { - case nullValue: - return (isNumeric() && asDouble() == 0.0) || - (type() == booleanValue && !value_.bool_) || - (type() == stringValue && asString().empty()) || - (type() == arrayValue && value_.map_->empty()) || - (type() == objectValue && value_.map_->empty()) || - type() == nullValue; - case intValue: - return isInt() || - (type() == realValue && InRange(value_.real_, minInt, maxInt)) || - type() == booleanValue || type() == nullValue; - case uintValue: - return isUInt() || - (type() == realValue && InRange(value_.real_, 0, maxUInt)) || - type() == booleanValue || type() == nullValue; - case realValue: - return isNumeric() || type() == booleanValue || type() == nullValue; - case booleanValue: - return isNumeric() || type() == booleanValue || type() == nullValue; - case stringValue: - return isNumeric() || type() == booleanValue || type() == stringValue || - type() == nullValue; - case arrayValue: - return type() == arrayValue || type() == nullValue; - case objectValue: - return type() == objectValue || type() == nullValue; - } - JSON_ASSERT_UNREACHABLE; - return false; -} - -/// Number of values in array or object -ArrayIndex Value::size() const { - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty()) { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index() + 1; - } - return 0; - case objectValue: - return ArrayIndex(value_.map_->size()); - } - JSON_ASSERT_UNREACHABLE; - return 0; // unreachable; -} - -bool Value::empty() const { - if (isNull() || isArray() || isObject()) - return size() == 0U; - return false; -} - -Value::operator bool() const { return !isNull(); } - -void Value::clear() { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue || - type() == objectValue, - "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; - switch (type()) { - case arrayValue: - case objectValue: - value_.map_->clear(); - break; - default: - break; - } -} - -void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::resize(): requires arrayValue"); - if (type() == nullValue) - *this = Value(arrayValue); - ArrayIndex oldSize = size(); - if (newSize == 0) - clear(); - else if (newSize > oldSize) - for (ArrayIndex i = oldSize; i < newSize; ++i) - (*this)[i]; - else { - for (ArrayIndex index = newSize; index < oldSize; ++index) { - value_.map_->erase(index); - } - JSON_ASSERT(size() == newSize); - } -} - -Value& Value::operator[](ArrayIndex index) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == arrayValue, - "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type() == nullValue) - *this = Value(arrayValue); - CZString key(index); - auto it = value_.map_->lower_bound(key); - if (it != value_.map_->end() && (*it).first == key) - return (*it).second; - - ObjectValues::value_type defaultValue(key, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - return (*it).second; -} - -Value& Value::operator[](int index) { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index): index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -const Value& Value::operator[](ArrayIndex index) const { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == arrayValue, - "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type() == nullValue) - return nullSingleton(); - CZString key(index); - ObjectValues::const_iterator it = value_.map_->find(key); - if (it == value_.map_->end()) - return nullSingleton(); - return (*it).second; -} - -const Value& Value::operator[](int index) const { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index) const: index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -void Value::initBasic(ValueType type, bool allocated) { - setType(type); - setIsAllocated(allocated); - comments_ = Comments{}; - start_ = 0; - limit_ = 0; -} - -void Value::dupPayload(const Value& other) { - setType(other.type()); - setIsAllocated(false); - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.isAllocated()) { - unsigned len; - char const* str; - decodePrefixedString(other.isAllocated(), other.value_.string_, &len, - &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - setIsAllocated(true); - } else { - value_.string_ = other.value_.string_; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -void Value::releasePayload() { - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (isAllocated()) - releasePrefixedStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -void Value::dupMeta(const Value& other) { - comments_ = other.comments_; - start_ = other.start_; - limit_ = other.limit_; -} - -// Access an object value by name, create a null member if it does not exist. -// @pre Type of '*this' is object or null. -// @param key is null-terminated. -Value& Value::resolveReference(const char* key) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::resolveReference(): requires objectValue"); - if (type() == nullValue) - *this = Value(objectValue); - CZString actualKey(key, static_cast(strlen(key)), - CZString::noDuplication); // NOTE! - auto it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -// @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* end) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type() == nullValue) - *this = Value(objectValue); - CZString actualKey(key, static_cast(end - key), - CZString::duplicateOnCopy); - auto it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -Value Value::get(ArrayIndex index, const Value& defaultValue) const { - const Value* value = &((*this)[index]); - return value == &nullSingleton() ? defaultValue : *value; -} - -bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } - -Value const* Value::find(char const* begin, char const* end) const { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::find(begin, end): requires " - "objectValue or nullValue"); - if (type() == nullValue) - return nullptr; - CZString actualKey(begin, static_cast(end - begin), - CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return nullptr; - return &(*it).second; -} -Value* Value::demand(char const* begin, char const* end) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::demand(begin, end): requires " - "objectValue or nullValue"); - return &resolveReference(begin, end); -} -const Value& Value::operator[](const char* key) const { - Value const* found = find(key, key + strlen(key)); - if (!found) - return nullSingleton(); - return *found; -} -Value const& Value::operator[](const String& key) const { - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) - return nullSingleton(); - return *found; -} - -Value& Value::operator[](const char* key) { - return resolveReference(key, key + strlen(key)); -} - -Value& Value::operator[](const String& key) { - return resolveReference(key.data(), key.data() + key.length()); -} - -Value& Value::operator[](const StaticString& key) { - return resolveReference(key.c_str()); -} - -Value& Value::append(const Value& value) { return append(Value(value)); } - -Value& Value::append(Value&& value) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::append: requires arrayValue"); - if (type() == nullValue) { - *this = Value(arrayValue); - } - return this->value_.map_->emplace(size(), std::move(value)).first->second; -} - -bool Value::insert(ArrayIndex index, const Value& newValue) { - return insert(index, Value(newValue)); -} - -bool Value::insert(ArrayIndex index, Value&& newValue) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::insert: requires arrayValue"); - ArrayIndex length = size(); - if (index > length) { - return false; - } - for (ArrayIndex i = length; i > index; i--) { - (*this)[i] = std::move((*this)[i - 1]); - } - (*this)[index] = std::move(newValue); - return true; -} - -Value Value::get(char const* begin, char const* end, - Value const& defaultValue) const { - Value const* found = find(begin, end); - return !found ? defaultValue : *found; -} -Value Value::get(char const* key, Value const& defaultValue) const { - return get(key, key + strlen(key), defaultValue); -} -Value Value::get(String const& key, Value const& defaultValue) const { - return get(key.data(), key.data() + key.length(), defaultValue); -} - -bool Value::removeMember(const char* begin, const char* end, Value* removed) { - if (type() != objectValue) { - return false; - } - CZString actualKey(begin, static_cast(end - begin), - CZString::noDuplication); - auto it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return false; - if (removed) - *removed = std::move(it->second); - value_.map_->erase(it); - return true; -} -bool Value::removeMember(const char* key, Value* removed) { - return removeMember(key, key + strlen(key), removed); -} -bool Value::removeMember(String const& key, Value* removed) { - return removeMember(key.data(), key.data() + key.length(), removed); -} -void Value::removeMember(const char* key) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type() == nullValue) - return; - - CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); - value_.map_->erase(actualKey); -} -void Value::removeMember(const String& key) { removeMember(key.c_str()); } - -bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type() != arrayValue) { - return false; - } - CZString key(index); - auto it = value_.map_->find(key); - if (it == value_.map_->end()) { - return false; - } - if (removed) - *removed = it->second; - ArrayIndex oldSize = size(); - // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i) { - CZString keey(i); - (*value_.map_)[keey] = (*this)[i + 1]; - } - // erase the last one ("leftover") - CZString keyLast(oldSize - 1); - auto itLast = value_.map_->find(keyLast); - value_.map_->erase(itLast); - return true; -} - -bool Value::isMember(char const* begin, char const* end) const { - Value const* value = find(begin, end); - return nullptr != value; -} -bool Value::isMember(char const* key) const { - return isMember(key, key + strlen(key)); -} -bool Value::isMember(String const& key) const { - return isMember(key.data(), key.data() + key.length()); -} - -Value::Members Value::getMemberNames() const { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::getMemberNames(), value must be objectValue"); - if (type() == nullValue) - return Value::Members(); - Members members; - members.reserve(value_.map_->size()); - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) { - members.push_back(String((*it).first.data(), (*it).first.length())); - } - return members; -} - -static bool IsIntegral(double d) { - double integral_part; - return modf(d, &integral_part) == 0.0; -} - -bool Value::isNull() const { return type() == nullValue; } - -bool Value::isBool() const { return type() == booleanValue; } - -bool Value::isInt() const { - switch (type()) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= minInt && value_.int_ <= maxInt; -#else - return true; -#endif - case uintValue: - return value_.uint_ <= UInt(maxInt); - case realValue: - return value_.real_ >= minInt && value_.real_ <= maxInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isUInt() const { - switch (type()) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); -#else - return value_.int_ >= 0; -#endif - case uintValue: -#if defined(JSON_HAS_INT64) - return value_.uint_ <= maxUInt; -#else - return true; -#endif - case realValue: - return value_.real_ >= 0 && value_.real_ <= maxUInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isInt64() const { -#if defined(JSON_HAS_INT64) - switch (type()) { - case intValue: - return true; - case uintValue: - return value_.uint_ <= UInt64(maxInt64); - case realValue: - // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a - // double, so double(maxInt64) will be rounded up to 2^63. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isUInt64() const { -#if defined(JSON_HAS_INT64) - switch (type()) { - case intValue: - return value_.int_ >= 0; - case uintValue: - return true; - case realValue: - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && - IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isIntegral() const { - switch (type()) { - case intValue: - case uintValue: - return true; - case realValue: -#if defined(JSON_HAS_INT64) - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); -#else - return value_.real_ >= minInt && value_.real_ <= maxUInt && - IsIntegral(value_.real_); -#endif // JSON_HAS_INT64 - default: - break; - } - return false; -} - -bool Value::isDouble() const { - return type() == intValue || type() == uintValue || type() == realValue; -} - -bool Value::isNumeric() const { return isDouble(); } - -bool Value::isString() const { return type() == stringValue; } - -bool Value::isArray() const { return type() == arrayValue; } - -bool Value::isObject() const { return type() == objectValue; } - -Value::Comments::Comments(const Comments& that) - : ptr_{cloneUnique(that.ptr_)} {} - -Value::Comments::Comments(Comments&& that) noexcept - : ptr_{std::move(that.ptr_)} {} - -Value::Comments& Value::Comments::operator=(const Comments& that) { - ptr_ = cloneUnique(that.ptr_); - return *this; -} - -Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { - ptr_ = std::move(that.ptr_); - return *this; -} - -bool Value::Comments::has(CommentPlacement slot) const { - return ptr_ && !(*ptr_)[slot].empty(); -} - -String Value::Comments::get(CommentPlacement slot) const { - if (!ptr_) - return {}; - return (*ptr_)[slot]; -} - -void Value::Comments::set(CommentPlacement slot, String comment) { - if (slot >= CommentPlacement::numberOfCommentPlacement) - return; - if (!ptr_) - ptr_ = std::unique_ptr(new Array()); - (*ptr_)[slot] = std::move(comment); -} - -void Value::setComment(String comment, CommentPlacement placement) { - if (!comment.empty() && (comment.back() == '\n')) { - // Always discard trailing newline, to aid indentation. - comment.pop_back(); - } - JSON_ASSERT(!comment.empty()); - JSON_ASSERT_MESSAGE( - comment[0] == '\0' || comment[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - comments_.set(placement, std::move(comment)); -} - -bool Value::hasComment(CommentPlacement placement) const { - return comments_.has(placement); -} - -String Value::getComment(CommentPlacement placement) const { - return comments_.get(placement); -} - -void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } - -void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } - -ptrdiff_t Value::getOffsetStart() const { return start_; } - -ptrdiff_t Value::getOffsetLimit() const { return limit_; } - -String Value::toStyledString() const { - StreamWriterBuilder builder; - - String out = this->hasComment(commentBefore) ? "\n" : ""; - out += Json::writeString(builder, *this); - out += '\n'; - - return out; -} - -Value::const_iterator Value::begin() const { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->begin()); - break; - default: - break; - } - return {}; -} - -Value::const_iterator Value::end() const { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->end()); - break; - default: - break; - } - return {}; -} - -Value::iterator Value::begin() { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->begin()); - break; - default: - break; - } - return iterator(); -} - -Value::iterator Value::end() { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->end()); - break; - default: - break; - } - return iterator(); -} - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() = default; - -PathArgument::PathArgument(ArrayIndex index) - : index_(index), kind_(kindIndex) {} - -PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} - -PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2, - const PathArgument& a3, const PathArgument& a4, - const PathArgument& a5) { - InArgs in; - in.reserve(5); - in.push_back(&a1); - in.push_back(&a2); - in.push_back(&a3); - in.push_back(&a4); - in.push_back(&a5); - makePath(path, in); -} - -void Path::makePath(const String& path, const InArgs& in) { - const char* current = path.c_str(); - const char* end = current + path.length(); - auto itInArg = in.begin(); - while (current != end) { - if (*current == '[') { - ++current; - if (*current == '%') - addPathInArg(path, in, itInArg, PathArgument::kindIndex); - else { - ArrayIndex index = 0; - for (; current != end && *current >= '0' && *current <= '9'; ++current) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back(index); - } - if (current == end || *++current != ']') - invalidPath(path, int(current - path.c_str())); - } else if (*current == '%') { - addPathInArg(path, in, itInArg, PathArgument::kindKey); - ++current; - } else if (*current == '.' || *current == ']') { - ++current; - } else { - const char* beginName = current; - while (current != end && !strchr("[.", *current)) - ++current; - args_.push_back(String(beginName, current)); - } - } -} - -void Path::addPathInArg(const String& /*path*/, const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind) { - if (itInArg == in.end()) { - // Error: missing argument %d - } else if ((*itInArg)->kind_ != kind) { - // Error: bad argument type - } else { - args_.push_back(**itInArg++); - } -} - -void Path::invalidPath(const String& /*path*/, int /*location*/) { - // Error: invalid path. -} - -const Value& Path::resolve(const Value& root) const { - const Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... ) - return Value::nullSingleton(); - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: unable to resolve path (object value expected at position...) - return Value::nullSingleton(); - } - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) { - // Error: unable to resolve path (object has no member named '' at - // position...) - return Value::nullSingleton(); - } - } - } - return *node; -} - -Value Path::resolve(const Value& root, const Value& defaultValue) const { - const Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) - return defaultValue; - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) - return defaultValue; - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) - return defaultValue; - } - } - return *node; -} - -Value& Path::make(Value& root) const { - Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray()) { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - -} // namespace Json diff --git a/Common/json/json_valueiterator.inl b/Common/json/json_valueiterator.inl deleted file mode 100644 index d6128b8edf0..00000000000 --- a/Common/json/json_valueiterator.inl +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() : current_() {} - -ValueIteratorBase::ValueIteratorBase( - const Value::ObjectValues::iterator& current) - : current_(current), isNull_(false) {} - -Value& ValueIteratorBase::deref() { return current_->second; } -const Value& ValueIteratorBase::deref() const { return current_->second; } - -void ValueIteratorBase::increment() { ++current_; } - -void ValueIteratorBase::decrement() { --current_; } - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance(const SelfType& other) const { - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if (isNull_ && other.isNull_) { - return 0; - } - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 - // RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) { - ++myDistance; - } - return myDistance; -} - -bool ValueIteratorBase::isEqual(const SelfType& other) const { - if (isNull_) { - return other.isNull_; - } - return current_ == other.current_; -} - -void ValueIteratorBase::copy(const SelfType& other) { - current_ = other.current_; - isNull_ = other.isNull_; -} - -Value ValueIteratorBase::key() const { - const Value::CZString czstring = (*current_).first; - if (czstring.data()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.data())); - return Value(czstring.data(), czstring.data() + czstring.length()); - } - return Value(czstring.index()); -} - -UInt ValueIteratorBase::index() const { - const Value::CZString czstring = (*current_).first; - if (!czstring.data()) - return czstring.index(); - return Value::UInt(-1); -} - -String ValueIteratorBase::name() const { - char const* keey; - char const* end; - keey = memberName(&end); - if (!keey) - return String(); - return String(keey, end); -} - -char const* ValueIteratorBase::memberName() const { - const char* cname = (*current_).first.data(); - return cname ? cname : ""; -} - -char const* ValueIteratorBase::memberName(char const** end) const { - const char* cname = (*current_).first.data(); - if (!cname) { - *end = nullptr; - return nullptr; - } - *end = cname + (*current_).first.length(); - return cname; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() = default; - -ValueConstIterator::ValueConstIterator( - const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueConstIterator::ValueConstIterator(ValueIterator const& other) - : ValueIteratorBase(other) {} - -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { - copy(other); - return *this; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() = default; - -ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) { - throwRuntimeError("ConstIterator to Iterator should never be allowed."); -} - -ValueIterator::ValueIterator(const ValueIterator& other) = default; - -ValueIterator& ValueIterator::operator=(const SelfType& other) { - copy(other); - return *this; -} - -} // namespace Json diff --git a/Common/json/json_writer.cpp b/Common/json/json_writer.cpp deleted file mode 100644 index 8f0f9cc2d93..00000000000 --- a/Common/json/json_writer.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_tool.h" -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if __cplusplus >= 201103L -#include -#include - -#if !defined(isnan) -#define isnan std::isnan -#endif - -#if !defined(isfinite) -#define isfinite std::isfinite -#endif - -#else -#include -#include - -#if defined(_MSC_VER) -#if !defined(isnan) -#include -#define isnan _isnan -#endif - -#if !defined(isfinite) -#include -#define isfinite _finite -#endif - -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - -#endif //_MSC_VER - -#if defined(__sun) && defined(__SVR4) // Solaris -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#endif - -#if defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) \ - ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) -#endif -#endif -#endif - -#if !defined(isnan) -// IEEE standard states that NaN values will not compare to themselves -#define isnan(x) ((x) != (x)) -#endif - -#if !defined(__APPLE__) -#if !defined(isfinite) -#define isfinite finite -#endif -#endif -#endif - -#if defined(_MSC_VER) -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -using StreamWriterPtr = std::unique_ptr; -#else -using StreamWriterPtr = std::auto_ptr; -#endif - -String valueToString(LargestInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - if (value == Value::minLargestInt) { - uintToString(LargestUInt(Value::maxLargestInt) + 1, current); - *--current = '-'; - } else if (value < 0) { - uintToString(LargestUInt(-value), current); - *--current = '-'; - } else { - uintToString(LargestUInt(value), current); - } - assert(current >= buffer); - return current; -} - -String valueToString(LargestUInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - uintToString(value, current); - assert(current >= buffer); - return current; -} - -#if defined(JSON_HAS_INT64) - -String valueToString(Int value) { return valueToString(LargestInt(value)); } - -String valueToString(UInt value) { return valueToString(LargestUInt(value)); } - -#endif // # if defined(JSON_HAS_INT64) - -namespace { -String valueToString(double value, bool useSpecialFloats, - unsigned int precision, PrecisionType precisionType) { - // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distinguish the - // concepts of reals and integers. - if (!isfinite(value)) { - static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, - {"null", "-1e+9999", "1e+9999"}}; - return reps[useSpecialFloats ? 0 : 1] - [isnan(value) ? 0 : (value < 0) ? 1 : 2]; - } - -#ifdef __clang__ - //Avoid subnormal representation as istream fails on it, thus making roundtrip impossible https://stackoverflow.com/a/48087390 - if(abs(value) < std::numeric_limits::min()) - value = abs(value) > (std::numeric_limits::min()/2) ? std::numeric_limits::min() * !signbit(value): 0; -#endif - - String buffer(size_t(36), '\0'); - while (true) { - int len = jsoncpp_snprintf( - &*buffer.begin(), buffer.size(), - (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", - precision, value); - assert(len >= 0); - auto wouldPrint = static_cast(len); - if (wouldPrint >= buffer.size()) { - buffer.resize(wouldPrint + 1); - continue; - } - buffer.resize(wouldPrint); - break; - } - - buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); - - // try to ensure we preserve the fact that this was given to us as a double on - // input - if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { - buffer += ".0"; - } - - // strip the zero padding from the right - if (precisionType == PrecisionType::decimalPlaces) { - buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision), - buffer.end()); - } - - return buffer; -} -} // namespace - -String valueToString(double value, unsigned int precision, - PrecisionType precisionType) { - return valueToString(value, false, precision, precisionType); -} - -String valueToString(bool value) { return value ? "true" : "false"; } - -static bool doesAnyCharRequireEscaping(char const* s, size_t n) { - assert(s || !n); - - return std::any_of(s, s + n, [](unsigned char c) { - return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; - }); -} - -static unsigned int utf8ToCodepoint(const char*& s, const char* e) { - const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; - - unsigned int firstByte = static_cast(*s); - - if (firstByte < 0x80) - return firstByte; - - if (firstByte < 0xE0) { - if (e - s < 2) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = - ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); - s += 1; - // oversized encoded characters are invalid - return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; - } - - if (firstByte < 0xF0) { - if (e - s < 3) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = ((firstByte & 0x0F) << 12) | - ((static_cast(s[1]) & 0x3F) << 6) | - (static_cast(s[2]) & 0x3F); - s += 2; - // surrogates aren't valid codepoints itself - // shouldn't be UTF-8 encoded - if (calculated >= 0xD800 && calculated <= 0xDFFF) - return REPLACEMENT_CHARACTER; - // oversized encoded characters are invalid - return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; - } - - if (firstByte < 0xF8) { - if (e - s < 4) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = ((firstByte & 0x07) << 18) | - ((static_cast(s[1]) & 0x3F) << 12) | - ((static_cast(s[2]) & 0x3F) << 6) | - (static_cast(s[3]) & 0x3F); - s += 3; - // oversized encoded characters are invalid - return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; - } - - return REPLACEMENT_CHARACTER; -} - -static const char hex2[] = "000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f" - "505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; - -static String toHex16Bit(unsigned int x) { - const unsigned int hi = (x >> 8) & 0xff; - const unsigned int lo = x & 0xff; - String result(4, ' '); - result[0] = hex2[2 * hi]; - result[1] = hex2[2 * hi + 1]; - result[2] = hex2[2 * lo]; - result[3] = hex2[2 * lo + 1]; - return result; -} - -static void appendRaw(String& result, unsigned ch) { - result += static_cast(ch); -} - -static void appendHex(String& result, unsigned ch) { - result.append("\\u").append(toHex16Bit(ch)); -} - -static String valueToQuotedStringN(const char* value, size_t length, - bool emitUTF8 = false) { - if (value == nullptr) - return ""; - - if (!doesAnyCharRequireEscaping(value, length)) - return String("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to String is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL - String result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - char const* end = value + length; - for (const char* c = value; c != end; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - if (codepoint < 0x20) { - appendHex(result, codepoint); - } else { - appendRaw(result, codepoint); - } - } else { - unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` - if (codepoint < 0x20) { - appendHex(result, codepoint); - } else if (codepoint < 0x80) { - appendRaw(result, codepoint); - } else if (codepoint < 0x10000) { - // Basic Multilingual Plane - appendHex(result, codepoint); - } else { - // Extended Unicode. Encode 20 bits as a surrogate pair. - codepoint -= 0x10000; - appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); - appendHex(result, 0xdc00 + (codepoint & 0x3ff)); - } - } - } break; - } - } - result += "\""; - return result; -} - -String valueToQuotedString(const char* value) { - return valueToQuotedStringN(value, strlen(value)); -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() = default; - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - - = default; - -void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } - -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - -String FastWriter::write(const Value& root) { - document_.clear(); - writeValue(root); - if (!omitEndingLineFeed_) - document_ += '\n'; - return document_; -} - -void FastWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; - break; - case intValue: - document_ += valueToString(value.asLargestInt()); - break; - case uintValue: - document_ += valueToString(value.asLargestUInt()); - break; - case realValue: - document_ += valueToString(value.asDouble()); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - document_ += valueToQuotedStringN(str, static_cast(end - str)); - break; - } - case booleanValue: - document_ += valueToString(value.asBool()); - break; - case arrayValue: { - document_ += '['; - ArrayIndex size = value.size(); - for (ArrayIndex index = 0; index < size; ++index) { - if (index > 0) - document_ += ','; - writeValue(value[index]); - } - document_ += ']'; - } break; - case objectValue: { - Value::Members members(value.getMemberNames()); - document_ += '{'; - for (auto it = members.begin(); it != members.end(); ++it) { - const String& name = *it; - if (it != members.begin()) - document_ += ','; - document_ += valueToQuotedStringN(name.data(), name.length()); - document_ += yamlCompatibilityEnabled_ ? ": " : ":"; - writeValue(value[name]); - } - document_ += '}'; - } break; - } -} - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() = default; - -String StyledWriter::write(const Value& root) { - document_.clear(); - addChildValues_ = false; - indentString_.clear(); - writeCommentBeforeValue(root); - writeValue(root); - writeCommentAfterValueOnSameLine(root); - document_ += '\n'; - return document_; -} - -void StyledWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - const String& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - document_ += " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledWriter::writeArrayValue(const Value& value) { - size_t size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultilineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - ArrayIndex index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - writeIndent(); - writeValue(childValue); - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - document_ += "[ "; - for (size_t index = 0; index < size; ++index) { - if (index > 0) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - -bool StyledWriter::isMultilineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledWriter::pushValue(const String& value) { - if (addChildValues_) - childValues_.push_back(value); - else - document_ += value; -} - -void StyledWriter::writeIndent() { - if (!document_.empty()) { - char last = document_[document_.length() - 1]; - if (last == ' ') // already indented - return; - if (last != '\n') // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - -void StyledWriter::writeWithIndent(const String& value) { - writeIndent(); - document_ += value; -} - -void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); } - -void StyledWriter::unindent() { - assert(indentString_.size() >= indentSize_); - indentString_.resize(indentString_.size() - indentSize_); -} - -void StyledWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - document_ += '\n'; - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - document_ += *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - writeIndent(); - ++iter; - } - - // Comments are stripped of trailing newlines, so add one here - document_ += '\n'; -} - -void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - document_ += " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - document_ += '\n'; - document_ += root.getComment(commentAfter); - document_ += '\n'; - } -} - -bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter(String indentation) - : document_(nullptr), indentation_(std::move(indentation)), - addChildValues_(), indented_(false) {} - -void StyledStreamWriter::write(OStream& out, const Value& root) { - document_ = &out; - addChildValues_ = false; - indentString_.clear(); - indented_ = true; - writeCommentBeforeValue(root); - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *document_ << "\n"; - document_ = nullptr; // Forget the stream, for safety. -} - -void StyledStreamWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - const String& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - *document_ << " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledStreamWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultilineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *document_ << "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - -bool StyledStreamWriter::isMultilineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledStreamWriter::pushValue(const String& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *document_ << value; -} - -void StyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - *document_ << '\n' << indentString_; -} - -void StyledStreamWriter::writeWithIndent(const String& value) { - if (!indented_) - writeIndent(); - *document_ << value; - indented_ = false; -} - -void StyledStreamWriter::indent() { indentString_ += indentation_; } - -void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *document_ << *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would include newline - *document_ << indentString_; - ++iter; - } - indented_ = false; -} - -void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - *document_ << ' ' << root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *document_ << root.getComment(commentAfter); - } - indented_ = false; -} - -bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -////////////////////////// -// BuiltStyledStreamWriter - -/// Scoped enums are not available until C++11. -struct CommentStyle { - /// Decide whether to write comments. - enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. - }; -}; - -struct BuiltStyledStreamWriter : public StreamWriter { - BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs, - String colonSymbol, String nullSymbol, - String endingLineFeedSymbol, bool useSpecialFloats, - bool emitUTF8, unsigned int precision, - PrecisionType precisionType); - int write(Value const& root, OStream* sout) override; - -private: - void writeValue(Value const& value); - void writeArrayValue(Value const& value); - bool isMultilineArray(Value const& value); - void pushValue(String const& value); - void writeIndent(); - void writeWithIndent(String const& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(Value const& root); - void writeCommentAfterValueOnSameLine(Value const& root); - static bool hasCommentForValue(const Value& value); - - using ChildValues = std::vector; - - ChildValues childValues_; - String indentString_; - unsigned int rightMargin_; - String indentation_; - CommentStyle::Enum cs_; - String colonSymbol_; - String nullSymbol_; - String endingLineFeedSymbol_; - bool addChildValues_ : 1; - bool indented_ : 1; - bool useSpecialFloats_ : 1; - bool emitUTF8_ : 1; - unsigned int precision_; - PrecisionType precisionType_; -}; -BuiltStyledStreamWriter::BuiltStyledStreamWriter( - String indentation, CommentStyle::Enum cs, String colonSymbol, - String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, - bool emitUTF8, unsigned int precision, PrecisionType precisionType) - : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), - colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), - endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), - addChildValues_(false), indented_(false), - useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), - precision_(precision), precisionType_(precisionType) {} -int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { - sout_ = sout; - addChildValues_ = false; - indented_ = true; - indentString_.clear(); - writeCommentBeforeValue(root); - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *sout_ << endingLineFeedSymbol_; - sout_ = nullptr; - return 0; -} -void BuiltStyledStreamWriter::writeValue(Value const& value) { - switch (value.type()) { - case nullValue: - pushValue(nullSymbol_); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, - precisionType_)); - break; - case stringValue: { - // Is NULL is possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue( - valueToQuotedStringN(str, static_cast(end - str), emitUTF8_)); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - String const& name = *it; - Value const& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent( - valueToQuotedStringN(name.data(), name.length(), emitUTF8_)); - *sout_ << colonSymbol_; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); - if (isMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - Value const& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *sout_ << "["; - if (!indentation_.empty()) - *sout_ << " "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *sout_ << ((!indentation_.empty()) ? ", " : ","); - *sout_ << childValues_[index]; - } - if (!indentation_.empty()) - *sout_ << " "; - *sout_ << "]"; - } - } -} - -bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - Value const& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void BuiltStyledStreamWriter::pushValue(String const& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *sout_ << value; -} - -void BuiltStyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - - if (!indentation_.empty()) { - // In this case, drop newlines too. - *sout_ << '\n' << indentString_; - } -} - -void BuiltStyledStreamWriter::writeWithIndent(String const& value) { - if (!indented_) - writeIndent(); - *sout_ << value; - indented_ = false; -} - -void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } - -void BuiltStyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) - return; - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *sout_ << *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would write extra newline - *sout_ << indentString_; - ++iter; - } - indented_ = false; -} - -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( - Value const& root) { - if (cs_ == CommentStyle::None) - return; - if (root.hasComment(commentAfterOnSameLine)) - *sout_ << " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *sout_ << root.getComment(commentAfter); - } -} - -// static -bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -/////////////// -// StreamWriter - -StreamWriter::StreamWriter() : sout_(nullptr) {} -StreamWriter::~StreamWriter() = default; -StreamWriter::Factory::~Factory() = default; -StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } -StreamWriterBuilder::~StreamWriterBuilder() = default; -StreamWriter* StreamWriterBuilder::newStreamWriter() const { - const String indentation = settings_["indentation"].asString(); - const String cs_str = settings_["commentStyle"].asString(); - const String pt_str = settings_["precisionType"].asString(); - const bool eyc = settings_["enableYAMLCompatibility"].asBool(); - const bool dnp = settings_["dropNullPlaceholders"].asBool(); - const bool usf = settings_["useSpecialFloats"].asBool(); - const bool emitUTF8 = settings_["emitUTF8"].asBool(); - unsigned int pre = settings_["precision"].asUInt(); - CommentStyle::Enum cs = CommentStyle::All; - if (cs_str == "All") { - cs = CommentStyle::All; - } else if (cs_str == "None") { - cs = CommentStyle::None; - } else { - throwRuntimeError("commentStyle must be 'All' or 'None'"); - } - PrecisionType precisionType(significantDigits); - if (pt_str == "significant") { - precisionType = PrecisionType::significantDigits; - } else if (pt_str == "decimal") { - precisionType = PrecisionType::decimalPlaces; - } else { - throwRuntimeError("precisionType must be 'significant' or 'decimal'"); - } - String colonSymbol = " : "; - if (eyc) { - colonSymbol = ": "; - } else if (indentation.empty()) { - colonSymbol = ":"; - } - String nullSymbol = "null"; - if (dnp) { - nullSymbol.clear(); - } - if (pre > 17) - pre = 17; - String endingLineFeedSymbol; - return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, - endingLineFeedSymbol, usf, emitUTF8, pre, - precisionType); -} - -bool StreamWriterBuilder::validate(Json::Value* invalid) const { - static const auto& valid_keys = *new std::set{ - "indentation", - "commentStyle", - "enableYAMLCompatibility", - "dropNullPlaceholders", - "useSpecialFloats", - "emitUTF8", - "precision", - "precisionType", - }; - for (auto si = settings_.begin(); si != settings_.end(); ++si) { - auto key = si.name(); - if (valid_keys.count(key)) - continue; - if (invalid) - (*invalid)[key] = *si; - else - return false; - } - return invalid ? invalid->empty() : true; -} - -Value& StreamWriterBuilder::operator[](const String& key) { - return settings_[key]; -} -// static -void StreamWriterBuilder::setDefaults(Json::Value* settings) { - //! [StreamWriterBuilderDefaults] - (*settings)["commentStyle"] = "All"; - (*settings)["indentation"] = "\t"; - (*settings)["enableYAMLCompatibility"] = false; - (*settings)["dropNullPlaceholders"] = false; - (*settings)["useSpecialFloats"] = false; - (*settings)["emitUTF8"] = false; - (*settings)["precision"] = 17; - (*settings)["precisionType"] = "significant"; - //! [StreamWriterBuilderDefaults] -} - -String writeString(StreamWriter::Factory const& factory, Value const& root) { - OStringStream sout; - StreamWriterPtr const writer(factory.newStreamWriter()); - writer->write(root, &sout); - return sout.str(); -} - -OStream& operator<<(OStream& sout, Value const& root) { - StreamWriterBuilder builder; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout; -} - -} // namespace Json diff --git a/Common/json/reader.h b/Common/json/reader.h deleted file mode 100644 index 46975d86fe8..00000000000 --- a/Common/json/reader.h +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_READER_H_INCLUDED -#define JSON_READER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_features.h" -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push) -#pragma pack() - -namespace Json { - -/** \brief Unserialize a JSON document into a - * Value. - * - * \deprecated Use CharReader and CharReaderBuilder. - */ - -class JSON_API Reader { -public: - using Char = char; - using Location = const Char*; - - /** \brief An error tagged with where in the JSON text it was encountered. - * - * The offsets give the [start, limit) range of bytes within the text. Note - * that this is bytes, not codepoints. - */ - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - String message; - }; - - /** \brief Constructs a Reader allowing all features for parsing. - * \deprecated Use CharReader and CharReaderBuilder. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set for parsing. - * \deprecated Use CharReader and CharReaderBuilder. - */ - Reader(const Features& features); - - /** \brief Read a Value from a JSON - * document. - * - * \param document UTF-8 encoded string containing the document - * to read. - * \param[out] root Contains the root value of the document if it - * was successfully parsed. - * \param collectComments \c true to collect comment and allow writing - * them back during serialization, \c false to - * discard comments. This parameter is ignored - * if Features::allowComments_ is \c false. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - bool parse(const std::string& document, Value& root, - bool collectComments = true); - - /** \brief Read a Value from a JSON - * document. - * - * \param beginDoc Pointer on the beginning of the UTF-8 encoded - * string of the document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string - * of the document to read. Must be >= beginDoc. - * \param[out] root Contains the root value of the document if it - * was successfully parsed. - * \param collectComments \c true to collect comment and allow writing - * them back during serialization, \c false to - * discard comments. This parameter is ignored - * if Features::allowComments_ is \c false. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - bool parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments = true); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse(IStream& is, Value& root, bool collectComments = true); - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * - * \return Formatted error message with the list of errors with their - * location in the parsed document. An empty string is returned if no error - * occurred during parsing. - * \deprecated Use getFormattedErrorMessages() instead (typo fix). - */ - JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") - String getFormatedErrorMessages() const; - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * - * \return Formatted error message with the list of errors with their - * location in the parsed document. An empty string is returned if no error - * occurred during parsing. - */ - String getFormattedErrorMessages() const; - - /** \brief Returns a vector of structured errors encountered while parsing. - * - * \return A (possibly empty) vector of StructuredError objects. Currently - * only one error can be returned, but the caller should tolerate multiple - * errors. This can occur if the parser recovers from a non-fatal parse - * error and then encounters additional errors. - */ - std::vector getStructuredErrors() const; - - /** \brief Add a semantic error message. - * - * \param value JSON Value location associated with the error - * \param message The error message. - * \return \c true if the error was successfully added, \c false if the Value - * offset exceeds the document size. - */ - bool pushError(const Value& value, const String& message); - - /** \brief Add a semantic error message with extra context. - * - * \param value JSON Value location associated with the error - * \param message The error message. - * \param extra Additional JSON Value location to contextualize the error - * \return \c true if the error was successfully added, \c false if either - * Value offset exceeds the document size. - */ - bool pushError(const Value& value, const String& message, const Value& extra); - - /** \brief Return whether there are any errors. - * - * \return \c true if there are no errors to report \c false if errors have - * occurred. - */ - bool good() const; - -private: - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - String message_; - Location extra_; - }; - - using Errors = std::deque; - - bool readToken(Token& token); - void skipSpaces(); - bool match(const Char* pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, String& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, Location extra = nullptr); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void getLocationLineAndColumn(Location location, int& line, - int& column) const; - String getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - static bool containsNewLine(Location begin, Location end); - static String normalizeEOL(Location begin, Location end); - - using Nodes = std::stack; - Nodes nodes_; - Errors errors_; - String document_; - Location begin_{}; - Location end_{}; - Location current_{}; - Location lastValueEnd_{}; - Value* lastValue_{}; - String commentsBefore_; - Features features_; - bool collectComments_{}; -}; // Reader - -/** Interface for reading JSON from a char array. - */ -class JSON_API CharReader { -public: - virtual ~CharReader() = default; - /** \brief Read a Value from a JSON - * document. The document must be a UTF-8 encoded string containing the - * document to read. - * - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string - * of the document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the - * document to read. Must be >= beginDoc. - * \param[out] root Contains the root value of the document if it was - * successfully parsed. - * \param[out] errs Formatted error messages (if not NULL) a user - * friendly string that lists errors in the parsed - * document. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) = 0; - - class JSON_API Factory { - public: - virtual ~Factory() = default; - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual CharReader* newCharReader() const = 0; - }; // Factory -}; // CharReader - -/** \brief Build a CharReader implementation. - * - * Usage: - * \code - * using namespace Json; - * CharReaderBuilder builder; - * builder["collectComments"] = false; - * Value value; - * String errs; - * bool ok = parseFromStream(builder, std::cin, &value, &errs); - * \endcode - */ -class JSON_API CharReaderBuilder : public CharReader::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - * These are case-sensitive. - * Available settings (case-sensitive): - * - `"collectComments": false or true` - * - true to collect comment and allow writing them back during - * serialization, false to discard comments. This parameter is ignored - * if allowComments is false. - * - `"allowComments": false or true` - * - true if comments are allowed. - * - `"allowTrailingCommas": false or true` - * - true if trailing commas in objects and arrays are allowed. - * - `"strictRoot": false or true` - * - true if root must be either an array or an object value - * - `"allowDroppedNullPlaceholders": false or true` - * - true if dropped null placeholders are allowed. (See - * StreamWriterBuilder.) - * - `"allowNumericKeys": false or true` - * - true if numeric object keys are allowed. - * - `"allowSingleQuotes": false or true` - * - true if '' are allowed for strings (both keys and values) - * - `"stackLimit": integer` - * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an - * exception. - * - This is a security issue (seg-faults caused by deeply nested JSON), so - * the default is low. - * - `"failIfExtra": false or true` - * - If true, `parse()` returns false when extra non-whitespace trails the - * JSON value in the input string. - * - `"rejectDupKeys": false or true` - * - If true, `parse()` returns false when a key is duplicated within an - * object. - * - `"allowSpecialFloats": false or true` - * - If true, special float values (NaNs and infinities) are allowed and - * their values are lossfree restorable. - * - `"skipBom": false or true` - * - If true, if the input starts with the Unicode byte order mark (BOM), - * it is skipped. - * - * You can examine 'settings_` yourself to see the defaults. You can also - * write and read them just like any JSON Value. - * \sa setDefaults() - */ - Json::Value settings_; - - CharReaderBuilder(); - ~CharReaderBuilder() override; - - CharReader* newCharReader() const override; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - - /** A simple way to update a specific setting. - */ - Value& operator[](const String& key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults - */ - static void setDefaults(Json::Value* settings); - /** Same as old Features::strictMode(). - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode - */ - static void strictMode(Json::Value* settings); -}; - -/** Consume entire stream and use its begin/end. - * Someday we might have a real StreamReader, but for now this - * is convenient. - */ -bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, - String* errs); - -/** \brief Read from 'sin' into 'root'. - * - * Always keep comments from the input JSON. - * - * This can be used to read a file into a particular sub-object. - * For example: - * \code - * Json::Value root; - * cin >> root["dir"]["file"]; - * cout << root; - * \endcode - * Result: - * \verbatim - * { - * "dir": { - * "file": { - * // The input stream JSON would be nested here. - * } - * } - * } - * \endverbatim - * \throw std::exception on parse error. - * \see Json::operator<<() - */ -JSON_API IStream& operator>>(IStream&, Value&); - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_READER_H_INCLUDED diff --git a/Common/json/value.h b/Common/json/value.h deleted file mode 100644 index 15c517e1204..00000000000 --- a/Common/json/value.h +++ /dev/null @@ -1,936 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_H_INCLUDED -#define JSON_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -// Conditional NORETURN attribute on the throw functions would: -// a) suppress false positives from static code analysis -// b) possibly improve optimization opportunities. -#if !defined(JSONCPP_NORETURN) -#if defined(_MSC_VER) && _MSC_VER == 1800 -#define JSONCPP_NORETURN __declspec(noreturn) -#else -#define JSONCPP_NORETURN [[noreturn]] -#endif -#endif - -// Support for '= delete' with template declarations was a late addition -// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 -// even though these declare themselves to be c++11 compilers. -#if !defined(JSONCPP_TEMPLATE_DELETE) -#if defined(__clang__) && defined(__apple_build_version__) -#if __apple_build_version__ <= 8000042 -#define JSONCPP_TEMPLATE_DELETE -#endif -#elif defined(__clang__) -#if __clang_major__ == 3 && __clang_minor__ <= 8 -#define JSONCPP_TEMPLATE_DELETE -#endif -#endif -#if !defined(JSONCPP_TEMPLATE_DELETE) -#define JSONCPP_TEMPLATE_DELETE = delete -#endif -#endif - -#include -#include -#include -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251 4275) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push) -#pragma pack() - -/** \brief JSON (JavaScript Object Notation). - */ -namespace Json { - -#if JSON_USE_EXCEPTION -/** Base class for all exceptions we throw. - * - * We use nothing but these internally. Of course, STL can throw others. - */ -class JSON_API Exception : public std::exception { -public: - Exception(String msg); - ~Exception() noexcept override; - char const* what() const noexcept override; - -protected: - String msg_; -}; - -/** Exceptions which the user cannot easily avoid. - * - * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input - * - * \remark derived from Json::Exception - */ -class JSON_API RuntimeError : public Exception { -public: - RuntimeError(String const& msg); -}; - -/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. - * - * These are precondition-violations (user bugs) and internal errors (our bugs). - * - * \remark derived from Json::Exception - */ -class JSON_API LogicError : public Exception { -public: - LogicError(String const& msg); -}; -#endif - -/// used internally -JSONCPP_NORETURN void throwRuntimeError(String const& msg); -/// used internally -JSONCPP_NORETURN void throwLogicError(String const& msg); - -/** \brief Type of the value held by a Value object. - */ -enum ValueType { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). -}; - -enum CommentPlacement { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for - /// root value) - numberOfCommentPlacement -}; - -/** \brief Type of precision for formatting of real values. - */ -enum PrecisionType { - significantDigits = 0, ///< we set max number of significant digits in string - decimalPlaces ///< we set max number of digits after "." in string -}; - -/** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignment takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ -class JSON_API StaticString { -public: - explicit StaticString(const char* czstring) : c_str_(czstring) {} - - operator const char*() const { return c_str_; } - - const char* c_str() const { return c_str_; } - -private: - const char* c_str_; -}; - -/** \brief Represents a JSON value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * Values of an #objectValue or #arrayValue can be accessed using operator[]() - * methods. - * Non-const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resized and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtain default value in the case the - * required element does not exist. - * - * It is possible to iterate over the list of member keys of an object using - * the getMemberNames() method. - * - * \note #Value string-length fit in size_t, but keys must be < 2^30. - * (The reason is an implementation detail.) A #CharReader will raise an - * exception if a bound is exceeded to avoid security holes in your app, - * but the Value API does *not* check bounds. That is the responsibility - * of the caller. - */ -class JSON_API Value { - friend class ValueIteratorBase; - -public: - using Members = std::vector; - using iterator = ValueIterator; - using const_iterator = ValueConstIterator; - using UInt = Json::UInt; - using Int = Json::Int; -#if defined(JSON_HAS_INT64) - using UInt64 = Json::UInt64; - using Int64 = Json::Int64; -#endif // defined(JSON_HAS_INT64) - using LargestInt = Json::LargestInt; - using LargestUInt = Json::LargestUInt; - using ArrayIndex = Json::ArrayIndex; - - // Required for boost integration, e. g. BOOST_TEST - using value_type = std::string; - -#if JSON_USE_NULLREF - // Binary compatibility kludges, do not use. - static const Value& null; - static const Value& nullRef; -#endif - - // null and nullRef are deprecated, use this instead. - static Value const& nullSingleton(); - - /// Minimum signed integer value that can be stored in a Json::Value. - static constexpr LargestInt minLargestInt = - LargestInt(~(LargestUInt(-1) / 2)); - /// Maximum signed integer value that can be stored in a Json::Value. - static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); - /// Maximum unsigned integer value that can be stored in a Json::Value. - static constexpr LargestUInt maxLargestUInt = LargestUInt(-1); - - /// Minimum signed int value that can be stored in a Json::Value. - static constexpr Int minInt = Int(~(UInt(-1) / 2)); - /// Maximum signed int value that can be stored in a Json::Value. - static constexpr Int maxInt = Int(UInt(-1) / 2); - /// Maximum unsigned int value that can be stored in a Json::Value. - static constexpr UInt maxUInt = UInt(-1); - -#if defined(JSON_HAS_INT64) - /// Minimum signed 64 bits int value that can be stored in a Json::Value. - static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2)); - /// Maximum signed 64 bits int value that can be stored in a Json::Value. - static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2); - /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. - static constexpr UInt64 maxUInt64 = UInt64(-1); -#endif // defined(JSON_HAS_INT64) - /// Default precision for real value for string representation. - static constexpr UInt defaultRealPrecision = 17; - // The constant is hard-coded because some compiler have trouble - // converting Value::maxUInt64 to a double correctly (AIX/xlC). - // Assumes that UInt64 is a 64 bits integer. - static constexpr double maxUInt64AsDouble = 18446744073709551615.0; -// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler -// when using gcc and clang backend compilers. CZString -// cannot be defined as private. See issue #486 -#ifdef __NVCC__ -public: -#else -private: -#endif -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - class CZString { - public: - enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; - CZString(ArrayIndex index); - CZString(char const* str, unsigned length, DuplicationPolicy allocate); - CZString(CZString const& other); - CZString(CZString&& other) noexcept; - ~CZString(); - CZString& operator=(const CZString& other); - CZString& operator=(CZString&& other) noexcept; - - bool operator<(CZString const& other) const; - bool operator==(CZString const& other) const; - ArrayIndex index() const; - // const char* c_str() const; ///< \deprecated - char const* data() const; - unsigned length() const; - bool isStaticString() const; - - private: - void swap(CZString& other); - - struct StringStorage { - unsigned policy_ : 2; - unsigned length_ : 30; // 1GB max - }; - - char const* cstr_; // actually, a prefixed string, unless policy is noDup - union { - ArrayIndex index_; - StringStorage storage_; - }; - }; - -public: - typedef std::map ObjectValues; -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -public: - /** - * \brief Create a default Value of the given type. - * - * This is a very useful constructor. - * To create an empty array, pass arrayValue. - * To create an empty object, pass objectValue. - * Another Value can then be set to this one by assignment. - * This is useful since clear() and resize() will not alter types. - * - * Examples: - * \code - * Json::Value null_value; // null - * Json::Value arr_value(Json::arrayValue); // [] - * Json::Value obj_value(Json::objectValue); // {} - * \endcode - */ - Value(ValueType type = nullValue); - Value(Int value); - Value(UInt value); -#if defined(JSON_HAS_INT64) - Value(Int64 value); - Value(UInt64 value); -#endif // if defined(JSON_HAS_INT64) - Value(double value); - Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) - Value(const char* begin, const char* end); ///< Copy all, incl zeroes. - /** - * \brief Constructs a value from a static string. - * - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to - * this constructor. - * - * \note This works only for null-terminated strings. (We cannot change the - * size of this class, so we have nowhere to store the length, which might be - * computed later for various operations.) - * - * Example of usage: - * \code - * static StaticString foo("some text"); - * Json::Value aValue(foo); - * \endcode - */ - Value(const StaticString& value); - Value(const String& value); - Value(bool value); - Value(std::nullptr_t ptr) = delete; - Value(const Value& other); - Value(Value&& other) noexcept; - ~Value(); - - /// \note Overwrite existing comments. To preserve comments, use - /// #swapPayload(). - Value& operator=(const Value& other); - Value& operator=(Value&& other) noexcept; - - /// Swap everything. - void swap(Value& other); - /// Swap values but leave comments and source offsets in place. - void swapPayload(Value& other); - - /// copy everything. - void copy(const Value& other); - /// copy values but leave comments and source offsets in place. - void copyPayload(const Value& other); - - ValueType type() const; - - /// Compare payload only, not comments etc. - bool operator<(const Value& other) const; - bool operator<=(const Value& other) const; - bool operator>=(const Value& other) const; - bool operator>(const Value& other) const; - bool operator==(const Value& other) const; - bool operator!=(const Value& other) const; - int compare(const Value& other) const; - - const char* asCString() const; ///< Embedded zeroes could cause you trouble! -#if JSONCPP_USING_SECURE_MEMORY - unsigned getCStringLength() const; // Allows you to understand the length of - // the CString -#endif - String asString() const; ///< Embedded zeroes are possible. - /** Get raw char* of string-value. - * \return false if !string. (Seg-fault if str or end are NULL.) - */ - bool getString(char const** begin, char const** end) const; - Int asInt() const; - UInt asUInt() const; -#if defined(JSON_HAS_INT64) - Int64 asInt64() const; - UInt64 asUInt64() const; -#endif // if defined(JSON_HAS_INT64) - LargestInt asLargestInt() const; - LargestUInt asLargestUInt() const; - float asFloat() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isInt64() const; - bool isUInt() const; - bool isUInt64() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - /// The `as` and `is` member function templates and specializations. - template T as() const JSONCPP_TEMPLATE_DELETE; - template bool is() const JSONCPP_TEMPLATE_DELETE; - - bool isConvertibleTo(ValueType other) const; - - /// Number of values in array or object - ArrayIndex size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return !isNull() - explicit operator bool() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to newSize elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize(ArrayIndex newSize); - - ///@{ - /// Access an array element (zero based index). If the array contains less - /// than index element, then null value are inserted in the array so that - /// its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value& operator[](ArrayIndex index); - Value& operator[](int index); - ///@} - - ///@{ - /// Access an array element (zero based index). - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value& operator[](ArrayIndex index) const; - const Value& operator[](int index) const; - ///@} - - /// If the array contains at least index+1 elements, returns the element - /// value, otherwise returns defaultValue. - Value get(ArrayIndex index, const Value& defaultValue) const; - /// Return true if index < size(). - bool isValidIndex(ArrayIndex index) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value& append(const Value& value); - Value& append(Value&& value); - - /// \brief Insert value in array at specific index - bool insert(ArrayIndex index, const Value& newValue); - bool insert(ArrayIndex index, Value&& newValue); - - /// Access an object value by name, create a null member if it does not exist. - /// \note Because of our implementation, keys are limited to 2^30 -1 chars. - /// Exceeding that will cause an exception. - Value& operator[](const char* key); - /// Access an object value by name, returns null if there is no member with - /// that name. - const Value& operator[](const char* key) const; - /// Access an object value by name, create a null member if it does not exist. - /// \param key may contain embedded nulls. - Value& operator[](const String& key); - /// Access an object value by name, returns null if there is no member with - /// that name. - /// \param key may contain embedded nulls. - const Value& operator[](const String& key) const; - /** \brief Access an object value by name, create a null member if it does not - * exist. - * - * If the object has no entry for that name, then the member name used to - * store the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value& operator[](const StaticString& key); - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - Value get(const char* key, const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \note key may contain embedded nulls. - Value get(const char* begin, const char* end, - const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \param key may contain embedded nulls. - Value get(const String& key, const Value& defaultValue) const; - /// Most general and efficient version of isMember()const, get()const, - /// and operator[]const - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - Value const* find(char const* begin, char const* end) const; - /// Most general and efficient version of object-mutators. - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. - Value* demand(char const* begin, char const* end); - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - void removeMember(const char* key); - /// Same as removeMember(const char*) - /// \param key may contain embedded nulls. - void removeMember(const String& key); - /// Same as removeMember(const char* begin, const char* end, Value* removed), - /// but 'key' is null-terminated. - bool removeMember(const char* key, Value* removed); - /** \brief Remove the named map member. - * - * Update 'removed' iff removed. - * \param key may contain embedded nulls. - * \return true iff removed (no exceptions) - */ - bool removeMember(String const& key, Value* removed); - /// Same as removeMember(String const& key, Value* removed) - bool removeMember(const char* begin, const char* end, Value* removed); - /** \brief Remove the indexed array element. - * - * O(n) expensive operations. - * Update 'removed' iff removed. - * \return true if removed (no exceptions) - */ - bool removeIndex(ArrayIndex index, Value* removed); - - /// Return true if the object has a member named key. - /// \note 'key' must be null-terminated. - bool isMember(const char* key) const; - /// Return true if the object has a member named key. - /// \param key may contain embedded nulls. - bool isMember(const String& key) const; - /// Same as isMember(String const& key)const - bool isMember(const char* begin, const char* end) const; - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - - /// \deprecated Always pass len. - JSONCPP_DEPRECATED("Use setComment(String const&) instead.") - void setComment(const char* comment, CommentPlacement placement) { - setComment(String(comment, strlen(comment)), placement); - } - /// Comments must be //... or /* ... */ - void setComment(const char* comment, size_t len, CommentPlacement placement) { - setComment(String(comment, len), placement); - } - /// Comments must be //... or /* ... */ - void setComment(String comment, CommentPlacement placement); - bool hasComment(CommentPlacement placement) const; - /// Include delimiters and embedded newlines. - String getComment(CommentPlacement placement) const; - - String toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - // Accessors for the [start, limit) range of bytes within the JSON text from - // which this value was parsed, if any. - void setOffsetStart(ptrdiff_t start); - void setOffsetLimit(ptrdiff_t limit); - ptrdiff_t getOffsetStart() const; - ptrdiff_t getOffsetLimit() const; - -private: - void setType(ValueType v) { - bits_.value_type_ = static_cast(v); - } - bool isAllocated() const { return bits_.allocated_; } - void setIsAllocated(bool v) { bits_.allocated_ = v; } - - void initBasic(ValueType type, bool allocated = false); - void dupPayload(const Value& other); - void releasePayload(); - void dupMeta(const Value& other); - - Value& resolveReference(const char* key); - Value& resolveReference(const char* key, const char* end); - - // struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder { - LargestInt int_; - LargestUInt uint_; - double real_; - bool bool_; - char* string_; // if allocated_, ptr to { unsigned, char[] }. - ObjectValues* map_; - } value_; - - struct { - // Really a ValueType, but types should agree for bitfield packing. - unsigned int value_type_ : 8; - // Unless allocated_, string_ must be null-terminated. - unsigned int allocated_ : 1; - } bits_; - - class Comments { - public: - Comments() = default; - Comments(const Comments& that); - Comments(Comments&& that) noexcept; - Comments& operator=(const Comments& that); - Comments& operator=(Comments&& that) noexcept; - bool has(CommentPlacement slot) const; - String get(CommentPlacement slot) const; - void set(CommentPlacement slot, String comment); - - private: - using Array = std::array; - std::unique_ptr ptr_; - }; - Comments comments_; - - // [start, limit) byte offsets in the source JSON text from which this Value - // was extracted. - ptrdiff_t start_; - ptrdiff_t limit_; -}; - -template <> inline bool Value::as() const { return asBool(); } -template <> inline bool Value::is() const { return isBool(); } - -template <> inline Int Value::as() const { return asInt(); } -template <> inline bool Value::is() const { return isInt(); } - -template <> inline UInt Value::as() const { return asUInt(); } -template <> inline bool Value::is() const { return isUInt(); } - -#if defined(JSON_HAS_INT64) -template <> inline Int64 Value::as() const { return asInt64(); } -template <> inline bool Value::is() const { return isInt64(); } - -template <> inline UInt64 Value::as() const { return asUInt64(); } -template <> inline bool Value::is() const { return isUInt64(); } -#endif - -template <> inline double Value::as() const { return asDouble(); } -template <> inline bool Value::is() const { return isDouble(); } - -template <> inline String Value::as() const { return asString(); } -template <> inline bool Value::is() const { return isString(); } - -/// These `as` specializations are type conversions, and do not have a -/// corresponding `is`. -template <> inline float Value::as() const { return asFloat(); } -template <> inline const char* Value::as() const { - return asCString(); -} - -/** \brief Experimental and untested: represents an element of the "path" to - * access a node. - */ -class JSON_API PathArgument { -public: - friend class Path; - - PathArgument(); - PathArgument(ArrayIndex index); - PathArgument(const char* key); - PathArgument(String key); - -private: - enum Kind { kindNone = 0, kindIndex, kindKey }; - String key_; - ArrayIndex index_{}; - Kind kind_{kindNone}; -}; - -/** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provided as parameter - */ -class JSON_API Path { -public: - Path(const String& path, const PathArgument& a1 = PathArgument(), - const PathArgument& a2 = PathArgument(), - const PathArgument& a3 = PathArgument(), - const PathArgument& a4 = PathArgument(), - const PathArgument& a5 = PathArgument()); - - const Value& resolve(const Value& root) const; - Value resolve(const Value& root, const Value& defaultValue) const; - /// Creates the "path" to access the specified node and returns a reference on - /// the node. - Value& make(Value& root) const; - -private: - using InArgs = std::vector; - using Args = std::vector; - - void makePath(const String& path, const InArgs& in); - void addPathInArg(const String& path, const InArgs& in, - InArgs::const_iterator& itInArg, PathArgument::Kind kind); - static void invalidPath(const String& path, int location); - - Args args_; -}; - -/** \brief base class for Value iterators. - * - */ -class JSON_API ValueIteratorBase { -public: - using iterator_category = std::bidirectional_iterator_tag; - using size_t = unsigned int; - using difference_type = int; - using SelfType = ValueIteratorBase; - - bool operator==(const SelfType& other) const { return isEqual(other); } - - bool operator!=(const SelfType& other) const { return !isEqual(other); } - - difference_type operator-(const SelfType& other) const { - return other.computeDistance(*this); - } - - /// Return either the index or the member name of the referenced value as a - /// Value. - Value key() const; - - /// Return the index of the referenced Value, or -1 if it is not an - /// arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value, or "" if it is not an - /// objectValue. - /// \note Avoid `c_str()` on result, as embedded zeroes are possible. - String name() const; - - /// Return the member name of the referenced Value. "" if it is not an - /// objectValue. - /// \deprecated This cannot be used for UTF-8 strings, since there can be - /// embedded nulls. - JSONCPP_DEPRECATED("Use `key = name();` instead.") - char const* memberName() const; - /// Return the member name of the referenced Value, or NULL if it is not an - /// objectValue. - /// \note Better version than memberName(). Allows embedded nulls. - char const* memberName(char const** end) const; - -protected: - /*! Internal utility functions to assist with implementing - * other iterator functions. The const and non-const versions - * of the "deref" protected methods expose the protected - * current_ member variable in a way that can often be - * optimized away by the compiler. - */ - const Value& deref() const; - Value& deref(); - - void increment(); - - void decrement(); - - difference_type computeDistance(const SelfType& other) const; - - bool isEqual(const SelfType& other) const; - - void copy(const SelfType& other); - -private: - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_{true}; - -public: - // For some reason, BORLAND needs these at the end, rather - // than earlier. No idea why. - ValueIteratorBase(); - explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); -}; - -/** \brief const iterator for object and array value. - * - */ -class JSON_API ValueConstIterator : public ValueIteratorBase { - friend class Value; - -public: - using value_type = const Value; - // typedef unsigned int size_t; - // typedef int difference_type; - using reference = const Value&; - using pointer = const Value*; - using SelfType = ValueConstIterator; - - ValueConstIterator(); - ValueConstIterator(ValueIterator const& other); - -private: - /*! \internal Use by Value to create an iterator. - */ - explicit ValueConstIterator(const Value::ObjectValues::iterator& current); - -public: - SelfType& operator=(const ValueIteratorBase& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - reference operator*() const { return deref(); } - - pointer operator->() const { return &deref(); } -}; - -/** \brief Iterator for object and array value. - */ -class JSON_API ValueIterator : public ValueIteratorBase { - friend class Value; - -public: - using value_type = Value; - using size_t = unsigned int; - using difference_type = int; - using reference = Value&; - using pointer = Value*; - using SelfType = ValueIterator; - - ValueIterator(); - explicit ValueIterator(const ValueConstIterator& other); - ValueIterator(const ValueIterator& other); - -private: - /*! \internal Use by Value to create an iterator. - */ - explicit ValueIterator(const Value::ObjectValues::iterator& current); - -public: - SelfType& operator=(const SelfType& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - /*! The return value of non-const iterators can be - * changed, so the these functions are not const - * because the returned references/pointers can be used - * to change state of the base class. - */ - reference operator*() const { return const_cast(deref()); } - pointer operator->() const { return const_cast(&deref()); } -}; - -inline void swap(Value& a, Value& b) { a.swap(b); } - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_H_INCLUDED diff --git a/Common/json/version.h b/Common/json/version.h deleted file mode 100644 index e931d0383e3..00000000000 --- a/Common/json/version.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef JSON_VERSION_H_INCLUDED -#define JSON_VERSION_H_INCLUDED - -// Note: version must be updated in three places when doing a release. This -// annoying process ensures that amalgamate, CMake, and meson all report the -// correct version. -// 1. /meson.build -// 2. /include/json/version.h -// 3. /CMakeLists.txt -// IMPORTANT: also update the SOVERSION!! - -#define JSONCPP_VERSION_STRING "1.9.5" -#define JSONCPP_VERSION_MAJOR 1 -#define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 5 -#define JSONCPP_VERSION_QUALIFIER -#define JSONCPP_VERSION_HEXA \ - ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ - (JSONCPP_VERSION_PATCH << 8)) - -#ifdef JSONCPP_USING_SECURE_MEMORY -#undef JSONCPP_USING_SECURE_MEMORY -#endif -#define JSONCPP_USING_SECURE_MEMORY 0 -// If non-zero, the library zeroes any memory that it has allocated before -// it frees its memory. - -#endif // JSON_VERSION_H_INCLUDED diff --git a/Common/json/writer.h b/Common/json/writer.h deleted file mode 100644 index 7d8cf4d63bc..00000000000 --- a/Common/json/writer.h +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_WRITER_H_INCLUDED -#define JSON_WRITER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push) -#pragma pack() - -namespace Json { - -class Value; - -/** - * - * Usage: - * \code - * using namespace Json; - * void writeToStdout(StreamWriter::Factory const& factory, Value const& value) - * { std::unique_ptr const writer( factory.newStreamWriter()); - * writer->write(value, &std::cout); - * std::cout << std::endl; // add lf and flush - * } - * \endcode - */ -class JSON_API StreamWriter { -protected: - OStream* sout_; // not owned; will not delete -public: - StreamWriter(); - virtual ~StreamWriter(); - /** Write Value into document as configured in sub-class. - * Do not take ownership of sout, but maintain a reference during function. - * \pre sout != NULL - * \return zero on success (For now, we always return zero, so check the - * stream instead.) \throw std::exception possibly, depending on - * configuration - */ - virtual int write(Value const& root, OStream* sout) = 0; - - /** \brief A simple abstract factory. - */ - class JSON_API Factory { - public: - virtual ~Factory(); - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual StreamWriter* newStreamWriter() const = 0; - }; // Factory -}; // StreamWriter - -/** \brief Write into stringstream, then return string, for convenience. - * A StreamWriter will be created from the factory, used, and then deleted. - */ -String JSON_API writeString(StreamWriter::Factory const& factory, - Value const& root); - -/** \brief Build a StreamWriter implementation. - -* Usage: -* \code -* using namespace Json; -* Value value = ...; -* StreamWriterBuilder builder; -* builder["commentStyle"] = "None"; -* builder["indentation"] = " "; // or whatever you like -* std::unique_ptr writer( -* builder.newStreamWriter()); -* writer->write(value, &std::cout); -* std::cout << std::endl; // add lf and flush -* \endcode -*/ -class JSON_API StreamWriterBuilder : public StreamWriter::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - * Available settings (case-sensitive): - * - "commentStyle": "None" or "All" - * - "indentation": "". - * - Setting this to an empty string also omits newline characters. - * - "enableYAMLCompatibility": false or true - * - slightly change the whitespace around colons - * - "dropNullPlaceholders": false or true - * - Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's JavaScript, it makes for smaller output and the - * browser can handle the output just fine. - * - "useSpecialFloats": false or true - * - If true, outputs non-finite floating point values in the following way: - * NaN values as "NaN", positive infinity as "Infinity", and negative - * infinity as "-Infinity". - * - "precision": int - * - Number of precision digits for formatting of real values. - * - "precisionType": "significant"(default) or "decimal" - * - Type of precision for formatting of real values. - * - "emitUTF8": false or true - * - If true, outputs raw UTF8 strings instead of escaping them. - - * You can examine 'settings_` yourself - * to see the defaults. You can also write and read them just like any - * JSON Value. - * \sa setDefaults() - */ - Json::Value settings_; - - StreamWriterBuilder(); - ~StreamWriterBuilder() override; - - /** - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - StreamWriter* newStreamWriter() const override; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - /** A simple way to update a specific setting. - */ - Value& operator[](const String& key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults - */ - static void setDefaults(Json::Value* settings); -}; - -/** \brief Abstract class for writers. - * \deprecated Use StreamWriter. (And really, this is an implementation detail.) - */ -class JSON_API Writer { -public: - virtual ~Writer(); - - virtual String write(const Value& root) = 0; -}; - -/** \brief Outputs a Value in JSON format - *without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' - *consumption, - * but may be useful to support feature such as RPC where bandwidth is limited. - * \sa Reader, Value - * \deprecated Use StreamWriterBuilder. - */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Deriving from deprecated class -#endif -class JSON_API FastWriter - : public Writer { -public: - FastWriter(); - ~FastWriter() override = default; - - void enableYAMLCompatibility(); - - /** \brief Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's JavaScript, it makes for smaller output and the - * browser can handle the output just fine. - */ - void dropNullPlaceholders(); - - void omitEndingLineFeed(); - -public: // overridden from Writer - String write(const Value& root) override; - -private: - void writeValue(const Value& value); - - String document_; - bool yamlCompatibilityEnabled_{false}; - bool dropNullPlaceholders_{false}; - bool omitEndingLineFeed_{false}; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -/** \brief Writes a Value in JSON format in a - *human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - *line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - *types, - * and all the values fit on one lines, then print the array on a single - *line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputted according to their - *#CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Deriving from deprecated class -#endif -class JSON_API - StyledWriter : public Writer { -public: - StyledWriter(); - ~StyledWriter() override = default; - -public: // overridden from Writer - /** \brief Serialize a Value in JSON format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - String write(const Value& root) override; - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultilineArray(const Value& value); - void pushValue(const String& value); - void writeIndent(); - void writeWithIndent(const String& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - static bool hasCommentForValue(const Value& value); - static String normalizeEOL(const String& text); - - using ChildValues = std::vector; - - ChildValues childValues_; - String document_; - String indentString_; - unsigned int rightMargin_{74}; - unsigned int indentSize_{3}; - bool addChildValues_{false}; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -/** \brief Writes a Value in JSON format in a - human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - types, - * and all the values fit on one lines, then print the array on a single - line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputted according to their - #CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Deriving from deprecated class -#endif -class JSON_API - StyledStreamWriter { -public: - /** - * \param indentation Each level will be indented by this amount extra. - */ - StyledStreamWriter(String indentation = "\t"); - ~StyledStreamWriter() = default; - -public: - /** \brief Serialize a Value in JSON format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not - * return a value. - */ - void write(OStream& out, const Value& root); - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultilineArray(const Value& value); - void pushValue(const String& value); - void writeIndent(); - void writeWithIndent(const String& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - static bool hasCommentForValue(const Value& value); - static String normalizeEOL(const String& text); - - using ChildValues = std::vector; - - ChildValues childValues_; - OStream* document_; - String indentString_; - unsigned int rightMargin_{74}; - String indentation_; - bool addChildValues_ : 1; - bool indented_ : 1; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#if defined(JSON_HAS_INT64) -String JSON_API valueToString(Int value); -String JSON_API valueToString(UInt value); -#endif // if defined(JSON_HAS_INT64) -String JSON_API valueToString(LargestInt value); -String JSON_API valueToString(LargestUInt value); -String JSON_API valueToString( - double value, unsigned int precision = Value::defaultRealPrecision, - PrecisionType precisionType = PrecisionType::significantDigits); -String JSON_API valueToString(bool value); -String JSON_API valueToQuotedString(const char* value); - -/// \brief Output using the StyledStreamWriter. -/// \see Json::operator>>() -JSON_API OStream& operator<<(OStream&, const Value& root); - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_WRITER_H_INCLUDED diff --git a/Common/log.cpp b/Common/log.cpp deleted file mode 100644 index 352918aeae2..00000000000 --- a/Common/log.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#define ENUM_DECLARATION_CPP -#include "log.h" -#include -#include -#include -#ifdef WIN32 -#include -#endif - -#include -#include "utils.h" -#include -#include - -std::ofstream Log::_logFile;// = bofstream(); - -std::ostream* Log::_nullStream = &std::cout; - -std::string Log::logFileNameBase = ""; - -logType Log::_where = logType::cout; -std::string Log::_logFilePath = ""; -logError Log::_logError = logError::noProblem; -int Log::_stdoutfd = -1; -int Log::_engineNo = -1; - - -logType Log::_default = -#ifdef JASP_DEBUG - logType::cout; -#else - logType::null; -#endif - -void Log::setDefaultDestination(logType newDestination) -{ - if(newDestination == logType::file) //It doesnt make any sense to have the default non-file logType be file... - newDestination = logType::cout; - - if(_default == newDestination) - return; - - bool setNewDefaultToWhere = _where == _default; - - _default = newDestination; - - if(setNewDefaultToWhere) - redirectStdOut(); -} - -void Log::setWhere(logType where) -{ - log() << std::flush; - - if(where == _where) - return; - - _where = where; - - redirectStdOut(); -} - -void Log::setLoggingToFile(bool logToFile) -{ - setWhere(logToFile ? logType::file : _default); -} - -void Log::setLogFileName(const std::string & filePath) -{ - if(_logFilePath == filePath) - return; - - _logFilePath = filePath; - - if(_where == logType::file) - redirectStdOut(); -} - -void Log::init(std::ostream* nullStream) -{ - _where = _default; - _nullStream = nullStream; -} - -void Log::redirectStdOut() -{ - switch(_where) - { - default: - break; - - case logType::file: - { - if(_logFilePath == "") - { - _logError = logError::filePathNotSet; - _where = _default; - redirectStdOut(); - return; - } - - //_currentFile = freopen(_logFilePath.c_str(), "a", stdout); - //if(!_currentFile) - - _logFile.open(_logFilePath.c_str(), std::ios_base::app | std::ios_base::out); - - if(_logFile.fail()) - { - _logError = logError::fileNotOpen; - _where = _default; - redirectStdOut(); - return; - } - break; - }; - } - - _logError = logError::noProblem; -} - -Json::Value Log::createLogCfgMsg() -{ - Json::Value json = Json::objectValue; - - json["where"] = logTypeToString(_where); - - return json; -} - -void Log::parseLogCfgMsg(const Json::Value & json) -{ - setWhere(logTypeFromString(json["where"].asString())); -} - -const char * Log::getTimestamp() -{ - static char buf[13]; - static auto startTime = std::chrono::time_point_cast(std::chrono::system_clock::now()); - - std::chrono::milliseconds duration = std::chrono::time_point_cast(std::chrono::system_clock::now()) - startTime; - - long durationMilli = (std::chrono::duration_cast(duration)).count(), - durationSec = durationMilli / 1000, - durationMin = durationSec / 60, - durationHour = durationMin / 60; - - int milli = durationMilli % 1000, - sec = durationSec % 60, - min = durationMin % 60, - hour = durationHour % 60; - - std::snprintf(buf, 13, "%02u:%02u:%02u.%03u", hour, min, sec, milli); - - return buf; -} - -std::ostream & Log::log(bool addTimestamp) -{ - switch(_where) - { - case logType::null: - { - return *_nullStream; - } - case logType::file: - { - if (addTimestamp) _logFile << Log::getTimestamp() << ": "; - return _logFile; - } - case logType::cout: - default: - { - if (addTimestamp) std::cout << ( _engineNo < 0 ? std::string("Desktop:\t") : "Engine#" + std::to_string(_engineNo) + ":\t"); - return std::cout; - } - } -} - -std::ostream & operator<<(std::ostream & os, const std::wstring & wStr) -{ - static std::wstring_convert> strCvt; - - return os << strCvt.to_bytes(wStr); -}; diff --git a/Common/log.h b/Common/log.h deleted file mode 100644 index 278cb7ae8ad..00000000000 --- a/Common/log.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef LOG_H -#define LOG_H - -#include -#include "enumutilities.h" -#include -#include - -DECLARE_ENUM(logType, cout, file, null); -DECLARE_ENUM(logError, noProblem, fileNotOpen, filePathNotSet); - -/// -/// As might be obvious from the name this is the main class for logging. -/// It can be set in three different states, in development default is to log everything to cout, which shows all output in the application output of qt creator -/// For the released version the default is to a "/dev/null" equivalent, aka everything is dropped to waste minimal time on formatting etc. -/// In both cases a setting can be turned on to write it all to files, then a file for Desktop is created and one for each running engine. -/// They will all have the exact same timestamp in the filename to easily group them. -/// For almost all messages a timestamp and identifier is added. But because the output from R (and some other places) comes in in pieces we omit that there. -/// -class Log -{ -public: - static std::ostream & log(bool addTimestamp = true); - - static std::string logFileNameBase; - - static void init(std::ostream* nullStream); - static void setLogFileName(const std::string & filePath); - - static void setDefaultDestination(logType newDestination); - static void setLoggingToFile(bool logToFile); - static void setWhere(logType where); - static void setEngineNo(int num) { _engineNo = num; } - - static Json::Value createLogCfgMsg(); - static void parseLogCfgMsg(const Json::Value & json); - - static std::string whereStr() { return logTypeToString(_where); } - - static bool toCout() { return _where == logType::cout; } - -private: - Log() { } - static void redirectStdOut(); - static const char * getTimestamp(); - - static logType _default; - static logType _where; - static std::string _logFilePath; - static logError _logError; - static int _stdoutfd, - _engineNo; - static std::ostream* _nullStream; - static std::ofstream _logFile; - -}; - -std::ostream & operator<<(std::ostream & os, const std::wstring & wStr); - -#endif // LOG_H diff --git a/Common/processinfo.cpp b/Common/processinfo.cpp deleted file mode 100644 index 1be5e4880b3..00000000000 --- a/Common/processinfo.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#include "processinfo.h" - -#ifdef _WIN32 -#include -#include -#else -#include "unistd.h" -#endif - -unsigned long ProcessInfo::currentPID() -{ - -#ifdef _WIN32 - return GetCurrentProcessId(); -#else - return getpid(); -#endif -} - -unsigned long ProcessInfo::parentPID() -{ - -#ifdef _WIN32 - - HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - PROCESSENTRY32 pe = { 0 }; - pe.dwSize = sizeof(PROCESSENTRY32); - - unsigned long pid = currentPID(); - unsigned long ppid = 0; - - if( Process32First(h, &pe)) { - do { - if (pe.th32ProcessID == pid) { - ppid = pe.th32ParentProcessID; - break; - } - } while( Process32Next(h, &pe)); - } - - CloseHandle(h); - - return ppid; - -#else - - return getppid(); - -#endif -} - -bool ProcessInfo::isParentRunning() -{ -#ifdef _WIN32 - - static unsigned long _parentPID = parentPID(); - static void* _parentHandle = NULL; - - if (_parentHandle == NULL && _parentPID != 0) - _parentHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, _parentPID); - - if (_parentHandle != NULL) - { - BOOL success; - DWORD exitCode; - - success = GetExitCodeProcess(_parentHandle, &exitCode); - - return ( ! success) || exitCode == STILL_ACTIVE; - } -#else - return getppid() != 1; -#endif -} diff --git a/Common/processinfo.h b/Common/processinfo.h deleted file mode 100644 index c353a6db034..00000000000 --- a/Common/processinfo.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#ifndef PROCESSINFO_H -#define PROCESSINFO_H - - -/// -/// Get your PID here! -/// -class ProcessInfo -{ -public: - - static unsigned long currentPID(); - static unsigned long parentPID(); - - static bool isParentRunning(); - -}; - -#endif // PROCESS_H diff --git a/Common/r_functionwhitelist.cpp b/Common/r_functionwhitelist.cpp deleted file mode 100644 index fc9c0bcdb4e..00000000000 --- a/Common/r_functionwhitelist.cpp +++ /dev/null @@ -1,374 +0,0 @@ -#include "r_functionwhitelist.h" -#include "stringutils.h" - - //The following functions (and keywords that can be followed by a '(') will be allowed in user-entered R-code, such as filters or computed columns. This is for security because otherwise JASP-files could become a vector of attack and that doesn't refer to an R-datatype. -const std::set R_FunctionWhiteList::functionWhiteList { - "AIC", - "Arg", - "Conj", - "Im", - "Mod", - "NCOL", - "Re", - "abs", - "acos", - "aggregate", - "anova", - "aov", - "apply", - "approx", - "array", - "as.Date", - "as.POSIXct", - "as.array", - "as.character", - "as.complex", - "as.data.frame", - "as.logical", - "as.numeric", - "as.factor", - "as.list", - "as.integer", - "asin", - "atan", - "atanh", - "atan2", - "attr", - "attributes", - "BoxCox", - "binom.test", - "by", - "c", - "cat", - "cbind", - "choose", - "class", - "coef", - "colMeans", - "colSums", - "colsum", - "convolve", - "cor", - "cos", - "cummax", - "cummin", - "cumprod", - "cumsum", - "cut", - "data.frame", - "density", - "deviance", - "df.residual", - "diag", - "diff", - "dim", - "dimnames", - "exp", - "expand.grid", - "factor", - "fft", - "filter", - "fitted", - "fishZ", - "for", - "format", - "function", - "gl", - "glm", - "gregexpr", - "grep", - "grepl", - "gsub", - "if", - "ifelse", - "ifElse", - "intersect", - "invBoxCox", - "invFishZ", - "invLogit", - "is.array", - "is.character", - "is.complex", - "is.data.frame", - "is.element", - "is.logical", - "is.na", - "is.null", - "is.numeric", - "lag", - "lapply", - "length", - "library", - "list", - "local", - "logit", - "lm", - "loess", - "log", - "log2", - "log10", - "logb", - "logLik", - "ls", - "ls.srt", - "match", - "matrix", - "max", - "mean", - "median", - "merge", - "methods", - "min", - "mvfft", - "na.fail", - "na.omit", - "nchar", - "ncol", - "nlm", - "nls", - "nrow", - "optim", - "pairwise.t.test", - "paste", - "paste0", - "pmatch", - "pmax", - "pmin", - "poly", - "powerTransform", - "power.t.test", - "predict", - "print", - "prod", - "prop.table", - "prop.test", - "quantile", - "range", - "rank", - "rbeta", - "rbind", - "rbinom", - "rcauchy", - "rchisq", - "regexec", - "regexpr", - "rep", - "replicate", - "reshape", - "residuals", - "return", - "rev", - "rexp", - "rf", - "rgamma", - "rgeom", - "rhyper", - "rlnorm", - "rlogis", - "rnbinom", - "rnorm", - "round", - "rowMeans", - "rowSums", - "rowsum", - "rpois", - "rt", - "runif", - "rweibull", - "rwilcox", - "sample", - "scale", - "sd", - "seq", - "setdiff", - "setequal", - "sin", - "sign", - "solve", - "sort", - "spline", - "sqrt", - "stack", - "str", - "strsplit", - "sub", - "subset", - "substr", - "sum", - "summary", - "t", - "t.test", - "table", - "tan", - "tanh", - "tapply", - "tolower", - "toString", - "toupper", - "trimws", - "unclass", - "union", - "unique", - "unstack", - "var", - "weighted.mean", - "which", - "which.max", - "which.min", - "xtabs", - "YeoJohnson", - ".setColumnDataAsScale", ".setColumnDataAsOrdinal", ".setColumnDataAsNominal", ".setColumnDataAsNominalText", "function", "stop", - "normalDist", "tDist", "chiSqDist", "fDist", "binomDist", "negBinomDist", "geomDist", "poisDist", "integerDist", "betaDist", "unifDist", "gammaDist", "expDist", "logNormDist", "weibullDist", - "replaceNA", - //Some distribution related stuff: - "dbeta", "pbeta", "qbeta", "rbeta", - "dbinom", "pbinom", "qbinom", "rbinom", - "dcauchy", "pcauchy", "qcauchy", "rcauchy", - "dchisq", "pchisq", "qchisq", "rchisq", - "dexp", "pexp", "qexp", "rexp", - "df", "pf", "qf", "rf", - "dgamma", "pgamma", "qgamma", "rgamma", - "dgeom", "pgeom", "qgeom", "rgeom", - "dhyper", "phyper", "qhyper", "rhyper", - "dlnorm", "plnorm", "qlnorm", "rlnorm", - "dmultinom", "pmultinom", "qmultinom", "rmultinom", - "dnbinom", "pnbinom", "qnbinom", "rnbinom", - "dnorm", "pnorm", "qnorm", "rnorm", - "dpois", "ppois", "qpois", "rpois", - "dt", "pt", "qt", "rt", - "dunif", "punif", "qunif", "runif", - "dweibull", "pweibull", "qweibull", "rweibull", - "dsignrank", "psignrank", "qsignrank", "rsignrank", - - "zScores", - "hasSubstring", - - "pbirthday", - "ptukey", - "dwilcox", - "switch", - "rowMean", "rowMeanNaRm", - "rowSum", "rowSumNaRm", - "rowSD", "rowSDNaRm", - "rowVariance", "rowVarianceNaRm", - "rowCovariance", - "rowCorrelation", - "rowMedian", "rowMedianNaRm", - "rowMin", "rowMinNaRm", - "rowMax", "rowMaxNaRm" - -#ifdef JASP_DEBUG - ,"Sys.sleep", ".crashPlease", "stringi::stri_enc_mark", "stringi::stri_enc_toutf8", "Encoding" -#endif - }; - -std::string R_FunctionWhiteList::returnOrderedWhiteList() -{ - std::stringstream out; - - for(auto & s : functionWhiteList) - out << "\"" << s << "\"," << std::endl; - out << std::flush; - - return out.str(); -} - -const std::string R_FunctionWhiteList::functionStartDelimit("(?:[;\\s\\(\"\\[\\+\\-\\=\\*\\%\\/\\{\\|&!]|^)"); //These should be all possible non-funtion-name-characters that could be right in front of any function-name in R. -const std::string R_FunctionWhiteList::functionNameStart("(?:\\.?[[:alpha:]])"); -const std::string R_FunctionWhiteList::functionNameBody("(?:\\w|\\.|::)+"); -const std::regex R_FunctionWhiteList::functionNameMatcher(functionStartDelimit + "(" + functionNameStart + functionNameBody + ")(?=[\\t \\r]*\\()"); - -std::set R_FunctionWhiteList::findIllegalFunctions(std::string const & script) -{ - std::set blackListedFunctionsFound; - - auto foundFunctionsBegin = std::sregex_iterator(script.begin(), script.end(), functionNameMatcher); - auto foundFunctionsEnd = std::sregex_iterator(); - - for(auto foundFunctionIter = foundFunctionsBegin; foundFunctionIter != foundFunctionsEnd; foundFunctionIter++ ) - { - std::string foundFunction((*foundFunctionIter)[1].str()); - bool whiteListed = functionWhiteList.count(foundFunction) > 0; - - if(!whiteListed && blackListedFunctionsFound.count(foundFunction) == 0) - blackListedFunctionsFound.insert(foundFunction); - } - - - return blackListedFunctionsFound; -} - -const std::string R_FunctionWhiteList::operatorsR("`(?:\\+|-|\\*|/|%(?:/|\\*|in)?%|\\^|<=?|>=?|==?|!=?|>?|\\|\\|?|&&?|:|\\$)`"); - -const std::regex R_FunctionWhiteList::assignmentWhiteListedRightMatcher( "(" + functionNameStart + functionNameBody + ")\\s*(?:>?)\\s*(" + functionNameStart + functionNameBody + ")"); -const std::regex R_FunctionWhiteList::assignmentOperatorRightMatcher( "(" + operatorsR + ")\\s*(?:>?)\\s*(" + operatorsR + ")"); - -std::set R_FunctionWhiteList::findIllegalFunctionsAliases(std::string const & script) -{ - //Log::log() << "findIllegalFunctionsAliases with " << script << std::endl; - - std::set illegalAliasesFound; - - auto aliasSearcher = [&illegalAliasesFound, &script](std::regex aliasAssignmentMatcher, bool (*lambdaMatchChecker)(std::string) ) - { - auto foundAliasesBegin = std::sregex_iterator(script.begin(), script.end(), aliasAssignmentMatcher); - auto foundAliasesEnd = std::sregex_iterator(); - - for(auto foundAliasesIter = foundAliasesBegin; foundAliasesIter != foundAliasesEnd; foundAliasesIter++ ) - { - std::string foundAlias((*foundAliasesIter)[1].str()); - bool allowed = (*lambdaMatchChecker)(foundAlias); - - //Log::log() << "I found alias assignment: " << foundAlias << " which is " << (allowed ? "allowed" : "not allowed") << ".." << std::endl; - - if(!allowed) - illegalAliasesFound.insert(foundAlias); - } - }; - - aliasSearcher(assignmentOperatorLeftMatcher, [](std::string alias) { return false; }); //operators are never allowed - aliasSearcher(assignmentOperatorRightMatcher, [](std::string alias) { return false; }); - aliasSearcher(assignmentWhiteListedLeftMatcher, [](std::string alias) { return functionWhiteList.count(alias) == 0; }); //only allowed when the token being assigned to is not in whitelist - aliasSearcher(assignmentWhiteListedRightMatcher, [](std::string alias) { return functionWhiteList.count(alias) == 0; }); - - //Log::log() << std::flush; - - return illegalAliasesFound; -} - -void R_FunctionWhiteList::scriptIsSafe(const std::string &script) -{ - std::string commentFree = stringUtils::stripRComments(script); - - static std::string errorMsg; - - std::set blackListedFunctions = findIllegalFunctions(commentFree); - - if(blackListedFunctions.size() > 0) - { - bool moreThanOne = blackListedFunctions.size() > 1; - std::stringstream ssm; - ssm << "Non-whitelisted function" << (moreThanOne ? "s" : "") << " used:" << (moreThanOne ? "\n" : " "); - for(auto & black : blackListedFunctions) - ssm << black << "\n"; - errorMsg = ssm.str(); - - throw filterException(errorMsg); - } - - std::set illegalAliasesFound = findIllegalFunctionsAliases(commentFree); - - if(illegalAliasesFound.size() > 0) - { - bool moreThanOne = illegalAliasesFound.size() > 1; - std::stringstream ssm; - ssm << "Illegal assignment to " << (moreThanOne ? "operators or whitelisted functions" : "an operator or whitelisted function") << " used:" << (moreThanOne ? "\n" : " "); - for(auto & alias : illegalAliasesFound) - ssm << alias << "\n"; - errorMsg = ssm.str(); - - throw filterException(errorMsg); - } -} diff --git a/Common/r_functionwhitelist.h b/Common/r_functionwhitelist.h deleted file mode 100644 index 05acdfda471..00000000000 --- a/Common/r_functionwhitelist.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef R_FUNCTIONWHITELIST_H -#define R_FUNCTIONWHITELIST_H - -#include -#include -#include - -///New exception to give feedback about possibly failing filters and such -class filterException : public std::logic_error -{ -public: - filterException(const std::string & what_arg) : std::logic_error(what_arg) {} - filterException(const char * what_arg) : std::logic_error(what_arg) {} -}; - -/// -/// This class provides for a modicum of security when opening JASP files created by strangers. -/// Because one can write filter or computed column code in R and R allows you to do almost anything. -/// This class attempts to restrict those scripts to use only whitelisted functions (in R_FunctionWhiteList::functionWhiteList) -/// Of course, R is very flexible and there might be ways around it that we haven't thought of but this is much better than nothing. -/// -class R_FunctionWhiteList -{ -private: - ///The following functions (and keywords that can be followed by a '(') will be allowed in user-entered R-code, such as filters or computed columns. This is for security because otherwise JASP-files could become a attack-vector (which doesn't refer to an R-datatype). - static const std::set functionWhiteList; - static const std::string functionPrecedingCharacter, functionStartDelimit, functionNameStart, functionNameBody, operatorsR; - static const std::regex functionNameMatcher, functionNamePrecederMatcher, assignmentWhiteListedRightMatcher, assignmentWhiteListedLeftMatcher, assignmentOperatorRightMatcher, assignmentOperatorLeftMatcher; - -public: - ///throws a filterexception if the script is not legal for some reason - static void scriptIsSafe(std::string const & script); - - ///Checks script for unsafe function-calls (all functions that aren't in R_FunctionWhiteList) and returns the set of unsafe calls. If it is empty then the script is deemed safe. - static std::set findIllegalFunctions(std::string const & script); - - ///Checks if someone is trying to overwrite whitelisted functions by other functions (like: "mean <- system") - static std::set findIllegalFunctionsAliases(std::string const & script); - - ///returns the whitelisted functions in a string, each function on its own line. - static std::string returnOrderedWhiteList(); -}; - -#endif // R_FUNCTIONWHITELIST_H diff --git a/Common/stringutils.h b/Common/stringutils.h deleted file mode 100644 index 67309399311..00000000000 --- a/Common/stringutils.h +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef STRINGUTILS_H -#define STRINGUTILS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include "utils.h" - -/// This class groups a variety of string related utility functions for use throughout JASP -/// All functions are inline and here to avoid problems through the mixing of MSVC and GCC on Windows. -/// (Because this code can be used from R-Interface which can only be compiled with RTools and Common with MSVC...) -class stringUtils -{ -public: - inline static std::string stripRComments(const std::string & rCode) - { - std::stringstream out; - - //Fixes https://github.com/jasp-stats/INTERNAL-jasp/issues/72 - //Gotta do some rudimentary parsing here... A comment starts with # and ends with newline, but if a # is inside a string then it doesn't start a comment... - //String are started with ' or " - - enum class status { R, Comment, SingleStr, DoubleStr }; - - status curStatus = status::R; - - for(size_t r=0; r splitString(const std::string & str, const char sep = ',') - { - stringvec vecString; - std::string item; - std::stringstream stringStream(str); - - while (std::getline(stringStream, item, sep)) - vecString.push_back(item); - - return vecString; - } - - inline static std::string toLower(std::string input) - { - std::transform(input.begin(), input.end(), input.begin(), ::tolower); - return input; - } - - inline static std::string replaceBy(std::string input, const std::string & replaceThis, const std::string & withThis) - { - //std::cout << "replaceBy('" << input << "', '" << replaceThis << "', '" << withThis << "');" << std::endl; - - size_t oldLen = replaceThis.size(), - newLen = withThis.size(); - - for ( std::string::size_type curPos = input.find(replaceThis) - ; curPos + oldLen <= input.size() && curPos != std::string::npos - ; curPos = input.find(replaceThis, curPos+newLen) - ) - input.replace(curPos, oldLen, withThis); - - return input; - } - - inline static std::string escapeHtmlStuff(std::string input) - { - input = replaceBy(input, "&", "&" ); - input = replaceBy(input, "<", "<" ); - input = replaceBy(input, ">", ">" ); - input = replaceBy(input, "<sub>", "" ); - input = replaceBy(input, "</sub>", ""); - input = replaceBy(input, "<sup>", "" ); - input = replaceBy(input, "</sup>", ""); - input = replaceBy(input, "<b>", "" ); - input = replaceBy(input, "</b>", "" ); - input = replaceBy(input, "<i>", "" ); - input = replaceBy(input, "</i>", "" ); - - return input; - } - - inline static std::string stripNonAlphaNum(std::string input) - { - //std::remove_if makes sure all non-ascii chars are removed from your vector, but it does not change the length of the vector. That's why we erase the remaining part of the vector afterwards. - input.erase(std::remove_if(input.begin(), input.end(), [](unsigned char x) - { - #ifdef _WIN32 - return !std::isalnum(x, std::locale()); - #else - return !std::isalnum(x); - #endif - - }), input.end()); - - return input; - } - - // Blatantly taken from https://stackoverflow.com/a/217605 - - // trim from start (in place) - static inline std::string ltrim(std::string &s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { - return !std::isspace(ch); - })); - return s; - } - - // trim from end (in place) - static inline std::string rtrim(std::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { - return !std::isspace(ch); - }).base(), s.end()); - return s; - } - - // trim from both ends (in place) - static inline std::string trim(std::string &s) { - ltrim(s); - rtrim(s); - return s; - } - - // trim from start (copying) - static inline std::string ltrim_copy(std::string s) { - ltrim(s); - return s; - } - - // trim from end (copying) - static inline std::string rtrim_copy(std::string s) { - rtrim(s); - return s; - } - - static inline bool startsWith(const std::string & line, const std::string & startsWithThis) - { - return line.size() >= startsWithThis.size() && line.substr(0, startsWithThis.size()) == startsWithThis; - } - - static inline bool escapeValue(std::string &value) - { - bool useQuotes = false; - std::size_t found = value.find(","); - if (found != std::string::npos) - useQuotes = true; - - if (value.find_first_of(" \n\r\t\v\f") == 0) - useQuotes = true; - - - if (value.find_last_of(" \n\r\t\v\f") == value.length() - 1) - useQuotes = true; - - size_t p = value.find("\""); - while (p != std::string::npos) - { - value.insert(p, "\""); - p = value.find("\"", p + 2); - useQuotes = true; - } - - return useQuotes; - } - -private: - stringUtils(); -}; - -#endif // STRINGUTILS_H diff --git a/Common/tempfiles.cpp b/Common/tempfiles.cpp deleted file mode 100644 index f5887ca171b..00000000000 --- a/Common/tempfiles.cpp +++ /dev/null @@ -1,382 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#include "tempfiles.h" - -#include -#include -#include - -#include "columnencoder.h" -#include "utils.h" - -#include "dirs.h" -#include "log.h" -using namespace std; - -const long outOfDateDelta = 24 * 3600; -long TempFiles::_sessionId = 0; -std::string TempFiles::_sessionDirName = ""; -std::string TempFiles::_statusFileName = ""; -std::string TempFiles::_clipboard = ""; -int TempFiles::_nextFileId = 0; -int TempFiles::_nextTmpFolderId = 0; - -void TempFiles::init(long sessionId) -{ - _sessionId = sessionId; - _nextFileId = 0; - _sessionDirName = Dirs::tempDir() + "/" + std::to_string(sessionId); - _statusFileName = _sessionDirName + "/status"; - _clipboard = Dirs::tempDir() + "/clipboard"; - - createSessionDir(); -} - -void TempFiles::createSessionDir() -{ - std::cout << "TempFiles::createSessionDir(): "; - - std::error_code error; - - std::filesystem::path sessionPath = Utils::osPath(_sessionDirName); - - std::cout<< "'" << sessionPath.string() << "' about to be (removed and re)created." << std::endl; - - std::filesystem::remove_all(sessionPath, error); - std::filesystem::create_directories(sessionPath, error); - - std::fstream f; - f.open(_statusFileName.c_str(), ios_base::out); - f.close(); - - //std::filesystem::path clipboardPath = Utils::osPath(clipboard); - //if ( ! std::filesystem::exists(clipboardPath, error)) - // std::filesystem::create_directories(clipboardPath, error); -} - -void TempFiles::clearSessionDir() -{ - std::filesystem::path sessionPath = Utils::osPath(_sessionDirName); - std::error_code error; - - if(!std::filesystem::exists(sessionPath, error) || error) - return; - - std::vector deleteUs; - - for(const std::filesystem::directory_entry & it : std::filesystem::directory_iterator{sessionPath}) - { - bool leaveMeBe = false; - - for (const std::filesystem::path & pp : it.path()) - { - std::string pathComp = pp.generic_string(); - if(pathComp.find("tmp") != std::string::npos || pathComp == "status" || pathComp == "internal.sqlite") - leaveMeBe = true; - } - - if(!leaveMeBe) - deleteUs.push_back(it.path()); - } - - for(auto & dir : deleteUs) - std::filesystem::remove_all(dir); -} - -void TempFiles::attach(long sessionId) -{ - _sessionId = sessionId; - _nextFileId = 0; - _sessionDirName = Dirs::tempDir() + "/" + std::to_string(sessionId); - _statusFileName = _sessionDirName + "/status"; -} - - -void TempFiles::deleteAll(int id) -{ - std::error_code error; - std::filesystem::path dir = id >= 0 ? std::filesystem::path(_sessionDirName + "/resources/" + std::to_string(id)) : Utils::osPath(_sessionDirName); - std::filesystem::remove_all(dir, error); -} - - -void TempFiles::deleteOrphans() -{ - Log::log() << "TempFiles::deleteOrphans started" << std::endl; - - std::error_code error; - - try - { - std::filesystem::path tempPath = Utils::osPath(Dirs::tempDir()); - std::filesystem::path sessionPath = Utils::osPath(_sessionDirName); - stringvec aliveIDs; - - std::filesystem::directory_iterator itr(tempPath, error); - - if (error) - { - Log::log() << error.message() << std::endl; - return; - } - - //find the Dirs that must be deleted and store their PIDs (name) - for (; itr != std::filesystem::directory_iterator(); itr++) - { - std::filesystem::path p = itr->path(); - - //Log::log() << "looking at file " << p.string() << std::endl; - - if (p.compare(sessionPath) == 0) - continue; - - string fileName = Utils::osPath(p.filename()); - bool is_directory = std::filesystem::is_directory(p, error); - - if (error) - continue; - - if (is_directory) - { - if (std::atoi(fileName.c_str()) == 0) - continue; - - std::filesystem::path statusFile = Utils::osPath(Utils::osPath(p) + "/status"); - - if (std::filesystem::exists(statusFile, error)) - { - long modTime = Utils::getFileModificationTime(Utils::osPath(statusFile)); - long now = Utils::currentSeconds(); - - if (now - modTime > outOfDateDelta) - { - std::filesystem::remove_all(p, error); - if (error) - Log::log() << "Error when deleting directory: " << error.message() << std::endl; - } - else - aliveIDs.push_back(p.filename().string()); - } - else // no status file - { - std::filesystem::remove_all(p, error); - if (error) - Log::log() << "Error when deleting directory, had no status file and " << error.message() << std::endl; - } - } - } - - //Delete files in the root not associated with the IDs that have been active for x time - deleteStrayRootFiles(aliveIDs, outOfDateDelta); - - } - catch (runtime_error e) - { - Log::log() << "Could not delete orphans, error: " << e.what() << std::endl; - return; - } -} - - - - -void TempFiles::heartbeat() -{ - Utils::touch(_statusFileName); -} - -void TempFiles::purgeClipboard() -{ - std::error_code error; - std::filesystem::remove_all(Utils::osPath(_clipboard), error); -} - -string TempFiles::createSpecific_clipboard(const string &filename) -{ - std::error_code error; - - string fullPath = _clipboard + "/" + filename; - std::filesystem::path path = Utils::osPath(fullPath), - dirPath = path.parent_path(); - - if (!std::filesystem::exists(dirPath, error) || error) - std::filesystem::create_directories(dirPath, error); - - return fullPath; -} - -string TempFiles::createSpecific(const string &dir, const string &filename) -{ - std::error_code error; - string fullPath = _sessionDirName + "/" + dir; - std::filesystem::path path = Utils::osPath(fullPath); - - if (!std::filesystem::exists(path, error) || error) - std::filesystem::create_directories(path, error); - - return fullPath + "/" + filename; -} - -void TempFiles::createSpecific(const string &name, int id, string &root, string &relativePath) -{ - root = _sessionDirName; - relativePath = "resources" + (id >= 0 ? "/" + std::to_string(id) : ""); - std::filesystem::path path = Utils::osPath(root + "/" + relativePath); - - std::error_code error; - if (!std::filesystem::exists(path, error) || error) - std::filesystem::create_directories(path, error); - - relativePath += "/" + name; -} - -void TempFiles::create(const string &extension, int id, string &root, string &relativePath) -{ - std::error_code error; - - root = _sessionDirName; - string resources = root + "/resources" + (id >= 0 ? "/" + std::to_string(id) : ""); - - std::filesystem::path path = Utils::osPath(resources); - - if (!std::filesystem::exists(resources, error) || error) - std::filesystem::create_directories(resources, error); - - string suffix = extension == "" ? "" : "." + extension; - - do - { - relativePath = "resources/" + (id >= 0 ? std::to_string(id) + "/" : "") + "_" + std::to_string(_nextFileId++) + "_t" + std::to_string(Utils::currentMillis()) + suffix; - path = Utils::osPath(root + "/" + relativePath); - } - while (std::filesystem::exists(path)); -} - -std::string TempFiles::createTmpFolder() -{ - std::error_code error; - - while(true) - { - std::string tmpFolder = _sessionDirName + "/tmp" + std::to_string(_nextTmpFolderId++) + "/"; - std::filesystem::path path = Utils::osPath(tmpFolder); - - if (!std::filesystem::exists(path, error) || error) - { - std::filesystem::create_directories(path, error); - return tmpFolder; - } - } -} - -vector TempFiles::retrieveList(int id) -{ - vector files; - - std::error_code error; - - string dir = _sessionDirName; - - if (id >= 0) - dir += "/resources/" + std::to_string(id); - - std::filesystem::path path = Utils::osPath(dir); - - std::filesystem::directory_iterator itr(path, error); - - if (error) - return files; - - for (; itr != std::filesystem::directory_iterator(); itr++) - if (std::filesystem::is_regular_file(itr->status())) - { - std::filesystem::path pad = itr->path(); - string absPath = pad.generic_string(); - string relPath = absPath.substr(_sessionDirName.size()+1); - - files.push_back(relPath); - } - - return files; -} - -void TempFiles::deleteList(const vector &files) -{ - std::error_code error; - - for(const string &file : files) - { - string absPath = _sessionDirName + "/" + file; - std::filesystem::path p = Utils::osPath(absPath); - - std::filesystem::remove(p, error); - } -} - -void TempFiles::deleteStrayRootFiles(const stringvec& validIDs, long outOfDateDelta) -{ - std::filesystem::path tempPath = Utils::osPath(Dirs::tempDir()); - std::error_code error; - std::filesystem::directory_iterator itr(tempPath, error); - - if (error) - { - Log::log() << error.message() << std::endl; - return; - } - - for (; itr != std::filesystem::directory_iterator(); itr++) - { - std::filesystem::path p = itr->path(); - - Log::log() << "looking at file " << p.string() << std::endl; - - string fileName = Utils::osPath(p.filename()); - bool is_directory = std::filesystem::is_directory(p, error); - - if (error) - continue; - - if (!is_directory) - { - long modTime = Utils::getFileModificationTime(Utils::osPath(p)); - long now = Utils::currentSeconds(); - - if (now - modTime <= outOfDateDelta || fileName.substr(0, 5).compare("JASP-") != 0) - continue; - - bool valid = false; - for (auto& id : validIDs) - { - if (fileName.find(id) != std::string::npos) - { - valid = true; - break; - } - } - if (valid) - continue; - - Log::log() << "Try to delete: " << fileName << std::endl; - std::filesystem::remove(p, error); - - if (error) - Log::log() << "Error when deleting file: " << error.message() << std::endl; - } - } -} diff --git a/Common/tempfiles.h b/Common/tempfiles.h deleted file mode 100644 index 116bb68ca2b..00000000000 --- a/Common/tempfiles.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#ifndef TEMPFILES_H -#define TEMPFILES_H - -#include -#include - -/// Each running UI process creates a series of temporary directories -/// -/// Within these temporary directories, subdirectories exist, numbered with the analysisId, for each analysis. -/// -/// In these the state file exists, as well as all the plots. -/// -/// In the event that the UI process crashes, and fails to clean up after itself, these 'orphans' are deleted next time the program starts up. -/// This is performed by the deleteOrphans() function below. -/// During normal operation, the UI process 'touch'es a status file in the temp directory, every 30 seconds or so this is handled by the heartbeat() function below. -/// -/// deleteOrphans() checks the modification time of this status file and if it is more than a minute old, the temp directory is considered orphaned and is deleted. -/// -class TempFiles -{ - typedef std::vector stringvec; - -public: - static void init(long _sessionId); - static void attach(long _sessionId); - static void heartbeat(); - - static void createSessionDir(); - static void clearSessionDir(); - - static std::string createSpecific_clipboard(const std::string &filename); - static void purgeClipboard(); - - static void create(const std::string &extension, int id, std::string &root, std::string &relativePath); - static void createSpecific(const std::string &name, int id, std::string &root, std::string &relativePath); - static std::string createSpecific(const std::string &dir, const std::string &filename); - static std::string createTmpFolder(); - - static std::string sessionDirName() { return _sessionDirName; } - static stringvec retrieveList(int id = -1); - - static void deleteList(const stringvec &files); - static void deleteAll(int id = -1); - static void deleteOrphans(); - - static void deleteStrayRootFiles(const stringvec& validIDs, long outOfDateDelta); - -private: - TempFiles() {} - static long _sessionId; - static std::string _sessionDirName, - _statusFileName, - _clipboard; - static int _nextFileId, - _nextTmpFolderId; -}; - - -#endif // TEMPFILES_H diff --git a/Common/timers.cpp b/Common/timers.cpp deleted file mode 100644 index f8370dd4d8d..00000000000 --- a/Common/timers.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "timers.h" - -#ifdef PROFILE_JASP -#include - -static std::map * timers = nullptr; - -boost::timer::cpu_timer * _getTimer(std::string timerName) -{ - - //Log::log() << "getTimer! "<< timerName << std::endl; - - if(timers == nullptr) - timers = new std::map(); - - if(timers->count(timerName) == 0) - { - (*timers)[timerName] = new boost::timer::cpu_timer(); //starts automatically - (*timers)[timerName]->stop(); - } - - return (*timers)[timerName]; -} - -void _printAllTimers() -{ - if(timers == nullptr) - return; - - for(auto keyval : *timers) - std::cout << keyval.first << " ran for " << keyval.second->format() << std::endl; -} - -#endif diff --git a/Common/timers.h b/Common/timers.h deleted file mode 100644 index 54c3bd3e16d..00000000000 --- a/Common/timers.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TIMERS_H -#define TIMERS_H - -#ifdef PROFILE_JASP - -/// -/// This file contains some simple timers that can be added to a variety of locations in JASP to be able to profile easily -/// To do so PROFILE_JASP can be defined in the build-environment and then rebuilt. -/// If it isn't used it just compiles into some comments and thus thrown out entirely by the preprocessor. - -#include -#include -#include - - -boost::timer::cpu_timer * _getTimer(std::string timerName); -void _printAllTimers(); - -#define JASPTIMER_START( TIMERNAME ) _getTimer( #TIMERNAME )->start() -#define JASPTIMER_RESUME( TIMERNAME ) _getTimer( #TIMERNAME )->resume() -#define JASPTIMER_STOP( TIMERNAME ) _getTimer( #TIMERNAME )->stop() -#define JASPTIMER_PRINT( TIMERNAME ) Log::log() << #TIMERNAME << " ran for " << _getTimer( #TIMERNAME )->format() << std::endl -#define JASPTIMER_FINISH( TIMERNAME ) JASPTIMER_STOP(TIMERNAME); JASPTIMER_PRINT(TIMERNAME) -#define JASPTIMER_PRINTALL() _printAllTimers() - -struct _JaspTimerScopeMeasure -{ - _JaspTimerScopeMeasure(const char * name) : _name(name) { _getTimer(_name)->resume(); } - ~_JaspTimerScopeMeasure() { _getTimer(_name)->stop(); } - - const char * _name; -}; -#define JASPTIMER_SCOPE(TIMERNAME) _JaspTimerScopeMeasure singleScopeTimer(#TIMERNAME) -#define JASPTIMER_CLASS(TIMERNAME) _JaspTimerScopeMeasure singleScopeTimer = #TIMERNAME; - -#else -//No timers please! -#define JASPTIMER_START( TIMERNAME ) /* TIMERNAME */ -#define JASPTIMER_RESUME( TIMERNAME ) /* TIMERNAME */ -#define JASPTIMER_STOP( TIMERNAME ) /* TIMERNAME */ -#define JASPTIMER_PRINT( TIMERNAME ) /* TIMERNAME */ -#define JASPTIMER_FINISH( TIMERNAME ) /* TIMERNAME */ -#define JASPTIMER_PRINTALL() /* bla bla bla */ -#define JASPTIMER_SCOPE(TIMERNAME) /* Hmm hmm */ -#define JASPTIMER_CLASS(TIMERNAME) /* Hmm hmm */ -#endif - -#endif // TIMERS_H diff --git a/Common/utilenums.cpp b/Common/utilenums.cpp deleted file mode 100644 index 56ced70cd0e..00000000000 --- a/Common/utilenums.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#define ENUM_DECLARATION_CPP -#include "utilenums.h" diff --git a/Common/utilenums.h b/Common/utilenums.h deleted file mode 100644 index 510717923f7..00000000000 --- a/Common/utilenums.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef UTILENUMS_H -#define UTILENUMS_H -#include "enumutilities.h" - -DECLARE_ENUM(FileTypeBase, jasp = 0, html, csv, txt, tsv, sav, zsav, ods, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, empty, unknown ); - -//const QStringList Database::dbTypes() const should be updated if DbType is changed. -DECLARE_ENUM(DbType, NOTCHOSEN, QDB2, /*QIBASE,*/ QMYSQL, QOCI, QODBC, QPSQL, QSQLITE /*, QSQLITE2, QTDS*/ ); - -#endif // UTILENUMS_H diff --git a/Common/utils.cpp b/Common/utils.cpp deleted file mode 100644 index 7f916dd687f..00000000000 --- a/Common/utils.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - - -#include "utils.h" - -#ifdef _WIN32 -#include -#include -#include -#else -#include -#include -#endif - - -#include "utilenums.h" -#include -#include -#include -#include - -#ifndef JASP_USES_QT_HERE -#include -#endif - -using namespace std; - -Utils::FileType Utils::getTypeFromFileName(const std::string &path) -{ - - size_t lastPoint = path.find_last_of('.'); - FileType filetype = lastPoint == string::npos ? FileType::empty : FileType::unknown; - - if (lastPoint != string::npos && (lastPoint + 1) < path.length()) - { - std::string suffix = path.substr(lastPoint + 1); - for (int i = 0; i < int(FileType::empty); i++) - { - FileType it = static_cast(i); - if (suffix == FileTypeBaseToString(it)) - { - filetype = it; - break; - } - } - } - - - return filetype; -} - -long Utils::currentMillis() -{ - return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); -} - -long Utils::currentSeconds() -{ - return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); -} - -long Utils::getFileModificationTime(const std::string &filename) -{ -#ifdef _WIN32 - - HANDLE file = CreateFileA(filename.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (file == INVALID_HANDLE_VALUE) - return -1; - - FILETIME modTime; - - bool success = GetFileTime(file, NULL, NULL, &modTime); - CloseHandle(file); - - if (success) - { - LARGE_INTEGER li; - ULONG seconds; - li.QuadPart = modTime.dwHighDateTime; - li.QuadPart = (li.QuadPart << 32) | modTime.dwLowDateTime; - RtlTimeToSecondsSince1970(&li, &seconds); - - return seconds; - } - else - { - return -1; - } -#elif __APPLE__ - - struct stat attrib; - stat(filename.c_str(), &attrib); - time_t modificationTime = attrib.st_mtimespec.tv_sec; - - return modificationTime; - -#else - struct stat attrib; - stat(filename.c_str(), &attrib); - time_t modificationTime = attrib.st_mtim.tv_sec; - - return modificationTime; -#endif -} - -long Utils::getFileSize(const string &filename) -{ - std::error_code ec; - std::filesystem::path path; - - path = filename; - - - uintmax_t fileSize = std::filesystem::file_size(path, ec); - - if (!ec) - return fileSize; - return -1; -} - -void Utils::touch(const string &filename) -{ -#ifdef _WIN32 - - HANDLE file = CreateFileA(filename.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (file == INVALID_HANDLE_VALUE) - return; - - FILETIME ft; - SYSTEMTIME st; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - SetFileTime(file, NULL, NULL, &ft); - - CloseHandle(file); - -#else - struct utimbuf newTime; - - time_t newTimeT; - time(&newTimeT); - - newTime.actime = newTimeT; - newTime.modtime = newTimeT; - - utime(filename.c_str(), &newTime); -#endif -} - -bool Utils::renameOverwrite(const string &oldName, const string &newName) -{ - std::filesystem::path o = osPath(oldName); - std::filesystem::path n = osPath(newName); - std::error_code ec; - -#ifdef _WIN32 - std::error_code er; - if (std::filesystem::exists(n, er)) - { - std::filesystem::file_status s = std::filesystem::status(n); - - bool readOnly = (s.permissions() & std::filesystem::perms::owner_write) == std::filesystem::perms::none; - if (readOnly) - std::filesystem::permissions(n, std::filesystem::perms::owner_write); - } -#endif - - std::filesystem::rename(o, n, ec); - - return !ec; -} - -bool Utils::removeFile(const string &path) -{ - std::filesystem::path p = osPath(path); - std::error_code ec; - - std::filesystem::remove(p, ec); - - return !ec; -} - -std::filesystem::path Utils::osPath(const string &path) -{ - return std::filesystem::path(path); -} - -string Utils::osPath(const std::filesystem::path &path) -{ - return path.generic_string(); -} - -void Utils::remove(vector &target, const vector &toRemove) -{ - for (const string &remove : toRemove) - target.erase(std::remove_if(target.begin(), target.end(), [&remove](const string& str){return (str == remove);}), target.end()); -} - -void Utils::sleep(int ms) -{ - -#ifdef _WIN32 - Sleep(DWORD(ms)); -#else - struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; - nanosleep(&ts, NULL); -#endif -} - -bool Utils::isEqual(const double a, const double b) -{ - if (isnan(a) || isnan(b)) return (isnan(a) && isnan(b)); - - return (fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * std::numeric_limits::epsilon())); -} -bool Utils::isEqual(const float a, const float b) -{ - if (isnan(a) || isnan(b)) return (isnan(a) && isnan(b)); - - return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * std::numeric_limits::epsilon()); -} - -#ifdef _WIN32 -std::wstring Utils::getShortPathWin(const std::wstring & longPath) -{ - //See: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getshortpathnamew - long length = 0; - TCHAR* buffer = NULL; - -// First obtain the size needed by passing NULL and 0. - - length = GetShortPathName(longPath.c_str(), NULL, 0); - if (length == 0) - return longPath; - -// Dynamically allocate the correct size -// (terminating null char was included in length) - - buffer = new TCHAR[length]; - -// Now simply call again using same long path. - - length = GetShortPathName(longPath.c_str(), buffer, length); - if (length == 0) - { - delete[] buffer; - return longPath; - } - - std::wstring shortPath(buffer, length); - - delete [] buffer; - - return shortPath; -} - -string Utils::wstringToString(const std::wstring & wstr) -{ - std::string str; - - //get size of buffer we need - int requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), -1, NULL, 0, NULL, NULL ); - str.resize(requiredSize); - - //convert it - WideCharToMultiByte(CP_UTF8, 0, wstr.data(), -1, str.data(), str.size(), NULL, NULL ); - str.resize(requiredSize-1);//drop /nul - - return str; - -} - -wstring Utils::stringToWString(const std::string &str) -{ - std::wstring wstr; - - //get size of buffer we need - int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str.data(), -1, NULL, 0); - wstr.resize(requiredSize); - - //convert it - MultiByteToWideChar(CP_UTF8, 0, str.data(), -1, wstr.data(), wstr.size()); - wstr.resize(requiredSize-1);//drop /nul - - return wstr; -} -#endif diff --git a/Common/utils.h b/Common/utils.h deleted file mode 100644 index 30e04cad54d..00000000000 --- a/Common/utils.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// 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, see . -// - -#ifndef UTILS_H -#define UTILS_H - -#include -#include -#include -#include -#include -#include -#include "timers.h" - -enum class FileTypeBase; - -typedef std::vector doublevec; -typedef std::vector boolvec; -typedef std::vector intvec; -typedef std::vector sizetvec; -typedef std::set intset; -typedef std::set sizetset; -typedef std::set doubleset; -typedef std::map intstrmap; -typedef std::map strstrmap; -typedef std::map strintmap; -typedef std::map intintmap; -typedef std::set stringset; -typedef std::vector stringvec; -typedef std::vector stringvecvec; - -/// One of the utility classes -/// This is for the sort of functions that you might want to use in either Desktop or Engine. Should not be used in R-Interface or jaspResults. -class Utils -{ -public: - typedef FileTypeBase FileType; - typedef std::vector FileTypeVector; - - static Utils::FileType getTypeFromFileName( const std::string &path); - - static long currentMillis(); - static long currentSeconds(); - static long getFileModificationTime(const std::string &filename); - static long getFileSize( const std::string &filename); - static void touch( const std::string &filename); - static bool renameOverwrite( const std::string &oldName, const std::string &newName); - static bool removeFile( const std::string &path); - - static std::filesystem::path osPath(const std::string &path); - static std::string osPath(const std::filesystem::path &path); - - static void remove(std::vector &target, const std::vector &toRemove); - static void sleep(int ms); - - static bool isEqual(const float a, const float b); - static bool isEqual(const double a, const double b); - -#ifdef _WIN32 - static std::wstring getShortPathWin(const std::wstring & path); - static std::string wstringToString(const std::wstring & wstr); - static std::wstring stringToWString(const std::string & str); -#endif - - -}; - -#endif // UTILS_H diff --git a/Common/version.cpp b/Common/version.cpp deleted file mode 100644 index 331809c6c44..00000000000 --- a/Common/version.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// 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, see . -// -#include "version.h" -#include -#include - -const char * Version::encodingError::what() const noexcept -{ - //Just here to have an out-of-line virtual method so that clang and gcc don't complain so much - return std::runtime_error::what(); -} - - -Version::Version(const char * version) -{ - fromString(version); -} - -Version::Version(const std::string & version) -{ - fromString(version); -} - -void Version::fromString(const std::string & version) -{ - const static std::regex parseIt("(\\d+)(\\.(\\d+))?(\\.(\\d+))?(\\.(\\d+))?"); //(sub)groups: 1 3 5 7//0 is whole match/line - - if (version.empty()) return; // Empty version. - - std::smatch found; - if(!std::regex_match(version, found, parseIt)) - throw encodingError(version); - - std::string majorStr = found[1], - minorStr = found[3], - releaseStr = found[5], - fourthStr = found[7]; - - - try - { - if(majorStr != "") _major = std::stoul(majorStr); - if(minorStr != "") _minor = std::stoul(minorStr); - if(releaseStr != "") _release = std::stoul(releaseStr); - if(fourthStr != "") _fourth = std::stoul(fourthStr); - } - catch(...) { throw encodingError(version); } -} - -std::string Version::asString(size_t nums) const -{ - bool addFourth = _fourth > 0 || nums > 3, - addRelease = addFourth || _release > 0 || nums > 2, - addMinor = addRelease || _minor > 0 || nums > 1; - - std::stringstream out; - out << std::to_string(_major); - if(addMinor) out << "." << std::to_string(_minor); - if(addRelease) out << "." << std::to_string(_release); - if(addFourth) out << "." << std::to_string(_fourth); - - return out.str(); -} - -void Version::swap(Version &other) -{ - std::swap(_major, other._major ); - std::swap(_minor, other._minor ); - std::swap(_release, other._release ); - std::swap(_fourth, other._fourth ); -} - -bool Version::operator == (const Version & other) const { return !operator!=(other); } -bool Version::operator <= (const Version & other) const { return operator==(other) || operator<(other); } -bool Version::operator >= (const Version & other) const { return !operator<(other); } -bool Version::operator > (const Version & other) const { return operator!=(other) && operator>=(other); } - -bool Version::operator != (const Version & other) const -{ - return _major != other._major || _minor != other._minor || _release != other._release || _fourth != other._fourth; -} - -bool Version::operator < (const Version & other) const -{ - if(_major < other._major) return true; - if(_major > other._major) return false; - - if(_minor < other._minor) return true; - if(_minor > other._minor) return false; - - if(_release < other._release) return true; - if(_release > other._release) return false; - - if(_fourth < other._fourth) return true; - - return false; -} - - -bool Version::isEmpty() const -{ - return - _major == 0 && - _minor == 0 && - _release == 0 && - _fourth == 0; -} diff --git a/Common/version.h b/Common/version.h deleted file mode 100644 index 9e0f6678b27..00000000000 --- a/Common/version.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// 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, see . -// - -#ifndef VERSION_H -#define VERSION_H - -#include -#include - -/// -/// Stores versions and has flexible parsing from string to instantiate. -/// The fourth value wat used as a sort of alpha/beta flagg at some point in the past but it added a lot of crap and we didn't use it so I removed it. -/// To be able to read those values it is still there, vestigially. -class Version -{ -public: - struct encodingError : public std::runtime_error - { - encodingError(const std::string & versionStr) : std::runtime_error("Module version not understood: " + versionStr) {} - const char* what() const noexcept override; - }; - - Version(const char * version); - Version(const std::string & version); - Version(unsigned int major = 0, unsigned int minor = 0, unsigned int release = 0, unsigned int fourth = 0) : _major(major), _minor(minor), _release(release), _fourth(fourth) {} - - ///By default this tries to minimize the string, so all trailing zeroes + dots are removed. Unless versionNumbersToInclude is set to something >1. If 2 then major and minor are always shown, etc. - std::string asString(size_t versionNumbersToInclude = 0) const; - - - - unsigned int major() const { return _major; } - unsigned int minor() const { return _minor; } - unsigned int release() const { return _release; } - unsigned int fourth() const { return _fourth; } - - bool isEmpty() const; - - void swap(Version &other ); - - bool operator < (const Version & other) const; - bool operator <= (const Version & other) const; - bool operator >= (const Version & other) const; - bool operator > (const Version & other) const; - bool operator == (const Version & other) const; - bool operator != (const Version & other) const; - -protected: - void fromString(const std::string & version); - - -private: - unsigned int _major = 0, - _minor = 0, - _release = 0, - _fourth = 0; //This is just here to be able to parse older files... -}; - -#endif // VERSION_H diff --git a/CommonData/CMakeLists.txt b/CommonData/CMakeLists.txt index 7405a9977ff..f6af617e030 100644 --- a/CommonData/CMakeLists.txt +++ b/CommonData/CMakeLists.txt @@ -23,7 +23,7 @@ endif() target_include_directories( CommonData PUBLIC # JASP - ${PROJECT_SOURCE_DIR}/Common + ${PROJECT_SOURCE_DIR}/jaspCommonLib # R ${R_INCLUDE_PATH} ${R_HOME_PATH}/include @@ -40,6 +40,10 @@ target_link_libraries( #$<$:${_PKGCONFIG_LIB_JSONCPP_LIBRARIES}> #$<$:${_PKGCONFIG_LIB_JSONCPP_LINK_LIBRARIES}> # + Boost::system + Boost::date_time + Boost::timer + Boost::chrono Common LibArchive::LibArchive SQLite::SQLite3 diff --git a/Desktop/CMakeLists.txt b/Desktop/CMakeLists.txt index 0debf23a117..7b9a78d5019 100644 --- a/Desktop/CMakeLists.txt +++ b/Desktop/CMakeLists.txt @@ -47,7 +47,6 @@ qt_add_executable( set( QML_IMPORT_PATH "${PROJECT_SOURCE_DIR}/Desktop/components" - "${PROJECT_SOURCE_DIR}/QMLComponents/components" CACHE PATH "Path used to locate CMake modules by Qt Creator" @@ -92,10 +91,10 @@ target_include_directories( JASP PUBLIC ${CMAKE_CURRENT_LIST_DIR} - ${PROJECT_SOURCE_DIR}/Common - ${PROJECT_SOURCE_DIR}/Common/QtUtils + ${PROJECT_SOURCE_DIR}/jaspCommonLib + ${PROJECT_SOURCE_DIR}/jaspCommonLib/QtUtils ${PROJECT_SOURCE_DIR}/CommonData - ${PROJECT_SOURCE_DIR}/QMLComponents + #${PROJECT_SOURCE_DIR}/JASPQMLControlsPlugin # ReadStat $<$:${RTOOLS_LIBREADSTAT_H}> ${LIBREADSTAT_INCLUDE_DIRS} @@ -109,9 +108,8 @@ target_include_directories( target_link_libraries( JASP PUBLIC - Common + CommonQt CommonData - QMLComponents Qt::Core Qt::Gui Qt::OpenGL diff --git a/Desktop/analysis/analyses.cpp b/Desktop/analysis/analyses.cpp index f75a82c1d00..a25227a8965 100644 --- a/Desktop/analysis/analyses.cpp +++ b/Desktop/analysis/analyses.cpp @@ -15,23 +15,15 @@ // License along with this program. If not, see // . // +#include +#include #include "analyses.h" -#include "appdirs.h" #include "utilities/settings.h" -#include "processinfo.h" #include "modules/ribbonmodel.h" -#include "analysisform.h" - -#include -#include - - -#include "utils.h" -#include "tempfiles.h" #include "log.h" - #include "knownissues.h" +#include "analysisformbase.h" using namespace std; using Modules::Upgrader; diff --git a/Desktop/analysis/analysis.cpp b/Desktop/analysis/analysis.cpp index 6769b0a6eed..d67d9a14b03 100644 --- a/Desktop/analysis/analysis.cpp +++ b/Desktop/analysis/analysis.cpp @@ -21,7 +21,7 @@ #include "appinfo.h" #include "dirs.h" #include "analyses.h" -#include "analysisform.h" +#include "analysisformbase.h" #include "qutils.h" #include "log.h" #include "utils.h" @@ -29,6 +29,7 @@ #include "gui/preferencesmodel.h" #include "utilities/reporter.h" #include "results/resultsjsinterface.h" +#include "messageforwarder.h" Analysis::Analysis(size_t id, Modules::AnalysisEntry * analysisEntry, std::string title, std::string moduleVersion, Json::Value *data) : AnalysisBase(Analyses::analyses(), moduleVersion), @@ -332,10 +333,10 @@ void Analysis::createForm(QQuickItem* parentItem) if (_analysisForm) { - connect(this, &Analysis::rSourceChanged, _analysisForm, &AnalysisForm::rSourceChanged ); - connect(this, &Analysis::refreshTableViewModels, _analysisForm, &AnalysisForm::refreshTableViewModels ); - connect(this, &Analysis::titleChanged, _analysisForm, &AnalysisForm::titleChanged ); - connect(this, &Analysis::needsRefreshChanged, _analysisForm, &AnalysisForm::needsRefreshChanged ); + connect(this, &Analysis::rSourceChanged, _analysisForm, &AnalysisFormBase::rSourceChanged ); + connect(this, &Analysis::refreshTableViewModels, _analysisForm, &AnalysisFormBase::refreshTableViewModels ); + connect(this, &Analysis::titleChanged, _analysisForm, &AnalysisFormBase::titleChanged ); + connect(this, &Analysis::needsRefreshChanged, _analysisForm, &AnalysisFormBase::needsRefreshChanged ); connect(this, &Analysis::boundValuesChanged, this, &Analysis::setRSyntaxTextInResult, Qt::QueuedConnection ); setRSyntaxTextInResult(); @@ -659,6 +660,11 @@ Json::Value Analysis::editOptionsOfPlot(const std::string & uniqueName, bool emi return editOptions; } +AnalysisFormBase* Analysis::form() const +{ + return _analysisForm; +} + bool Analysis::_editOptionsOfPlot(const Json::Value & results, const std::string & uniqueName, Json::Value & editOptions) { if(results.isArray()) diff --git a/Desktop/analysis/analysis.h b/Desktop/analysis/analysis.h index 18c8a1ad58a..f353c8575a3 100644 --- a/Desktop/analysis/analysis.h +++ b/Desktop/analysis/analysis.h @@ -24,14 +24,12 @@ #include "version.h" #include "enginedefinitions.h" -#include "controls/jaspcontrol.h" #include #include "analysisbase.h" #include "modules/dynamicmodules.h" #include "data/datasetpackage.h" #include "qutils.h" -#include "modules/upgrader/upgradechange.h" #include #include @@ -110,8 +108,8 @@ class Analysis : public AnalysisBase const Json::Value & imgOptions() const { return _imgOptions; } const Json::Value & imgResults() const { return _imgResults; } Modules::DynamicModule * dynamicModule() const { return _dynamicModule; } - AnalysisForm * form() const { return _analysisForm; } - bool hasForm() const { return _analysisForm; } + AnalysisFormBase* form() const; + bool hasForm() const { return _analysisForm != nullptr; } bool isDuplicate() const override { return _isDuplicate; } bool shouldRun() { return !isWaitingForModule() && ( isSaveImg() || isEditImg() || isRewriteImgs() || isEmpty() ) && form(); } bool beingTranslated() { return _beingTranslated; }; diff --git a/QMLComponents/components/JASP/Theme/DarkTheme.qml b/Desktop/components/JASP/Theme/DarkTheme.qml similarity index 100% rename from QMLComponents/components/JASP/Theme/DarkTheme.qml rename to Desktop/components/JASP/Theme/DarkTheme.qml diff --git a/QMLComponents/components/JASP/Theme/Theme.qml b/Desktop/components/JASP/Theme/Theme.qml similarity index 100% rename from QMLComponents/components/JASP/Theme/Theme.qml rename to Desktop/components/JASP/Theme/Theme.qml diff --git a/QMLComponents/components/JASP/Theme/qmldir b/Desktop/components/JASP/Theme/qmldir similarity index 100% rename from QMLComponents/components/JASP/Theme/qmldir rename to Desktop/components/JASP/Theme/qmldir diff --git a/Desktop/components/JASP/Widgets/AnalysisFormExpander.qml b/Desktop/components/JASP/Widgets/AnalysisFormExpander.qml index 6a0f9a148c1..5bbbf44bdce 100644 --- a/Desktop/components/JASP/Widgets/AnalysisFormExpander.qml +++ b/Desktop/components/JASP/Widgets/AnalysisFormExpander.qml @@ -1,6 +1,6 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP.Controls import Qt5Compat.GraphicalEffects DropArea @@ -128,7 +128,7 @@ DropArea } - ToolTip + QTC.ToolTip { text: qsTr("Drag to reorder the analyses") timeout: jaspTheme.toolTipTimeout diff --git a/Desktop/components/JASP/Widgets/AnalysisForms.qml b/Desktop/components/JASP/Widgets/AnalysisForms.qml index a7db37f2528..a1eb8de20f0 100644 --- a/Desktop/components/JASP/Widgets/AnalysisForms.qml +++ b/Desktop/components/JASP/Widgets/AnalysisForms.qml @@ -1,7 +1,6 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 +import QtQuick import JASP -import JASP.Controls 1.0 +import JASP.Controls FocusScope diff --git a/Desktop/components/JASP/Widgets/ComputeColumnWindow.qml b/Desktop/components/JASP/Widgets/ComputeColumnWindow.qml index 997b9ed8964..21c489e3a51 100644 --- a/Desktop/components/JASP/Widgets/ComputeColumnWindow.qml +++ b/Desktop/components/JASP/Widgets/ComputeColumnWindow.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.3 -import JASP.Controls 1.0 as JaspControls +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import JASP.Controls as JaspControls import "FilterConstructor" diff --git a/Desktop/components/JASP/Widgets/CreateComputeColumnDialog.qml b/Desktop/components/JASP/Widgets/CreateComputeColumnDialog.qml index 1e80a84676b..e4c0555377e 100644 --- a/Desktop/components/JASP/Widgets/CreateComputeColumnDialog.qml +++ b/Desktop/components/JASP/Widgets/CreateComputeColumnDialog.qml @@ -1,5 +1,5 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick +import QtQuick.Controls import JASP.Controls as JaspControls diff --git a/Desktop/components/JASP/Widgets/CustomMenu.qml b/Desktop/components/JASP/Widgets/CustomMenu.qml index 555175b09b3..1fa26022c79 100644 --- a/Desktop/components/JASP/Widgets/CustomMenu.qml +++ b/Desktop/components/JASP/Widgets/CustomMenu.qml @@ -16,9 +16,9 @@ // . // -import QtQuick 2.15 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 as JASPControl +import QtQuick +import QtQuick.Controls +import JASP.Controls as JASPControl import Qt5Compat.GraphicalEffects FocusScope diff --git a/Desktop/components/JASP/Widgets/EnginesWindow.qml b/Desktop/components/JASP/Widgets/EnginesWindow.qml index 5678e233eff..ea8d7545d39 100644 --- a/Desktop/components/JASP/Widgets/EnginesWindow.qml +++ b/Desktop/components/JASP/Widgets/EnginesWindow.qml @@ -1,8 +1,8 @@ -import QtQuick 2.12 -import QtQuick.Window 2.12 -import QtWebEngine 1.8 -import JASP.Widgets 1.0 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Window +import QtWebEngine +import JASP.Widgets +import JASP.Controls Window { diff --git a/Desktop/components/JASP/Widgets/FileMenu/BreadCrumbs.qml b/Desktop/components/JASP/Widgets/FileMenu/BreadCrumbs.qml index f6673df0528..c10eff5b210 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/BreadCrumbs.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/BreadCrumbs.qml @@ -1,9 +1,7 @@ -import QtQuick 2.11 -import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.4 - -import JASP.Widgets 1.0 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Layouts +import JASP.Widgets +import JASP.Controls ListView { diff --git a/Desktop/components/JASP/Widgets/FileMenu/Computer.qml b/Desktop/components/JASP/Widgets/FileMenu/Computer.qml index 0012f4c30e9..3dcf7d7a0e6 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/Computer.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/Computer.qml @@ -1,9 +1,8 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 - -import JASP.Controls 1.0 -import JASP.Widgets 1.0 +import QtQuick +import QtQuick.Controls as QTC +import QtQuick.Layouts +import JASP.Controls +import JASP.Widgets Item { @@ -34,7 +33,7 @@ Item } - ToolSeparator + QTC.ToolSeparator { id: firstSeparator diff --git a/Desktop/components/JASP/Widgets/FileMenu/CurrentFile.qml b/Desktop/components/JASP/Widgets/FileMenu/CurrentFile.qml index 3be5ff10714..c83884bb200 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/CurrentFile.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/CurrentFile.qml @@ -1,6 +1,5 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 - +import QtQuick +import QtQuick.Controls Item { diff --git a/Desktop/components/JASP/Widgets/FileMenu/DataLibrary.qml b/Desktop/components/JASP/Widgets/FileMenu/DataLibrary.qml index b1b884a6323..6af2fb0152a 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/DataLibrary.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/DataLibrary.qml @@ -1,7 +1,6 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 - +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts Item { diff --git a/Desktop/components/JASP/Widgets/FileMenu/DataLibraryBreadCrumbs.qml b/Desktop/components/JASP/Widgets/FileMenu/DataLibraryBreadCrumbs.qml index a390d5430c1..dcbb406528d 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/DataLibraryBreadCrumbs.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/DataLibraryBreadCrumbs.qml @@ -1,7 +1,7 @@ -import QtQuick 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 -import JASP.Theme 1.0 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import JASP.Theme ListView { diff --git a/Desktop/components/JASP/Widgets/FileMenu/FileList.qml b/Desktop/components/JASP/Widgets/FileMenu/FileList.qml index 7eeced8b7d5..dc2f232fb43 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/FileList.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/FileList.qml @@ -1,7 +1,5 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 - +import QtQuick +import JASP.Controls ListView { diff --git a/Desktop/components/JASP/Widgets/FileMenu/FileMenu.qml b/Desktop/components/JASP/Widgets/FileMenu/FileMenu.qml index 3fb2d62dccf..230c1f7cde2 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/FileMenu.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/FileMenu.qml @@ -1,10 +1,9 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 - -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Controls as QTC +import QtQuick.Layouts import JASP -import FileOperation 1.0 +import JASP.Controls +import FileOperation FocusScope { @@ -153,7 +152,7 @@ FocusScope } } - ToolSeparator + QTC.ToolSeparator { id: actionToolSeperator anchors diff --git a/Desktop/components/JASP/Widgets/FileMenu/ListItem.qml b/Desktop/components/JASP/Widgets/FileMenu/ListItem.qml index 42d7f2d53f2..f8c9b83036f 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/ListItem.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/ListItem.qml @@ -1,7 +1,6 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 - +import QtQuick +import QtQuick.Controls as QTC +import JASP.Controls FocusScope { @@ -95,7 +94,7 @@ FocusScope onDoubleClicked: {} } - ToolTip + QTC.ToolTip { id: firstFileOrFolderTooltip delay: 500 @@ -176,7 +175,7 @@ FocusScope cursorShape: Qt.PointingHandCursor } - ToolTip + QTC.ToolTip { id: datafileToolTip delay: 500 @@ -233,7 +232,7 @@ FocusScope onDoubleClicked: {} } - ToolTip + QTC.ToolTip { id: commonToolTip delay: 500 diff --git a/Desktop/components/JASP/Widgets/FileMenu/MenuHeader.qml b/Desktop/components/JASP/Widgets/FileMenu/MenuHeader.qml index d5e3b244fe7..3f107b9eb6d 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/MenuHeader.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/MenuHeader.qml @@ -1,9 +1,9 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls as QTC +import QtQuick.Layouts -import JASP.Widgets 1.0 -import JASP.Controls 1.0 +import JASP.Widgets +import JASP.Controls Item { @@ -63,7 +63,7 @@ Item } } - ToolSeparator + QTC.ToolSeparator { id: firstSeparator diff --git a/Desktop/components/JASP/Widgets/FileMenu/OSF.qml b/Desktop/components/JASP/Widgets/FileMenu/OSF.qml index 780fca7edb0..518a01a76b5 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/OSF.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/OSF.qml @@ -16,11 +16,10 @@ // . // -import QtQuick 2.0 -import QtQuick.Controls 2.2 - -import JASP.Controls 1.0 -import JASP.Widgets 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP.Controls +import JASP.Widgets //import QtQuick.Layouts 1.3 @@ -120,7 +119,7 @@ Item sortMenuModel: fileMenuModel.osf.sortedMenuModel } - ToolSeparator + QTC.ToolSeparator { id : firstSeparator visible : loggedin diff --git a/Desktop/components/JASP/Widgets/FileMenu/OSFLogin.qml b/Desktop/components/JASP/Widgets/FileMenu/OSFLogin.qml index ba09039e81c..b7268e43b3f 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/OSFLogin.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/OSFLogin.qml @@ -16,9 +16,9 @@ // . // -import QtQuick -import QtQuick.Controls -import JASP.Controls +import QtQuick +import QtQuick.Controls +import JASP.Controls import JASP.Widgets import QtQuick.Layouts diff --git a/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml b/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml index eba2bc91565..2480aa7c0e1 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml @@ -1,9 +1,9 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import JASP.Widgets 1.0 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP.Widgets +import JASP.Controls -ScrollView +QTC.ScrollView { id: scrollPrefs focus: true diff --git a/Desktop/components/JASP/Widgets/FileMenu/PrefsGroupRect.qml b/Desktop/components/JASP/Widgets/FileMenu/PrefsGroupRect.qml index 3f079553f03..578f290ea3a 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/PrefsGroupRect.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/PrefsGroupRect.qml @@ -1,10 +1,8 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import QtQuick.Layouts 1.3 -import JASP.Widgets 1.0 - -import JASP.Controls 1.0 -import JASP 1.0 +import QtQuick +import QtQuick.Layouts +import JASP.Widgets +import JASP.Controls +import JASP Rectangle { diff --git a/Desktop/components/JASP/Widgets/FileMenu/PrefsResults.qml b/Desktop/components/JASP/Widgets/FileMenu/PrefsResults.qml index c5601c16818..2b5e7001bb4 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/PrefsResults.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/PrefsResults.qml @@ -1,10 +1,9 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Widgets 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP.Widgets +import JASP.Controls -import JASP.Controls 1.0 - -ScrollView +QTC.ScrollView { id: scrollPrefs focus: true diff --git a/Desktop/components/JASP/Widgets/FileMenu/PrefsTextInput.qml b/Desktop/components/JASP/Widgets/FileMenu/PrefsTextInput.qml index 3d1b395513d..f3a57722db0 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/PrefsTextInput.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/PrefsTextInput.qml @@ -1,5 +1,5 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 +import QtQuick +import QtQuick.Controls Rectangle { diff --git a/Desktop/components/JASP/Widgets/FileMenu/PrefsUI.qml b/Desktop/components/JASP/Widgets/FileMenu/PrefsUI.qml index 9c9bd25347e..8e8294ddab8 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/PrefsUI.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/PrefsUI.qml @@ -1,10 +1,10 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 +import QtQuick +import QtQuick.Controls as QTC import QtQuick.Layouts 1.3 as L -import JASP.Widgets 1.0 -import JASP.Controls 1.0 +import JASP.Widgets +import JASP.Controls -ScrollView +QTC.ScrollView { id: scrollPrefs focus: true @@ -181,7 +181,7 @@ ScrollView id: languageGroup title: qsTr("Preferred language") - ComboBox + DropDown { id: languages fieldWidth: 100 diff --git a/Desktop/components/JASP/Widgets/FileMenu/RecentFiles.qml b/Desktop/components/JASP/Widgets/FileMenu/RecentFiles.qml index e05df5b4728..eb957182f66 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/RecentFiles.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/RecentFiles.qml @@ -1,7 +1,6 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 - +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts Item { diff --git a/Desktop/components/JASP/Widgets/FilterConstructor/ComputedColumnsConstructor.qml b/Desktop/components/JASP/Widgets/FilterConstructor/ComputedColumnsConstructor.qml index 6572ff0c8d0..4a8eeb446e5 100644 --- a/Desktop/components/JASP/Widgets/FilterConstructor/ComputedColumnsConstructor.qml +++ b/Desktop/components/JASP/Widgets/FilterConstructor/ComputedColumnsConstructor.qml @@ -1,6 +1,6 @@ -import JASP.Controls 1.0 -import QtQuick.Controls 2.2 -import QtQuick 2.9 +import JASP.Controls +import QtQuick.Controls +import QtQuick FocusScope diff --git a/Desktop/components/JASP/Widgets/FilterWindow.qml b/Desktop/components/JASP/Widgets/FilterWindow.qml index 736727261b8..a8c6ab0ee55 100644 --- a/Desktop/components/JASP/Widgets/FilterWindow.qml +++ b/Desktop/components/JASP/Widgets/FilterWindow.qml @@ -1,6 +1,7 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import JASP.Controls 1.0 as JaspControls +import QtQuick +import QtQuick.Controls as QTC +import JASP +import JASP.Controls import "FilterConstructor" FocusScope @@ -156,7 +157,7 @@ FocusScope } } - JaspControls.MenuButton + MenuButton { id: helpEasyRectangularButton height: 33 * jaspTheme.uiScale @@ -171,7 +172,7 @@ FocusScope top: parent.top } } - JaspControls.MenuButton + MenuButton { id: closeButton height: 33 * jaspTheme.uiScale @@ -188,7 +189,7 @@ FocusScope } } - JaspControls.RectangularButton + RectangularButton { id: rRectangularButton iconSource: jaspTheme.iconPath + "/R.png" @@ -202,7 +203,7 @@ FocusScope } } - JaspControls.RectangularButton + RectangularButton { id: showInactiveFilteredButtonEasy iconSource: dataSetModel.showInactive ? jaspTheme.iconPath + "/eyeOpen.png" : jaspTheme.iconPath + "/eyeClosed.png" @@ -217,7 +218,7 @@ FocusScope } } - JaspControls.RectangularButton + RectangularButton { property bool showApplyNotApplied: easyFilterConstructor.somethingChanged || easyFilterConstructor.showStartupMsg @@ -276,7 +277,7 @@ FocusScope height: implicitHeight * ratio } - ScrollView + QTC.ScrollView { id: filterScroller anchors.fill: parent @@ -300,7 +301,7 @@ FocusScope } - TextArea + QTC.TextArea { id: filterGeneratedEdit anchors.top: filterGeneratedBox.top @@ -314,11 +315,11 @@ FocusScope onActiveFocusChanged: if(!activeFocus) deselect() font.pixelSize: baseFontSize * preferencesModel.uiScale font.family: jaspTheme.fontCode.family - wrapMode: TextArea.WrapAtWordBoundaryOrAnywhere + wrapMode: QTC.TextArea.WrapAtWordBoundaryOrAnywhere } - JaspControls.RectangularButton + RectangularButton { id: resetAllGeneratedFilters width: dataSetModel.columnsFilteredCount > 0 ? height : 0 @@ -344,7 +345,7 @@ FocusScope anchors.left: parent.left anchors.right: parent.right - TextArea + QTC.TextArea { id: filterEdit @@ -353,7 +354,7 @@ FocusScope onActiveFocusChanged: if(!activeFocus) deselect() font.family: jaspTheme.fontCode.family font.pixelSize: baseFontSize * preferencesModel.uiScale - wrapMode: TextArea.WrapAtWordBoundaryOrAnywhere + wrapMode: QTC.TextArea.WrapAtWordBoundaryOrAnywhere color: jaspTheme.textEnabled property bool changedSinceLastApply: text !== filterModel.rFilter @@ -403,7 +404,7 @@ FocusScope } } - ScrollView + QTC.ScrollView { id: filterErrorScroll height: filterWindow.minimumHeightTextBoxes @@ -415,7 +416,7 @@ FocusScope bottom: filterButtons.top } - TextArea + QTC.TextArea { id: filterError color: jaspTheme.red @@ -455,7 +456,7 @@ FocusScope bottom: parent.bottom } - JaspControls.RectangularButton + RectangularButton { id: easyRectangularButton iconSource: jaspTheme.iconPath + "/NotR.png" @@ -470,7 +471,7 @@ FocusScope } } - JaspControls.RectangularButton + RectangularButton { id: showInactiveFilteredButtonR iconSource: dataSetModel.showInactive ? jaspTheme.iconPath + "/eyeOpen.png" : jaspTheme.iconPath + "/eyeClosed.png" @@ -485,7 +486,7 @@ FocusScope } } - JaspControls.RectangularButton + RectangularButton { id: clearRectangularButton iconSource: jaspTheme.iconPath + "eraser.png" @@ -503,7 +504,7 @@ FocusScope } } - JaspControls.RectangularButton + RectangularButton { id: applyFilter @@ -521,7 +522,7 @@ FocusScope toolTip: filterEdit.changedSinceLastApply ? qsTr("Click to apply filter") : filterIsDefault ? qsTr("Filter is unchanged from default") : qsTr("Filter is already applied") } - JaspControls.RectangularButton + RectangularButton { id: helpButton iconSource: jaspTheme.iconPath + "info-button.png" @@ -534,7 +535,7 @@ FocusScope } - JaspControls.RectangularButton + RectangularButton { id: closeRectangularButton iconSource: jaspTheme.iconPath + "cross.png" diff --git a/Desktop/components/JASP/Widgets/HelpWindow.qml b/Desktop/components/JASP/Widgets/HelpWindow.qml index 968c30e0bd3..e288a30f77a 100644 --- a/Desktop/components/JASP/Widgets/HelpWindow.qml +++ b/Desktop/components/JASP/Widgets/HelpWindow.qml @@ -1,8 +1,8 @@ -import QtQuick 2.12 -import QtQuick.Window 2.12 -import QtWebEngine 1.8 -import JASP.Widgets 1.0 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Window +import QtWebEngine +import JASP.Widgets +import JASP.Controls Window { diff --git a/Desktop/components/JASP/Widgets/JASPDataView.qml b/Desktop/components/JASP/Widgets/JASPDataView.qml index 57f54b0f515..54b8c8f0bb6 100644 --- a/Desktop/components/JASP/Widgets/JASPDataView.qml +++ b/Desktop/components/JASP/Widgets/JASPDataView.qml @@ -1,9 +1,9 @@ -import QtQuick 2.9 -import QtQuick.Window 2.3 -import QtQuick.Controls 2.2 +import QtQuick +import QtQuick.Window +//import QtQuick.Controls -import JASP.Controls 1.0 -import JASP 1.0 +import JASP.Controls +import JASP FocusScope { diff --git a/Desktop/components/JASP/Widgets/JASPSplitHandle.qml b/Desktop/components/JASP/Widgets/JASPSplitHandle.qml index 745092c72b9..fc6e4b72132 100644 --- a/Desktop/components/JASP/Widgets/JASPSplitHandle.qml +++ b/Desktop/components/JASP/Widgets/JASPSplitHandle.qml @@ -1,6 +1,6 @@ -import QtQuick 2.11 -import JASP.Widgets 1.0 -import QtQuick.Controls 6.0 +import QtQuick +import JASP.Widgets +import QtQuick.Controls //Only works vertically right now... diff --git a/Desktop/components/JASP/Widgets/MainPage.qml b/Desktop/components/JASP/Widgets/MainPage.qml index 6bd4307a70f..e80d90e1e2a 100644 --- a/Desktop/components/JASP/Widgets/MainPage.qml +++ b/Desktop/components/JASP/Widgets/MainPage.qml @@ -20,7 +20,8 @@ import QtQuick import QtWebEngine import QtWebChannel import JASP -import QtQuick.Controls +import JASP.Controls +//import QtQuick.Controls Item { diff --git a/Desktop/components/JASP/Widgets/MainWindow.qml b/Desktop/components/JASP/Widgets/MainWindow.qml index 4a96dc4cd59..11f8ed4dd2e 100644 --- a/Desktop/components/JASP/Widgets/MainWindow.qml +++ b/Desktop/components/JASP/Widgets/MainWindow.qml @@ -16,10 +16,10 @@ // . // -import QtQuick 2.11 -import QtQuick.Window 2.11 +import QtQuick +import QtQuick.Window import JASP -import QtQuick.Controls 2.12 +import QtQuick.Controls Window { diff --git a/Desktop/components/JASP/Widgets/MessageBox.qml b/Desktop/components/JASP/Widgets/MessageBox.qml index 6fdd34f8c5f..29ed2037b68 100644 --- a/Desktop/components/JASP/Widgets/MessageBox.qml +++ b/Desktop/components/JASP/Widgets/MessageBox.qml @@ -1,11 +1,10 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP.Controls //import QtQuick.Dialogs 1.2 -Popup -//MessageDialog +QTC.Popup { id: messageRoot @@ -102,7 +101,7 @@ Popup margins: jaspTheme.generalAnchorMargin } - TextArea + QTC.TextArea { id: messageText text: "I should be changed, and I will be!" diff --git a/Desktop/components/JASP/Widgets/ModuleInstaller.qml b/Desktop/components/JASP/Widgets/ModuleInstaller.qml index fa71a66adce..e8ad427d9a0 100644 --- a/Desktop/components/JASP/Widgets/ModuleInstaller.qml +++ b/Desktop/components/JASP/Widgets/ModuleInstaller.qml @@ -16,12 +16,11 @@ // . // -import QtQuick 2.11 -import QtQuick.Controls 2.7 as QTCONTROLS -import Qt.labs.folderlistmodel 2.11 -//import QtQuick.Window 2.3 -import JASP.Controls 1.0 -import JASP.Widgets 1.0 +import QtQuick +import QtQuick.Controls as QTCONTROLS +import Qt.labs.folderlistmodel +import JASP.Controls +import JASP.Widgets QTCONTROLS.Popup { diff --git a/Desktop/components/JASP/Widgets/PlotEditor/PlotEditingAxis.qml b/Desktop/components/JASP/Widgets/PlotEditor/PlotEditingAxis.qml index 2681fcfdc04..98f5e24cc45 100644 --- a/Desktop/components/JASP/Widgets/PlotEditor/PlotEditingAxis.qml +++ b/Desktop/components/JASP/Widgets/PlotEditor/PlotEditingAxis.qml @@ -1,11 +1,11 @@ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Layouts 1.3 -import JASP.Widgets 1.0 as JASPW -import JASP.Theme 1.0 -import JASP.Controls 1.0 as JASPC -import JASP.PlotEditor 1.0 -import JASP 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import JASP.Widgets as JASPW +import JASP.Theme +import JASP.Controls as JASPC +import JASP.PlotEditor +import JASP /* TODO: it might make sense to add a global title/ box around all the options inside one axis. diff --git a/Desktop/components/JASP/Widgets/PlotEditor/PlotEditor.qml b/Desktop/components/JASP/Widgets/PlotEditor/PlotEditor.qml index 06f01415a74..a505a7ef41a 100644 --- a/Desktop/components/JASP/Widgets/PlotEditor/PlotEditor.qml +++ b/Desktop/components/JASP/Widgets/PlotEditor/PlotEditor.qml @@ -1,10 +1,10 @@ -import QtQuick 2.14 -import QtQuick.Controls 6.0 -import QtQuick.Layouts 1.3 -import JASP.Widgets 1.0 as JASPW -import JASP.Theme 1.0 -import JASP.Controls 1.0 as JASPC -import JASP.PlotEditor 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import JASP.Widgets as JASPW +import JASP.Theme +import JASP.Controls as JASPC +import JASP.PlotEditor Popup { diff --git a/Desktop/components/JASP/Widgets/ProgressBarHolder.qml b/Desktop/components/JASP/Widgets/ProgressBarHolder.qml index 298aca7e7d2..46d5d7c9b5e 100644 --- a/Desktop/components/JASP/Widgets/ProgressBarHolder.qml +++ b/Desktop/components/JASP/Widgets/ProgressBarHolder.qml @@ -1,6 +1,5 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 - +import QtQuick +import QtQuick.Controls Item { diff --git a/Desktop/components/JASP/Widgets/RCommanderWindow.qml b/Desktop/components/JASP/Widgets/RCommanderWindow.qml index 175f2bac7fb..6a8d8240c1d 100644 --- a/Desktop/components/JASP/Widgets/RCommanderWindow.qml +++ b/Desktop/components/JASP/Widgets/RCommanderWindow.qml @@ -16,12 +16,12 @@ // . // -import QtQuick 2.12 -import QtQuick.Window 2.12 -import QtQuick.Controls 2.12 -import JASP 1.0 -import JASP.Widgets 1.0 as JW -import JASP.Controls 1.0 as JC +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import JASP +import JASP.Widgets as JW +import JASP.Controls as JC Window { diff --git a/Desktop/components/JASP/Widgets/RenameColumnDialog.qml b/Desktop/components/JASP/Widgets/RenameColumnDialog.qml index 81d9157444d..92381a666f2 100644 --- a/Desktop/components/JASP/Widgets/RenameColumnDialog.qml +++ b/Desktop/components/JASP/Widgets/RenameColumnDialog.qml @@ -1,8 +1,8 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import JASP.Controls 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP.Controls -Popup +QTC.Popup { id: popupRenameColumnDialog; modal: true; diff --git a/Desktop/components/JASP/Widgets/Ribbon/RibbonBar.qml b/Desktop/components/JASP/Widgets/Ribbon/RibbonBar.qml index 0deac041a1b..bb6a66b7d6a 100644 --- a/Desktop/components/JASP/Widgets/Ribbon/RibbonBar.qml +++ b/Desktop/components/JASP/Widgets/Ribbon/RibbonBar.qml @@ -16,8 +16,9 @@ // . // -import QtQuick 2.11 +import QtQuick import JASP +import JASP.Controls FocusScope diff --git a/Desktop/components/JASP/Widgets/Ribbon/RibbonButton.qml b/Desktop/components/JASP/Widgets/Ribbon/RibbonButton.qml index dc5450023ef..df2e938bc7f 100644 --- a/Desktop/components/JASP/Widgets/Ribbon/RibbonButton.qml +++ b/Desktop/components/JASP/Widgets/Ribbon/RibbonButton.qml @@ -16,10 +16,10 @@ // . // -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP 1.0 -import JASP.Widgets 1.0 +import QtQuick +import QtQuick.Controls as QTC +import JASP +import JASP.Widgets Rectangle { @@ -48,10 +48,10 @@ Rectangle signal clicked - ToolTip.text: ribbonButton.toolTip - ToolTip.timeout: jaspTheme.toolTipTimeout - ToolTip.delay: jaspTheme.toolTipDelay - ToolTip.visible: ribbonButton.toolTip !== "" && mice.containsMouse && !ribbonButton.showPressed + QTC.ToolTip.text: ribbonButton.toolTip + QTC.ToolTip.timeout: jaspTheme.toolTipTimeout + QTC.ToolTip.delay: jaspTheme.toolTipDelay + QTC.ToolTip.visible: ribbonButton.toolTip !== "" && mice.containsMouse && !ribbonButton.showPressed Keys.onPressed: (event) => { diff --git a/Desktop/components/JASP/Widgets/Ribbon/Ribbons.qml b/Desktop/components/JASP/Widgets/Ribbon/Ribbons.qml index c1b0456a6c5..91e8cf80d28 100644 --- a/Desktop/components/JASP/Widgets/Ribbon/Ribbons.qml +++ b/Desktop/components/JASP/Widgets/Ribbon/Ribbons.qml @@ -16,9 +16,9 @@ // . // -import QtQuick 2.15 -import QtQuick.Controls 2.15 +import QtQuick import JASP +import JASP.Controls Item { diff --git a/Desktop/components/JASP/Widgets/SaveDiscardCancelDialog.qml b/Desktop/components/JASP/Widgets/SaveDiscardCancelDialog.qml index 287f319fbae..41c3283b8ec 100644 --- a/Desktop/components/JASP/Widgets/SaveDiscardCancelDialog.qml +++ b/Desktop/components/JASP/Widgets/SaveDiscardCancelDialog.qml @@ -1,5 +1,5 @@ -import QtQuick 2.12 -import JASP 1.0 +import QtQuick +import JASP QtObject { diff --git a/Desktop/components/JASP/Widgets/SpinBox.qml b/Desktop/components/JASP/Widgets/SpinBox.qml index ea0d9367463..32e7e18005a 100644 --- a/Desktop/components/JASP/Widgets/SpinBox.qml +++ b/Desktop/components/JASP/Widgets/SpinBox.qml @@ -16,10 +16,10 @@ // . // -import QtQuick 2.11 -import QtQuick.Controls 2.5 -import JASP.Controls 1.0 as JaspControls -import JASP 1.0 +import QtQuick +import QtQuick.Controls +import JASP.Controls as JaspControls +import JASP Item { @@ -97,7 +97,7 @@ Item TextField { id: valueField - validator: JASPDoubleValidator { id: doubleValidator; bottom: root.min; top: root.max ; decimals: root.decimals } + validator: JaspControls.JASPDoubleValidator { id: doubleValidator; bottom: root.min; top: root.max ; decimals: root.decimals } anchors { left: minus.right diff --git a/Desktop/components/JASP/Widgets/UIScaleNotifier.qml b/Desktop/components/JASP/Widgets/UIScaleNotifier.qml index c975126ed85..802ec970c1b 100644 --- a/Desktop/components/JASP/Widgets/UIScaleNotifier.qml +++ b/Desktop/components/JASP/Widgets/UIScaleNotifier.qml @@ -1,6 +1,6 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Widgets 1.0 +import QtQuick +import QtQuick.Controls +import JASP.Widgets Item { diff --git a/Desktop/data/datasetpackage.cpp b/Desktop/data/datasetpackage.cpp index 3231197b941..bbdd3bb3a81 100644 --- a/Desktop/data/datasetpackage.cpp +++ b/Desktop/data/datasetpackage.cpp @@ -26,7 +26,7 @@ #include "appdirs.h" #include "utils.h" #include "columnutils.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "datasetpackagesubnodemodel.h" #include "databaseconnectioninfo.h" #include "utilities/settings.h" diff --git a/Desktop/engine/enginerepresentation.cpp b/Desktop/engine/enginerepresentation.cpp index 9e29536dbe7..0c8153b01eb 100644 --- a/Desktop/engine/enginerepresentation.cpp +++ b/Desktop/engine/enginerepresentation.cpp @@ -1,6 +1,6 @@ #include "enginerepresentation.h" #include "gui/preferencesmodel.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "qutils.h" #include "utils.h" #include "log.h" diff --git a/Desktop/gui/preferencesmodel.cpp.in b/Desktop/gui/preferencesmodel.cpp.in index 8b934a142f6..6739419b9d5 100644 --- a/Desktop/gui/preferencesmodel.cpp.in +++ b/Desktop/gui/preferencesmodel.cpp.in @@ -1,7 +1,7 @@ #include "preferencesmodel.h" -#include "utilities/qutils.h" +#include "qutils.h" #include "utilities/settings.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "jasptheme.h" #include "utilities/languagemodel.h" #include diff --git a/Desktop/mainwindow.cpp b/Desktop/mainwindow.cpp index 34930bb95d1..870292b1974 100644 --- a/Desktop/mainwindow.cpp +++ b/Desktop/mainwindow.cpp @@ -39,32 +39,11 @@ #include "processinfo.h" #include "columnutils.h" #include "mainwindow.h" - -#include "analysisform.h" -#include "controls/jaspcontrol.h" -#include "controls/checkboxbase.h" -#include "controls/comboboxbase.h" -#include "controls/textinputbase.h" -#include "controls/componentslistbase.h" -#include "controls/factorsformbase.h" -#include "controls/inputlistbase.h" -#include "controls/textareabase.h" -#include "controls/sliderbase.h" -#include "controls/expanderbuttonbase.h" -#include "controls/variableslistbase.h" -#include "controls/variablesformbase.h" -#include "controls/factorlevellistbase.h" -#include "controls/tableviewbase.h" -#include "controls/radiobuttonbase.h" -#include "controls/radiobuttonsgroupbase.h" -#include "controls/jaspdoublevalidator.h" - - #include "gui/jaspversionchecker.h" #include "gui/preferencesmodel.h" -#include "ALTNavigation/altnavigation.h" -#include "ALTNavigation/altnavcontrol.h" -#include "utilities/messageforwarder.h" +//TODO: #include "ALTNavigation/altnavigation.h" +//#include "ALTNavigation/altnavcontrol.h" +#include "messageforwarder.h" #include "modules/activemodules.h" #include "modules/dynamicmodules.h" @@ -79,12 +58,11 @@ #include "qutils.h" #include "appdirs.h" #include "utilities/settings.h" -#include "utilities/qmlutils.h" +#include "qmlutils.h" #include "utilities/reporter.h" #include "widgets/filemenu/filemenu.h" -#include "rsyntax/formulabase.h" -#include "utilities/desktopcommunicator.h" +#include "desktopcommunicator.h" #include "boost/iostreams/stream.hpp" #include @@ -163,38 +141,13 @@ MainWindow::MainWindow(QApplication * application) : QObject(application), _appl makeConnections(); - qmlRegisterUncreatableType ("JASP", 1, 0 ,"JASP", "Impossible to create JASP Object" ); //This is here to keep JASP.enum short I guess? - qmlRegisterUncreatableType ("JASP", 1, 0, "MessageForwarder", "You can't touch this" ); - - qmlRegisterType ("JASP", 1, 0, "DataSetView" ); - qmlRegisterType ("JASP", 1, 0, "JaspTheme" ); - qmlRegisterType ("JASP", 1, 0, "AnalysisForm" ); - qmlRegisterType ("JASP", 1, 0, "RCommander" ); - qmlRegisterType ("JASP", 1, 0, "JASPControl" ); - qmlRegisterType ("JASP", 1, 0, "ExpanderButtonBase" ); - qmlRegisterType ("JASP", 1, 0, "CheckBoxBase" ); - qmlRegisterType ("JASP", 1, 0, "SliderBase" ); - qmlRegisterType ("JASP", 1, 0, "TextInputBase" ); - qmlRegisterType ("JASP", 1, 0, "TextAreaBase" ); - qmlRegisterType ("JASP", 1, 0, "ComboBoxBase" ); - qmlRegisterType ("JASP", 1, 0, "RadioButtonBase" ); - qmlRegisterType ("JASP", 1, 0, "RadioButtonsGroupBase" ); - qmlRegisterType ("JASP", 1, 0, "ComponentsListBase" ); - qmlRegisterType ("JASP", 1, 0, "FactorsFormBase" ); - qmlRegisterType ("JASP", 1, 0, "InputListBase" ); - qmlRegisterType ("JASP", 1, 0, "FactorLevelListBase" ); - qmlRegisterType ("JASP", 1, 0, "VariablesListBase" ); - qmlRegisterType ("JASP", 1, 0, "VariablesFormBase" ); - qmlRegisterType ("JASP", 1, 0, "TableViewBase" ); - qmlRegisterType ("JASP", 1, 0, "JASPDoubleValidator" ); - qmlRegisterType ("JASP", 1, 0, "ResultsJsInterface" ); - qmlRegisterType ("JASP", 1, 0, "ColumnModel" ); - qmlRegisterType ("JASP", 1, 0, "Formula" ); - qmlRegisterUncreatableType ("JASP.PlotEditor", 1, 0, "AxisModel", "Can't make it"); - qmlRegisterUncreatableType ("JASP.PlotEditor", 1, 0, "PlotEditorModel", "Can't make it"); - - ALTNavigation::registerQMLTypes("JASP"); - ALTNavControl::ctrl()->enableAlTNavigation(_preferences->ALTNavModeActive()); + qmlRegisterUncreatableType ("JASP", 1, 0, "MessageForwarder", "You can't touch this" ); + qmlRegisterType ("JASP", 1, 0, "DataSetView" ); + qmlRegisterType ("JASP", 1, 0, "JaspTheme" ); + qmlRegisterType ("JASP", 1, 0, "RCommander" ); + qmlRegisterType ("JASP", 1, 0, "ResultsJsInterface" ); + qmlRegisterUncreatableType ("JASP.PlotEditor", 1, 0, "AxisModel", "Can't make it"); + qmlRegisterUncreatableType ("JASP.PlotEditor", 1, 0, "PlotEditorModel", "Can't make it"); _dynamicModules->registerQMLTypes(); @@ -404,7 +357,6 @@ void MainWindow::makeConnections() connect(_engineSync, &EngineSync::checkDataSetForUpdates, _package, &DataSetPackage::checkDataSetForUpdates, Qt::QueuedConnection); qRegisterMetaType(); - qRegisterMetaType(); qRegisterMetaType(); connect(_computedColumnsModel, &ComputedColumnsModel::sendComputeCode, _engineSync, &EngineSync::computeColumn, Qt::QueuedConnection); @@ -481,7 +433,7 @@ void MainWindow::makeConnections() connect(_preferences, &PreferencesModel::normalizedNotationChanged, _resultsJsInterface, &ResultsJsInterface::setNormalizedNotationHandler ); connect(_preferences, &PreferencesModel::developerFolderChanged, _dynamicModules, &DynamicModules::uninstallJASPDeveloperModule ); connect(_preferences, &PreferencesModel::showRSyntaxInResultsChanged, _analyses, &Analyses::showRSyntaxInResults ); - connect(_preferences, &PreferencesModel::ALTNavModeActiveChanged, ALTNavControl::ctrl(), &ALTNavControl::enableAlTNavigation ); + // TODO: connect(_preferences, &PreferencesModel::ALTNavModeActiveChanged, ALTNavControl::ctrl(), &ALTNavControl::enableAlTNavigation ); auto * dCSingleton = DesktopCommunicator::singleton(); @@ -583,31 +535,6 @@ void MainWindow::loadQML() _qml->rootContext()->setContextProperty("computedColumnTypeConstructorCode", int(computedColumnType::constructorCode) ); _qml->rootContext()->setContextProperty("computedColumnTypeAnalysisNotComputed", int(computedColumnType::analysisNotComputed) ); - - bool debug = false, - isMac = false, - isLinux = false; - -#ifdef JASP_DEBUG - debug = true; -#endif - -#ifdef __APPLE__ - isMac = true; -#endif - -#ifdef __linux__ - isLinux = true; -#endif - - bool isWindows = !isMac && !isLinux; - - _qml->rootContext()->setContextProperty("DEBUG_MODE", debug); - _qml->rootContext()->setContextProperty("MACOS", isMac); - _qml->rootContext()->setContextProperty("LINUX", isLinux); - _qml->rootContext()->setContextProperty("WINDOWS", isWindows); - _qml->rootContext()->setContextProperty("INTERACTION_SEPARATOR", Term::separator); - _qml->setOutputWarningsToStandardError(true); setQmlImportPaths(); @@ -705,6 +632,7 @@ void MainWindow::setQmlImportPaths() QStringList newImportPaths = originalImportPaths; + newImportPaths.append(AppDirs::pluginsDir()); newImportPaths.append("qrc:///components"); newImportPaths.append(_dynamicModules->importPaths()); diff --git a/Desktop/mainwindow.h b/Desktop/mainwindow.h index 3001035c0d5..5f693ca73bf 100644 --- a/Desktop/mainwindow.h +++ b/Desktop/mainwindow.h @@ -25,7 +25,6 @@ #include #include "analysis/analyses.h" -#include "analysisform.h" #include "data/asyncloader.h" #include "data/asyncloaderthread.h" #include "data/columnsmodel.h" @@ -55,6 +54,7 @@ #include "utilities/codepageswindows.h" #include "widgets/filemenu/filemenu.h" #include "data/workspacemodel.h" +#include "messageforwarder.h" #include "utilities/languagemodel.h" #include diff --git a/Desktop/modules/dynamicmodule.cpp b/Desktop/modules/dynamicmodule.cpp index b91f34194dc..793f60a77e9 100644 --- a/Desktop/modules/dynamicmodule.cpp +++ b/Desktop/modules/dynamicmodule.cpp @@ -31,11 +31,11 @@ #include "upgrader/upgrades.h" #include "appdirs.h" #include "utilities/settings.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "utilities/languagemodel.h" #include "description/description.h" #include "utilities/extractarchive.h" -#include "utilities/qmlutils.h" +#include "qmlutils.h" #include "mainwindow.h" namespace Modules diff --git a/Desktop/modules/dynamicmodules.cpp b/Desktop/modules/dynamicmodules.cpp index 4224da11c6e..bb505201779 100644 --- a/Desktop/modules/dynamicmodules.cpp +++ b/Desktop/modules/dynamicmodules.cpp @@ -21,7 +21,7 @@ #include "dynamicmodules.h" #include "utilities/extractarchive.h" #include "utilities/settings.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "appdirs.h" #include "qutils.h" #include "log.h" diff --git a/Desktop/modules/ribbonmodel.cpp b/Desktop/modules/ribbonmodel.cpp index c0d58c92156..57ffa070d88 100644 --- a/Desktop/modules/ribbonmodel.cpp +++ b/Desktop/modules/ribbonmodel.cpp @@ -19,7 +19,7 @@ #include "ribbonmodel.h" #include "appdirs.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "log.h" #include "data/datasetpackage.h" #include "jasptheme.h" diff --git a/Desktop/modules/upgrader/upgrader.cpp b/Desktop/modules/upgrader/upgrader.cpp index 47a0e0c2b3d..ee0495170b6 100644 --- a/Desktop/modules/upgrader/upgrader.cpp +++ b/Desktop/modules/upgrader/upgrader.cpp @@ -3,7 +3,7 @@ #include "analysis/analysis.h" #include "../dynamicmodule.h" #include -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include namespace Modules diff --git a/Desktop/osf/onlinedatamanager.cpp b/Desktop/osf/onlinedatamanager.cpp index 9d2a585121d..292d7bacb77 100644 --- a/Desktop/osf/onlinedatamanager.cpp +++ b/Desktop/osf/onlinedatamanager.cpp @@ -25,7 +25,7 @@ #include "onlinedataconnection.h" #include "onlinedatanodeosf.h" #include "onlineusernodeosf.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "simplecrypt.h" #include "utilities/settings.h" #include "appinfo.h" diff --git a/Desktop/osf/onlineusernodeosf.cpp b/Desktop/osf/onlineusernodeosf.cpp index d2ce723c1da..8bd35a7729d 100644 --- a/Desktop/osf/onlineusernodeosf.cpp +++ b/Desktop/osf/onlineusernodeosf.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "widgets/filemenu/osf.h" diff --git a/Desktop/qquick/rcommander.cpp b/Desktop/qquick/rcommander.cpp index 14e6910db65..d1a142708d9 100644 --- a/Desktop/qquick/rcommander.cpp +++ b/Desktop/qquick/rcommander.cpp @@ -2,6 +2,7 @@ #include "engine/enginesync.h" #include "mainwindow.h" #include "modules/dynamicmodules.h" +#include "analysisformbase.h" RCommander * RCommander::_lastCommander = nullptr; @@ -96,7 +97,7 @@ bool RCommander::addAnalysis(const QString &code) { Analysis* analysis = Analyses::analyses()->createAnalysis(moduleName, analysisName); if (analysis) - analysis->sendRScript(code, AnalysisForm::rSyntaxControlName, false); + analysis->sendRScript(code, analysis->form()->rSyntaxControlName, false); else appendToOutput("> " + tr("Analysis not found")); } diff --git a/Desktop/results/ploteditoraxismodel.cpp b/Desktop/results/ploteditoraxismodel.cpp index 07c1cdf9126..0e4903bb946 100644 --- a/Desktop/results/ploteditoraxismodel.cpp +++ b/Desktop/results/ploteditoraxismodel.cpp @@ -3,7 +3,7 @@ #include "qutils.h" #include "jsonutilities.h" #include "log.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "utils.h" namespace PlotEditor diff --git a/Desktop/results/ploteditormodel.cpp b/Desktop/results/ploteditormodel.cpp index 20827ecd6b1..184af2370fe 100644 --- a/Desktop/results/ploteditormodel.cpp +++ b/Desktop/results/ploteditormodel.cpp @@ -5,7 +5,7 @@ #include "log.h" #include "tempfiles.h" #include -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" namespace PlotEditor { diff --git a/Desktop/results/resultsjsinterface.cpp b/Desktop/results/resultsjsinterface.cpp index 9e3001e207d..4b92654d562 100644 --- a/Desktop/results/resultsjsinterface.cpp +++ b/Desktop/results/resultsjsinterface.cpp @@ -33,7 +33,7 @@ #include "utilities/settings.h" #include #include -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include #include "gui/preferencesmodel.h" #include diff --git a/Desktop/utilities/reporter.cpp b/Desktop/utilities/reporter.cpp index 8ee28a1f1a7..c22305cea0e 100644 --- a/Desktop/utilities/reporter.cpp +++ b/Desktop/utilities/reporter.cpp @@ -2,7 +2,7 @@ #include "QtCore/qdiriterator.h" #include "results/resultsjsinterface.h" #include "data/datasetpackage.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "gui/preferencesmodel.h" #include "analysis/analyses.h" #include diff --git a/Desktop/widgets/filemenu/computer.cpp b/Desktop/widgets/filemenu/computer.cpp index d7f2f5b598f..216fcf4a7e8 100644 --- a/Desktop/widgets/filemenu/computer.cpp +++ b/Desktop/widgets/filemenu/computer.cpp @@ -18,7 +18,7 @@ #include "computer.h" #include -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "log.h" Computer::Computer(FileMenu *parent): FileMenuObject(parent) diff --git a/Desktop/widgets/filemenu/databasefilemenu.cpp b/Desktop/widgets/filemenu/databasefilemenu.cpp index eac615b9129..364b3a22e78 100644 --- a/Desktop/widgets/filemenu/databasefilemenu.cpp +++ b/Desktop/widgets/filemenu/databasefilemenu.cpp @@ -5,7 +5,7 @@ #include #include "log.h" #include "qutils.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "filemenu.h" const QStringList DatabaseFileMenu::dbTypes() diff --git a/Desktop/widgets/filemenu/filemenu.cpp b/Desktop/widgets/filemenu/filemenu.cpp index c56a35318b7..33b7a4c36e4 100644 --- a/Desktop/widgets/filemenu/filemenu.cpp +++ b/Desktop/widgets/filemenu/filemenu.cpp @@ -20,7 +20,7 @@ #include #include "utilities/settings.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "log.h" #include "data/datasetpackage.h" #include "mainwindow.h" diff --git a/Desktop/widgets/filemenu/osf.cpp b/Desktop/widgets/filemenu/osf.cpp index caf8d3a04db..2ccc260cc5c 100644 --- a/Desktop/widgets/filemenu/osf.cpp +++ b/Desktop/widgets/filemenu/osf.cpp @@ -24,7 +24,7 @@ #include "utilities/settings.h" #include "qutils.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include "osf/onlineusernodeosf.h" #include "filemenu.h" diff --git a/Desktop/widgets/filemenu/osf.h b/Desktop/widgets/filemenu/osf.h index 4bf42159519..5635a6fe621 100644 --- a/Desktop/widgets/filemenu/osf.h +++ b/Desktop/widgets/filemenu/osf.h @@ -22,7 +22,7 @@ #include "filemenuobject.h" #include "osflistmodel.h" #include "osfbreadcrumbslistmodel.h" -#include "models/sortmenumodel.h" +#include "sortmenumodel.h" #include #include diff --git a/Desktop/widgets/filemenu/osffilesystem.cpp b/Desktop/widgets/filemenu/osffilesystem.cpp index a03a8c61ffc..9fb28fe2ea3 100644 --- a/Desktop/widgets/filemenu/osffilesystem.cpp +++ b/Desktop/widgets/filemenu/osffilesystem.cpp @@ -37,7 +37,7 @@ #include "simplecrypt.h" #include "utilities/settings.h" #include "qutils.h" -#include "utilities/messageforwarder.h" +#include "messageforwarder.h" #include const QString OSFFileSystem::rootelementname = "Projects"; diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 467ce95989a..50bd7498a61 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -37,7 +37,7 @@ target_include_directories( JASPEngine PUBLIC ${PROJECT_SOURCE_DIR}/R-Interface ${PROJECT_SOURCE_DIR}/CommonData - ${PROJECT_SOURCE_DIR}/Common + ${PROJECT_SOURCE_DIR}/jaspCommonLib # Conan #$<$:${CONAN_INCLUDE_DIRS_JSONCPP}> # diff --git a/Modules/install-jaspBase.R.in b/Modules/install-jaspBase.R.in index ae167fa5a21..fb2ce3e2432 100644 --- a/Modules/install-jaspBase.R.in +++ b/Modules/install-jaspBase.R.in @@ -29,7 +29,7 @@ prompt <- FALSE if (md5SumsChanged(modulePkg, moduleLibrary)) { options( renv.cache.linkable = FALSE, - configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/Common'") + configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/jaspCommonLib'") ) Sys.setenv(JASP_R_INTERFACE_LIBRARY="Oh yes indeed") diff --git a/Modules/install-module.R.in b/Modules/install-module.R.in index 4ebd0a092c5..989e28e3ed5 100644 --- a/Modules/install-module.R.in +++ b/Modules/install-module.R.in @@ -29,7 +29,7 @@ if (@IS_FLATPAK_USED@) { .libPaths(c("@R_LIBRARY_PATH@")) options( - configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/Common'") #Needed for flatpak build as it keeps recompiling jaspBase (which it shouldnt of course but I dont know why) and this is an easy fix to get it to work now + configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/jaspCommonLib'") #Needed for flatpak build as it keeps recompiling jaspBase (which it shouldnt of course but I dont know why) and this is an easy fix to get it to work now ) if (jaspBase::getOS() == "osx") { diff --git a/Modules/jaspAcceptanceSampling b/Modules/jaspAcceptanceSampling index a694a6c1073..4f6a15b3e1a 160000 --- a/Modules/jaspAcceptanceSampling +++ b/Modules/jaspAcceptanceSampling @@ -1 +1 @@ -Subproject commit a694a6c1073a96031402610ca6099ff3a6a2609c +Subproject commit 4f6a15b3e1af9b4318fa9bac5bc3b9c552544e3e diff --git a/Modules/jaspAnova b/Modules/jaspAnova index dac094c009f..b78b6ef08ac 160000 --- a/Modules/jaspAnova +++ b/Modules/jaspAnova @@ -1 +1 @@ -Subproject commit dac094c009fd3345747997ab9400c1e373eeaa61 +Subproject commit b78b6ef08ac420f3500a42084f77983f411cced3 diff --git a/Modules/jaspAudit b/Modules/jaspAudit index 01dd96cfb70..074ad93f765 160000 --- a/Modules/jaspAudit +++ b/Modules/jaspAudit @@ -1 +1 @@ -Subproject commit 01dd96cfb7027a21f9adf01b41c308b823fb12f7 +Subproject commit 074ad93f765c2a312c59e9c6df09e990a5fe5265 diff --git a/Modules/jaspBain b/Modules/jaspBain index e839638a1bd..3f42e1da8fa 160000 --- a/Modules/jaspBain +++ b/Modules/jaspBain @@ -1 +1 @@ -Subproject commit e839638a1bd0e7024dbe8d3f51a8cdb6d4f2429c +Subproject commit 3f42e1da8faf6800d1b8550a9990eec799b23590 diff --git a/Modules/jaspBsts b/Modules/jaspBsts index d4b2ede4cf7..6d5cac9cfc8 160000 --- a/Modules/jaspBsts +++ b/Modules/jaspBsts @@ -1 +1 @@ -Subproject commit d4b2ede4cf7c046d3bbba365757d7fe11de1891e +Subproject commit 6d5cac9cfc8b2055e55af2fd20ae0290cea7392f diff --git a/Modules/jaspCircular b/Modules/jaspCircular index d0ae90d5906..5f317dc34ad 160000 --- a/Modules/jaspCircular +++ b/Modules/jaspCircular @@ -1 +1 @@ -Subproject commit d0ae90d5906a52ffa8d36e2242caa538a1e66b25 +Subproject commit 5f317dc34adef29177a5debbaa06d820b2aebceb diff --git a/Modules/jaspCochrane b/Modules/jaspCochrane index 94d4786dfc3..2aabd58c8ef 160000 --- a/Modules/jaspCochrane +++ b/Modules/jaspCochrane @@ -1 +1 @@ -Subproject commit 94d4786dfc3db789f7525c7c4dfb75682dcd9ca7 +Subproject commit 2aabd58c8ef57c7a165d99fbe6c9c8852a2c21bc diff --git a/Modules/jaspDescriptives b/Modules/jaspDescriptives index 876495415d8..bcda33851d3 160000 --- a/Modules/jaspDescriptives +++ b/Modules/jaspDescriptives @@ -1 +1 @@ -Subproject commit 876495415d86ea308d7b41129227ad2ad3498a23 +Subproject commit bcda33851d3c264fa51d5b5ec4459c34593dc315 diff --git a/Modules/jaspDistributions b/Modules/jaspDistributions index 85412275f72..f83e6558a79 160000 --- a/Modules/jaspDistributions +++ b/Modules/jaspDistributions @@ -1 +1 @@ -Subproject commit 85412275f72c2cbc18bac47555de20a3cc3f7991 +Subproject commit f83e6558a79d68eadf296046d898bb6935ac3f14 diff --git a/Modules/jaspEquivalenceTTests b/Modules/jaspEquivalenceTTests index 6fcd63967c8..6093513f480 160000 --- a/Modules/jaspEquivalenceTTests +++ b/Modules/jaspEquivalenceTTests @@ -1 +1 @@ -Subproject commit 6fcd63967c88953f6b966f91c34f0e5f2f9bae2c +Subproject commit 6093513f480311e2e62c895eb69af6f7973a9629 diff --git a/Modules/jaspFactor b/Modules/jaspFactor index 8c758921677..ead7d6be00f 160000 --- a/Modules/jaspFactor +++ b/Modules/jaspFactor @@ -1 +1 @@ -Subproject commit 8c758921677163a2d5f5fe8aa3604804d60635f8 +Subproject commit ead7d6be00f8f186e49cadf8084f237fcb136dca diff --git a/Modules/jaspFrequencies b/Modules/jaspFrequencies index fd5b928efbe..a0bf28188c9 160000 --- a/Modules/jaspFrequencies +++ b/Modules/jaspFrequencies @@ -1 +1 @@ -Subproject commit fd5b928efbeae98ecb0e31ef5ac98b7b6606059a +Subproject commit a0bf28188c9a82598f51c885ff54c8f612b60689 diff --git a/Modules/jaspJags b/Modules/jaspJags index 0b61a9e990f..9e390c11639 160000 --- a/Modules/jaspJags +++ b/Modules/jaspJags @@ -1 +1 @@ -Subproject commit 0b61a9e990f36535161953547433eb8769fa0c91 +Subproject commit 9e390c11639e46ea2737e4f6147e0eb32f2484bb diff --git a/Modules/jaspLearnBayes b/Modules/jaspLearnBayes index 54b712eddcc..16459172055 160000 --- a/Modules/jaspLearnBayes +++ b/Modules/jaspLearnBayes @@ -1 +1 @@ -Subproject commit 54b712eddcce0fad8c52279c46a176a4a1888055 +Subproject commit 16459172055596e3b36520c5a574d5272234e9e9 diff --git a/Modules/jaspLearnStats b/Modules/jaspLearnStats index 3fc0d30c99c..e9b0310066a 160000 --- a/Modules/jaspLearnStats +++ b/Modules/jaspLearnStats @@ -1 +1 @@ -Subproject commit 3fc0d30c99c775f4ce1bab078182d4b8ec9b9362 +Subproject commit e9b0310066a2fa6e21ddc3f86e9edc4bebb75323 diff --git a/Modules/jaspMachineLearning b/Modules/jaspMachineLearning index 30657d058b2..23f2ab53cb6 160000 --- a/Modules/jaspMachineLearning +++ b/Modules/jaspMachineLearning @@ -1 +1 @@ -Subproject commit 30657d058b2024321db301e5c082d2a06c61650a +Subproject commit 23f2ab53cb65c7d3641b231229e59640fa17255b diff --git a/Modules/jaspMetaAnalysis b/Modules/jaspMetaAnalysis index 2fb463780d2..57cac7b41f3 160000 --- a/Modules/jaspMetaAnalysis +++ b/Modules/jaspMetaAnalysis @@ -1 +1 @@ -Subproject commit 2fb463780d22fbdb44991d7426ff93b768d65ecf +Subproject commit 57cac7b41f3abf676bb59037494c6cd6a8aa9d4a diff --git a/Modules/jaspMixedModels b/Modules/jaspMixedModels index 8818ba9c356..0e391562dfc 160000 --- a/Modules/jaspMixedModels +++ b/Modules/jaspMixedModels @@ -1 +1 @@ -Subproject commit 8818ba9c356b9d191a0d7efdf1639e0d2c7628cb +Subproject commit 0e391562dfc3145cbdd82ffd467abc5b2f0d2560 diff --git a/Modules/jaspNetwork b/Modules/jaspNetwork index cb74183937e..6effce45ee6 160000 --- a/Modules/jaspNetwork +++ b/Modules/jaspNetwork @@ -1 +1 @@ -Subproject commit cb74183937e83202210d1e12d1f7d4abef27c03e +Subproject commit 6effce45ee6a4c12ca02165dc278f9237bdb1f9e diff --git a/Modules/jaspPower b/Modules/jaspPower index 8378dc88fbb..105688c7a9b 160000 --- a/Modules/jaspPower +++ b/Modules/jaspPower @@ -1 +1 @@ -Subproject commit 8378dc88fbbb6b739f223dfe91adab7c0f743353 +Subproject commit 105688c7a9b41258a144146aaf62ca8cce21f877 diff --git a/Modules/jaspPredictiveAnalytics b/Modules/jaspPredictiveAnalytics index bf06e10754a..dd0a41ecc15 160000 --- a/Modules/jaspPredictiveAnalytics +++ b/Modules/jaspPredictiveAnalytics @@ -1 +1 @@ -Subproject commit bf06e10754ac52c7d9cea705e8c488b38ec1cd3e +Subproject commit dd0a41ecc15abbb33ff1da752fd66c8c64e2e9a9 diff --git a/Modules/jaspProphet b/Modules/jaspProphet index a691a341f9a..443d77c0cd4 160000 --- a/Modules/jaspProphet +++ b/Modules/jaspProphet @@ -1 +1 @@ -Subproject commit a691a341f9a54cc2eba9b77e2d4b0e650cd65214 +Subproject commit 443d77c0cd4e7c3831ccfa3ac53faf638a8ef831 diff --git a/Modules/jaspQualityControl b/Modules/jaspQualityControl index 946f25a6d3b..fb9c1449f56 160000 --- a/Modules/jaspQualityControl +++ b/Modules/jaspQualityControl @@ -1 +1 @@ -Subproject commit 946f25a6d3b27a3797750fd8aac9f2d446ecad29 +Subproject commit fb9c1449f569aec69de58aa3d26d9580de74b17f diff --git a/Modules/jaspRegression b/Modules/jaspRegression index 2c61dc70aff..9dd49c72eec 160000 --- a/Modules/jaspRegression +++ b/Modules/jaspRegression @@ -1 +1 @@ -Subproject commit 2c61dc70affbde1d9ca3c4ecc318a3b21117a7aa +Subproject commit 9dd49c72eeca7ae7a382a40f92b653fd29fd8013 diff --git a/Modules/jaspReliability b/Modules/jaspReliability index 088bc1b1196..629f780726c 160000 --- a/Modules/jaspReliability +++ b/Modules/jaspReliability @@ -1 +1 @@ -Subproject commit 088bc1b1196ad677b101f17805733bdc3a9eb4c2 +Subproject commit 629f780726c377810c4e202b42bd046dd6c223e6 diff --git a/Modules/jaspSem b/Modules/jaspSem index bd965aeeb86..b6c9ed6637f 160000 --- a/Modules/jaspSem +++ b/Modules/jaspSem @@ -1 +1 @@ -Subproject commit bd965aeeb867865e748ead99195e8eb5098dcead +Subproject commit b6c9ed6637f3c1b46167e68f38bea635220bd1e9 diff --git a/Modules/jaspSummaryStatistics b/Modules/jaspSummaryStatistics index 6d432d18ecf..946ccdf1be1 160000 --- a/Modules/jaspSummaryStatistics +++ b/Modules/jaspSummaryStatistics @@ -1 +1 @@ -Subproject commit 6d432d18ecf087770631ec1232bd0bef450077b1 +Subproject commit 946ccdf1be1bf9b328717724e2053c7990b00942 diff --git a/Modules/jaspTTests b/Modules/jaspTTests index aed551c3958..ef730b533dd 160000 --- a/Modules/jaspTTests +++ b/Modules/jaspTTests @@ -1 +1 @@ -Subproject commit aed551c3958ae6244ce79c50dab47c316f256dcd +Subproject commit ef730b533dd716288b315057c4c4b020d20104b2 diff --git a/Modules/jaspTestModule b/Modules/jaspTestModule index 5f5a8ac8845..45d11bd3144 160000 --- a/Modules/jaspTestModule +++ b/Modules/jaspTestModule @@ -1 +1 @@ -Subproject commit 5f5a8ac884522dd76a7ad3fd3ff5377c713f63e5 +Subproject commit 45d11bd31441c3f9cba66e4d74e9aa6cd540a605 diff --git a/Modules/jaspTimeSeries b/Modules/jaspTimeSeries index 04aa678b53c..01143147131 160000 --- a/Modules/jaspTimeSeries +++ b/Modules/jaspTimeSeries @@ -1 +1 @@ -Subproject commit 04aa678b53c061aacb669711ab65347b7402089b +Subproject commit 01143147131e4f62ba34f41be018aedd3db39e94 diff --git a/Modules/jaspVisualModeling b/Modules/jaspVisualModeling index 172ce9f825e..050eaa2a9ac 160000 --- a/Modules/jaspVisualModeling +++ b/Modules/jaspVisualModeling @@ -1 +1 @@ -Subproject commit 172ce9f825efb17c49af6a314017c0cf7d78028f +Subproject commit 050eaa2a9ac3ad16f3552cf6698802e6a25c4400 diff --git a/QMLComponents/ALTNavigation/altnavcontrol.cpp b/QMLComponents/ALTNavigation/altnavcontrol.cpp deleted file mode 100644 index a1bca2af582..00000000000 --- a/QMLComponents/ALTNavigation/altnavcontrol.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "altnavcontrol.h" - - -ALTNavControl* ALTNavControl::_instance = nullptr; - -ALTNavControl* ALTNavControl::ctrl() -{ - if(!_instance) - _instance = new ALTNavControl(); - return _instance; -} - -ALTNavControl::ALTNavControl(QObject *parent) : QObject{parent} -{ - qApp->installEventFilter(this); - _currentRoot =_currentNode = _defaultRoot = new ALTNavScope(this); - _defaultRoot->setScopeOnly(true); - _defaultRoot->setRoot(true); - _attachedScopeMap.insert(nullptr, _defaultRoot); -} - -void ALTNavControl::enableAlTNavigation(bool state) -{ - if(!state) - setAltNavActive(false); - _altNavEnabled = state; -} - -ALTNavControl::~ALTNavControl() -{ - -} - -ALTNavScope* ALTNavControl::getAttachedScope(QObject *obj) -{ - auto it = _attachedScopeMap.find(obj); - if (it != _attachedScopeMap.end()) - return it.value(); - return nullptr; -} - -void ALTNavControl::registrate(ALTNavScope* scope, QObject *obj) -{ - _attachedScopeMap.insert(obj, scope); -} - -void ALTNavControl::unregister(QObject *obj) -{ - auto it = _attachedScopeMap.find(obj); - if (it != _attachedScopeMap.end()) - { - ALTNavScope* scope = it.value(); - if (scope == _currentRoot) - { - setCurrentRoot(_defaultRoot); - resetAltNavInput(); - } - if (scope == _currentNode) - { - setCurrentNode(_currentRoot); - setAltNavInput(_currentRoot->prefix()); - } - } - _attachedScopeMap.remove(obj); -} - -bool ALTNavControl::eventFilter(QObject *object, QEvent *event) -{ - static bool specialCharInput = false; - - if (event->type() == QEvent::KeyRelease) - { - QKeyEvent* keyEvent = static_cast(event); - int key = keyEvent->key(); - if (key == Qt::Key_Alt) - { - if(!specialCharInput && keyEvent->modifiers() == Qt::NoModifier) - { - resetAltNavInput(); - setAltNavActive(!_altNavActive); - } - else - specialCharInput = false; - return true; - - } - } - else if (event->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(event); - int key = keyEvent->key(); - if(_altNavActive) - { - if ((key >= Qt::Key_A && key <= Qt::Key_Z) || (key >= Qt::Key_0 && key <= Qt::Key_9)) - updateAltNavInput(keyEvent->text().toUpper()); - else if (key != Qt::Key_Alt) - { - resetAltNavInput(); - setAltNavActive(false); - } - return true; - } - else if ((key >= Qt::Key_A && key <= Qt::Key_Z) || (key >= Qt::Key_0 && key <= Qt::Key_9) & keyEvent->modifiers() == Qt::AltModifier) - specialCharInput = true; - } - return false; -} - -void ALTNavControl::resetAltNavInput() -{ - _currenAltNavInput = ""; - emit altNavInputChanged(); -} - -void ALTNavControl::setAltNavInput(QString input) -{ - _currenAltNavInput = input; - emit altNavInputChanged(); -} - - -void ALTNavControl::updateAltNavInput(QString entry) -{ - _currenAltNavInput += entry; - _currentNode->traverse(_currenAltNavInput); - emit altNavInputChanged(); -} - -void ALTNavControl::setAltNavActive(bool value) -{ - if(!_altNavEnabled || value == _altNavActive) return; - - _altNavActive = value; - emit altNavActiveChanged(); - - if(_altNavActive) - { - _dynamicTreeUpdate = true; - _currentRoot->setChildrenPrefix(); - for(ALTNavScope* node : qAsConst(_attachedScopeMap)) - { - if (node->foreground()) - { - setAltNavInput(node->prefix()); - setCurrentNode(node); - } - } - _currentNode->setChildrenActive(true); - } - else - { - _dynamicTreeUpdate = false; - _currentNode->setChildrenActive(false); - setCurrentNode(_currentRoot); - } -} - -bool ALTNavControl::AltNavActive() -{ - return _altNavActive; -} - -void ALTNavControl::setCurrentNode(ALTNavScope *scope) -{ - _currentNode->setChildrenActive(false); - scope->setChildrenActive(_altNavActive); - scope->setChildrenPrefix(); - _currentNode = scope; -} - -void ALTNavControl::setCurrentRoot(ALTNavScope *root) -{ - _currentRoot = root; -} - -ALTNavScope *ALTNavControl::getCurrentNode() -{ - return _currentNode; -} - -ALTNavScope *ALTNavControl::getCurrentRoot() -{ - return _currentRoot; -} - -ALTNavScope *ALTNavControl::getDefaultRoot() -{ - return _defaultRoot; -} - -QString ALTNavControl::getCurrentALTNavInput() -{ - return _currenAltNavInput; -} - -bool ALTNavControl::dynamicTreeUpdate() -{ - return _dynamicTreeUpdate; -} diff --git a/QMLComponents/ALTNavigation/altnavcontrol.h b/QMLComponents/ALTNavigation/altnavcontrol.h deleted file mode 100644 index 977dbf93dc2..00000000000 --- a/QMLComponents/ALTNavigation/altnavcontrol.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef ALTNAVROOT_H -#define ALTNAVROOT_H - -#include -#include "altnavscope.h" - -class ALTNavControl : public QObject -{ - Q_OBJECT -public: - explicit ALTNavControl(QObject *parent = nullptr); - ~ALTNavControl(); - - /*! - * \brief Returns ALTNavScope attached to attachee object - * \param obj attachee object - * \return Attached scope - */ - ALTNavScope* getAttachedScope(QObject* obj); - /*! - * \brief Registers connection between attachee and attached scope - * \param scope - * \param obj - */ - void registrate(ALTNavScope* scope, QObject* obj); - /*! - * \brief Undo registration - * \param obj attachee object - */ - void unregister(QObject* obj); - - /*! - * \brief This global event filter captures user input for the ALTNavigation subsystem. - * - * ALT keypress captured when mode is off. Turns mode on when captured. - * Captures 0-9 + A-Z + ALT + ESC when mode is on. Disables mode for ALT + ESC press or uncaptured keystrokes. - * - * \param object object for which the event is filtered - * \param event - * \return true when event is filtered out. false when the event is not handeled. - */ - bool eventFilter(QObject* object, QEvent* event); - - void resetAltNavInput(); - void setAltNavInput(QString input); - /*! - * \brief Appends the given entry to the current user input. - * \param entry - */ - void updateAltNavInput(QString entry); - QString getCurrentALTNavInput(); - - /*! - * \brief Returns whether trees should dynamically update upon child events - */ - bool dynamicTreeUpdate(); - - /*! - * \brief Turns the ALT navigation mode on or off. - * \param value - */ - void setAltNavActive(bool value); - /*! - * \brief Returns whether ALT navigation mode is on or off - * \return - */ - bool AltNavActive(); - - - void setCurrentNode(ALTNavScope* scope); - void setCurrentRoot(ALTNavScope* root); - ALTNavScope* getCurrentNode(); - ALTNavScope* getCurrentRoot(); - ALTNavScope* getDefaultRoot(); - - //singleton stuff - /*! - * \brief returns the ALTNavControl singleton - */ - static ALTNavControl* ctrl(); - ALTNavControl(ALTNavControl& other) = delete; - void operator=(const ALTNavControl&) = delete; - -public slots: - void enableAlTNavigation(bool state); - -signals: - void altNavInputChanged(); - void altNavActiveChanged(); - -private: - static ALTNavControl* _instance; - QHash _attachedScopeMap; - - ALTNavScope* _currentNode = nullptr; - ALTNavScope* _currentRoot = nullptr; - ALTNavScope* _defaultRoot = nullptr; - - bool _altNavEnabled = false; - bool _altNavActive = false; - bool _dynamicTreeUpdate = false; - QString _currenAltNavInput = ""; - -}; - -#endif // ALTNAVROOT_H diff --git a/QMLComponents/ALTNavigation/altnavigation.cpp b/QMLComponents/ALTNavigation/altnavigation.cpp deleted file mode 100644 index 1c725663a30..00000000000 --- a/QMLComponents/ALTNavigation/altnavigation.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "altnavigation.h" -#include "altnavcontrol.h" - -ALTNavScope* ALTNavigation::qmlAttachedProperties(QObject *object) -{ - ALTNavScope* scope = new ALTNavScope(object); - ALTNavControl::ctrl()->registrate(scope, object); - return scope; -} - -//Could parameterize module -void ALTNavigation::registerQMLTypes(QString uri) -{ - std::string u = uri.toStdString(); - qmlRegisterType (u.c_str(), 1, 0, "ALTNavigation" ); - qmlRegisterType (u.c_str(), 1, 0, "ALTNavTagBase" ); - qmlRegisterUncreatableType (u.c_str(), 1, 0, "AssignmentStrategy", "Can't make it" ); -} diff --git a/QMLComponents/ALTNavigation/altnavigation.h b/QMLComponents/ALTNavigation/altnavigation.h deleted file mode 100644 index cc980e6906e..00000000000 --- a/QMLComponents/ALTNavigation/altnavigation.h +++ /dev/null @@ -1,104 +0,0 @@ -/*! @file altnavigation.h - * @brief Defines the attaching type for the ALTNavigation attached property. - * - * The ALTNavigation subsystem implements an Attached Property which allows QQuickItems to register themselves. - * Upon registration they are assigned a textual tag shown when the ALT navigation mode is activated. - * The registered item may connect a handler to the attached onTagMatch signal to provide functionality/navigation. - * - * See https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html#providing-attached-properties for information on attached properties. - * This file provides the attaching type which creates the attached object type, ALTNavScope, to be attached to the attachee. - * ALTNavScope will create an ALTNavTag visual item. The lifetime of the ALTNavScope and visual ALTNavTag are tied to the attachee. - * - * ALTNavScopes will arrange themselves into Tree(s) by traversing upwards through the attachee ancestors - * until a registered parent is discovered. If none exist it is set as a child of the default root. - * This Process is facilitated by ALTNavControl. - * Tags are formed by combining parent prefixes with unique postfixes for all children. - * The postfixes are determined by the ALTNavPostfixAssignmentStrategy of the parent node. - * - * ALTNavScopes may generate a visual tag or they may be just parent scopes without visual representation to bundle other tags. - * e.g the items in a list share a scope-only parent node. - * - * ALTNavControl collects user input through which the ALTNavScope tree is traversed and the mode is (de)activated. - * It keeps track of the current node, current root, registered QQuickItems and their attached ALTNavScopes. - * The children of the the current node will be visible. - * - * ALTNavScopes may define a rule that defines them as being on the foreground. - * They will be set as the current node when true. - * - * ALTNavScopes may define themselves as a root. A forest of ALTNavscrope trees will result. - * Only one root can be the current root. This is determined by the foreground property of the root scopes. - * - * - * The following properties are provided through ALTNavigation: - * - * - enabled When set to false an ALTNavscope unparent itself until enabled is true once again - * - root Defines a scope as a root - * - parent Overrules the parent discovered by the normal tree forming parent search method. If set to null default root is set as parent. - * - scopeOnly Scope has no visual representation - * - showChildren Children of this scope will also be visible when this node is - * - strategy Define postfix allocation strategy - * - foreground This property may be set to true if the scope should be forcefully set to the current node (e.g. submenu is open) - * - requestedPostfix Defines a postfix preference that the current strategy may use - * - scopePriority Defines a priority for the preference that the strategy may use - * - index Defines a index that the current strategy may use to make ordered postfixes (e.g. items in a list) - * - x,y Defines the position of the visual tag relative to the attachee - * - * The following signals are provided: - * - tagMatch triggers when current user input matches the tag of a scope - * - * - * Examples of basic usage: - * SomeItem - * { - * ALTNavigation.enabled: true - * ALTNavigation.onTagMatch: { forceActiveFocus(); } - * } - * - * List - * { - * ALTNavigation.enabled: true - * ALTNavigation.scopeOnly: true - * ALTNavigation.strategy: AssignmentStrategy.INDEXED - * - * delegate: SomeItem - * { - * ALTNavigation.enabled: true - * ALTNavigation.index: index - * ALTNavigation.onTagMatch: { open(); } - * } - * } - * - * @author Rens Dofferhoff - */ - - -#ifndef ALTNAVIGATION_H -#define ALTNAVIGATION_H - -#include -#include - -#include "altnavscope.h" - -//! Attaching type ALTNavigation -class ALTNavigation : public QObject -{ - Q_OBJECT - QML_ATTACHED(ALTNavScope) - -public: - /*! - * \brief Creates and registers attached object type ALTNavScope for attachee - * \param object Attachee object - * \return Attaching ALNavScope - */ - static ALTNavScope* qmlAttachedProperties(QObject *object); - - /*! - * \brief registers the QML types related to this subsystem under JASP - */ - static void registerQMLTypes(QString uri); - -}; - -#endif // ALTNAVIGATION_H diff --git a/QMLComponents/ALTNavigation/altnavpostfixassignmentstrategy.cpp b/QMLComponents/ALTNavigation/altnavpostfixassignmentstrategy.cpp deleted file mode 100644 index b6c0fba8e43..00000000000 --- a/QMLComponents/ALTNavigation/altnavpostfixassignmentstrategy.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "altnavpostfixassignmentstrategy.h" -#include "altnavscope.h" -#include - -std::string capitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -ALTNavPostfixAssignmentStrategy* ALTNavPostfixAssignmentStrategy::createStrategy(AssignmentStrategy strategy) -{ - switch (strategy) { - case PRIORITIZED: - return new PriorityStrategy(); - case INDEXED: - return new IndexedStrategy(); - case PASS_THROUGH: - return new PassthroughStrategy(); - case UNKNOWN: - default: - return nullptr; - } -}; - -void PriorityStrategy::assignPostfixes(QList& children, QString prefix) -{ - - //handle postfix requests - //postfix request must be unique on first character and priority is taken into account - QList unassigned; - QSet assigned; - ALTNavScope* assignments[26] = { 0 }; - for (auto it = children.rbegin(); it != children.rend() ;it++) - { - ALTNavScope* scope = *it; - QString request = scope->getRequestedPostfix(); - if (request != "" && request[0].isLetter() && request[0].isUpper()) - { - ALTNavScope* current = assignments[request[0].toLatin1() - 'A']; - if(current) //check if already assigned if so compare priority - { - if(current->getScopePriority() >= scope->getScopePriority()) - { - unassigned.push_back(scope); - continue; - } - else - unassigned.push_back(current); - } - assignments[request[0].toLatin1() - 'A'] = scope; - assigned.insert(request[0].toLatin1()); - scope->setPrefix(prefix + scope->getRequestedPostfix()); - } - else - unassigned.push_back(scope); - } - - //assign the leftover postfixes - std::string preferredSacrifices = ""; - for (char option : capitalLetters) - { - if(unassigned.empty()) - return; - else if (assigned.contains(option)) - continue; - else - { - preferredSacrifices += option; - assigned.insert(option); - assignments[option - 'A'] = unassigned.last(); - unassigned.last()->setPrefix(prefix + option); - unassigned.pop_back(); - } - } - - - //We assigned 26 postfixes so now we need to get creative and we start assigning postfixes of lenght >= 2, like ZA,ZB...,ZZ - QString layerPrefix = ""; - QString nextLayerPrefix = ""; - //no spots left so we need a sacrifice. If no candidates is available we use Z. Who uses the letter Z anyways - if (assigned.size() == 26 && unassigned.size() > 0) //26 letters in alphabet - { - char sacrifice = preferredSacrifices.length() == 0 ? 'Z' : preferredSacrifices.back(); - assigned.remove(sacrifice); - unassigned.push_back(assignments[sacrifice - 'A']); - nextLayerPrefix = layerPrefix += sacrifice; - } - - - //assign the rest, move to next layer if more than 26 left to assign - while (unassigned.size()) - { - bool nextLayer = unassigned.size() > 26; - for (char option : capitalLetters) - { - if (unassigned.empty()) - return; - else if (nextLayer) - { - nextLayerPrefix += option; - nextLayer = false; - } - else - { - unassigned.last()->setPrefix(prefix + layerPrefix + option); - unassigned.pop_back(); - } - } - layerPrefix = nextLayerPrefix; - } -} - -void IndexedStrategy::assignPostfixes(QList& children, QString prefix) -{ - int maxLeadingZeros = std::log10((double)children.size()); //if needed I can write a fast integer version that never fails but I doubt it will really matter for reasonable input sizes - for (ALTNavScope* scope : children) - { - int n = scope->getIndex() + 1; //get rid of 0 index - int numLeadingZeros = maxLeadingZeros - (int)std::log10((double)n); - QString tag = QString("0").repeated(numLeadingZeros) + QString::number(n); - scope->setPrefix(prefix + tag); - } -} - -void PassthroughStrategy::assignPostfixes(QList& children, QString prefix) -{ - assert(children.length() <= 1); - for (ALTNavScope* scope : children) - { - scope->setPrefix(prefix); - } -} diff --git a/QMLComponents/ALTNavigation/altnavpostfixassignmentstrategy.h b/QMLComponents/ALTNavigation/altnavpostfixassignmentstrategy.h deleted file mode 100644 index cc36b2c4918..00000000000 --- a/QMLComponents/ALTNavigation/altnavpostfixassignmentstrategy.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef ALTNAVPOSTFIXASSIGNMENTSTRATEGY_H -#define ALTNAVPOSTFIXASSIGNMENTSTRATEGY_H - -#include - -class ALTNavScope; - -/*! - * \brief The ALTNavPostfixAssignmentStrategy class defines the interface which concrete strategies must define - */ -class ALTNavPostfixAssignmentStrategy : public QObject -{ - Q_OBJECT - -public: - virtual ~ALTNavPostfixAssignmentStrategy() {}; - - /*! - * \brief Compute postfixes and set resulting prefixes for children - * \param children - * \param prefix parent prefix - */ - virtual void assignPostfixes(QList& children, QString prefix) = 0; - - /*! - * \brief The AssignmentStrategy enum defines all strategies - */ - enum AssignmentStrategy { PASS_THROUGH, INDEXED, PRIORITIZED, UNKNOWN }; - Q_ENUM(AssignmentStrategy) - - - /*! - * \brief Factory method that creates the desired strategy type - * \param strategy - * \return Specified strategy type - */ - static ALTNavPostfixAssignmentStrategy* createStrategy(AssignmentStrategy strategy); - - - -}; - -/*! - * \brief The PriorityStrategy class assigns postfixes A-Z while taking request and priorities into account - * If the number of children is larger than 26 it finds a suitable sacrifice X and assigns postfixes X(A-Z) - */ -class PriorityStrategy : public ALTNavPostfixAssignmentStrategy -{ -public: - PriorityStrategy(){}; - ~PriorityStrategy(){}; - void assignPostfixes(QList& children, QString prefix); - -}; - -/*! - * \brief The IndexedStrategy class assigns prefixes 1-9 dependend on child index properties - * If the number of children > 9 it will assign prefixes 0(1-9) + 10-99. - */ -class IndexedStrategy : public ALTNavPostfixAssignmentStrategy -{ -public: - IndexedStrategy(){}; - ~IndexedStrategy(){}; - void assignPostfixes(QList& children, QString prefix); -}; - -/*! - * \brief The PassthroughStrategy class copies the parent prefix. Only use with one child. - */ -class PassthroughStrategy : public ALTNavPostfixAssignmentStrategy -{ -public: - PassthroughStrategy(){}; - ~PassthroughStrategy(){}; - void assignPostfixes(QList& children, QString prefix); -}; - -#endif // ALTNAVPOSTFIXASSIGNMENTSTRATEGY_H diff --git a/QMLComponents/ALTNavigation/altnavscope.cpp b/QMLComponents/ALTNavigation/altnavscope.cpp deleted file mode 100644 index baa3303ae29..00000000000 --- a/QMLComponents/ALTNavigation/altnavscope.cpp +++ /dev/null @@ -1,327 +0,0 @@ -#include "altnavscope.h" -#include "altnavpostfixassignmentstrategy.h" -#include "altnavcontrol.h" - -#include -#include - -ALTNavScope::ALTNavScope(QObject* attachee) - : QObject{attachee} -{ - _postfixBroker = ALTNavPostfixAssignmentStrategy::createStrategy(_currentStrategy); - if(attachee) - { - _attachee = qobject_cast(attachee); - if(_attachee) //is a visual item - { - //create a visual tag - QQmlComponent component(qmlEngine(_attachee), QUrl("qrc:///components/JASP/Widgets/ALTNavTag.qml"), _attachee); - _attachedTag = qobject_cast(component.create()); - _attachedTag->setParentItem(_attachee); - _attachedTag->setParent(_attachee); - - //Find parent when attachee parent changes or component is completed (this is when registration of any parent is guaranteed) - QObject* attached_component = qmlAttachedPropertiesObject(_attachee); - connect(attached_component, SIGNAL(completed()), this, SLOT(init())); - connect(_attachee, &QQuickItem::parentChanged, this, &ALTNavScope::registerWithParent); - } - } -} - -ALTNavScope::~ALTNavScope() -{ - setParentScope(nullptr); - for (ALTNavScope* child : _childScopes) - child->setParentScope(nullptr); - ALTNavControl::ctrl()->unregister(_attachee); - delete _postfixBroker; -} - -void ALTNavScope::registerWithParent() -{ - if (_root) - return; - - ALTNavControl* ctrl = ALTNavControl::ctrl(); - ALTNavScope* newParentScope = nullptr; - - if(_parentOverride) - newParentScope = ctrl->getAttachedScope(_parentScopeAttachee); - - //no parent scope was set explicitly so lets find one - if(_attachee && !newParentScope) - { - QQuickItem* curr = _attachee->parentItem(); - while (curr) - { - ALTNavScope* scope = ctrl->getAttachedScope(curr); - if(scope) //found a different valid valid scope - { - newParentScope = scope; - break; - } - curr = curr->parentItem(); - } - } - - //no ancestors were registered so set default root - if(!newParentScope) - { - newParentScope = ctrl->getDefaultRoot(); - } - - if(newParentScope != _parentScope) - setParentScope(newParentScope); -} - -void ALTNavScope::addChild(ALTNavScope *child) -{ - _childScopes.push_back(child); - ALTNavControl* ctrl = ALTNavControl::ctrl(); - if(ctrl->dynamicTreeUpdate()) - { - ctrl->getCurrentNode()->setChildrenActive(ctrl->AltNavActive()); - setChildrenPrefix(); - } -} - -void ALTNavScope::removeChild(ALTNavScope *child) -{ - _childScopes.removeOne(child); - ALTNavControl* ctrl = ALTNavControl::ctrl(); - if(ctrl->dynamicTreeUpdate()) - { - ctrl->getCurrentNode()->setChildrenActive(ctrl->AltNavActive()); - setChildrenPrefix(); - } -} - -void ALTNavScope::setParentScope(ALTNavScope *parent) -{ - if (_parentScope) - _parentScope->removeChild(this); - _parentScope = parent; - if(_parentScope) - _parentScope->addChild(this); - else - { - setScopeActive(false); - setChildrenActive(false); - } -} - -void ALTNavScope::init() -{ - registerWithParent(); - _initialized = true; -} - - -void ALTNavScope::traverse(QString input) -{ - ALTNavControl* ctrl = ALTNavControl::ctrl(); - - bool matchPossible = false; - for(ALTNavScope* scope : qAsConst(_childScopes)) - { - //total match, progress in tree - if(scope->_prefix == input) - { - ctrl->setCurrentNode(scope); - scope->match(); - scope->traverse(input); - return; - } - //partial match - bool partialMatch = input.length() < scope->_prefix.length() && scope->_prefix.first(input.length()) == input; - if (!partialMatch) - scope->setScopeActive(false); - matchPossible |= partialMatch; - } - - //end of the road so we disable the altnavigation mode and return to root - if(!matchPossible) - { - ctrl->setCurrentNode(ctrl->getCurrentRoot()); - ctrl->setAltNavActive(false); - } - -} - -void ALTNavScope::match() -{ - emit tagMatch(); -} - - -void ALTNavScope::setPrefix(QString prefix) -{ - _prefix = prefix; - if (_attachedTag) - _attachedTag->setFullTag(_prefix); - setChildrenPrefix(); -} - -void ALTNavScope::setChildrenPrefix() -{ - if(_postfixBroker) - _postfixBroker->assignPostfixes(_childScopes, _prefix); -} - -void ALTNavScope::setScopeActive(bool value) -{ - _scopeActive = value; - if (!_scopeOnly) - _attachedTag->setActive(value); - if (_propagateActivity) - setChildrenActive(value); -} - -void ALTNavScope::setChildrenActive(bool value) -{ - for(ALTNavScope* child : _childScopes) - { - child->setScopeActive(value); - } -} - -void ALTNavScope::setForeground(bool onForeground) -{ - if(onForeground == _foreground) - return; - - ALTNavControl* ctrl = ALTNavControl::ctrl(); - _foreground = onForeground; - if (onForeground) // set ourselfs as the currentNode - { - if (_root) - ctrl->setCurrentRoot(this); - ctrl->setCurrentNode(this); - ctrl->setAltNavInput(_prefix); - } - else - { - if (_root && ctrl->getCurrentRoot() == this) //we are the current root but we lost foreground so unset ourselfs - { - ctrl->setCurrentRoot(ctrl->getDefaultRoot()); - ctrl->resetAltNavInput(); - } - if (ctrl->getCurrentNode() == this) //we are the currentNode but lost foreground reset to root - { - ctrl->setCurrentNode(ctrl->getCurrentRoot()); - ctrl->setAltNavInput(ctrl->getCurrentRoot()->prefix()); - } - } - emit foregroundChanged(); -} - -void ALTNavScope::setRoot(bool value) -{ - _root = value; - if (_root) - { - setParentScope(nullptr); - setPrefix(""); - } - - emit rootChanged(); -} - -void ALTNavScope::setX(qreal x) -{ - _x = x; - _attachedTag->setX(_x); -} - -void ALTNavScope::setY(qreal y) -{ - _y = y; - _attachedTag->setY(_y); -} - -QString ALTNavScope::getRequestedPostfix() -{ - return _requestedPostfix; -} - -int ALTNavScope::getScopePriority() -{ - return _scopePriority; -} - -int ALTNavScope::getIndex() -{ - return _index; -} - -bool ALTNavScope::foreground() -{ - return _foreground; -} - -QString ALTNavScope::prefix() -{ - return _prefix; -} - -void ALTNavScope::setScopeOnly(bool value) -{ - _scopeOnly = value; - _propagateActivity = true; - emit scopeOnlyChanged(); -} - -void ALTNavScope::setEnabled(bool value) -{ - if(value == _enabled) - return; - - _enabled = value; - if(!_enabled) - { - setParentScope(nullptr); - } - else if(_initialized) //back in business - { - registerWithParent(); - } - - emit enabledChanged(); -} - -void ALTNavScope::setParentAttachee(QObject* parent) -{ - _parentScopeAttachee = qobject_cast(parent); - _parentOverride = true; -} - -void ALTNavScope::setRequestedPostfix(QString postfix) -{ - _requestedPostfix = postfix; -} - -void ALTNavScope::setScopePriority(int priority) -{ - _scopePriority = priority; -} - -void ALTNavScope::setIndex(int index) -{ - _index = index; - //indices changed recalc prefixes - if (_parentScope) - _parentScope->setChildrenPrefix(); -} - -void ALTNavScope::setStrategy(AssignmentStrategy strategy) -{ - setStrategy(ALTNavPostfixAssignmentStrategy::createStrategy(strategy)); - emit postfixAssignmentStrategyChanged(); -} - - -void ALTNavScope::setStrategy(ALTNavPostfixAssignmentStrategy* strategy) -{ - delete _postfixBroker; - _postfixBroker = strategy; -} diff --git a/QMLComponents/ALTNavigation/altnavscope.h b/QMLComponents/ALTNavigation/altnavscope.h deleted file mode 100644 index 24e6f44a9ff..00000000000 --- a/QMLComponents/ALTNavigation/altnavscope.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef ALTNAVSCOPE_H -#define ALTNAVSCOPE_H - -#include -#include - -#include "altnavtag.h" -#include "altnavpostfixassignmentstrategy.h" - -using AssignmentStrategy = ALTNavPostfixAssignmentStrategy::AssignmentStrategy; - -/*! \brief Attaching object type providing the properties and signals along with most of the tree construction and traversal logic. - * - */ -class ALTNavScope : public QObject -{ - Q_OBJECT - - //ALTNavigation Interface - //! When set to false an ALTNavscope unparent itself until enabled is true once again - Q_PROPERTY( bool enabled MEMBER _enabled WRITE setEnabled NOTIFY enabledChanged ); - //! Defines a scope as a root - Q_PROPERTY( bool root MEMBER _root WRITE setRoot NOTIFY rootChanged ); - //! Overrules the parent discovered by the normal tree forming parent search method. If null the default root is set as parent - Q_PROPERTY( QObject* parent MEMBER _parentScopeAttachee WRITE setParentAttachee NOTIFY parentScopeChanged ); - //! Set if their should be no visual representation - Q_PROPERTY( bool scopeOnly MEMBER _scopeOnly WRITE setScopeOnly NOTIFY scopeOnlyChanged ); - //! Children of this scope will also be visible when this node is. - Q_PROPERTY( bool showChildren MEMBER _propagateActivity ); - //! Define postfix allocation strategy - Q_PROPERTY( AssignmentStrategy strategy MEMBER _currentStrategy WRITE setStrategy NOTIFY postfixAssignmentStrategyChanged ); - //! Defines the x position of the visual tag relative to the attachee - Q_PROPERTY( int x MEMBER _x WRITE setX ); - //! Defines the y position of the visual tag relative to the attachee - Q_PROPERTY( int y MEMBER _y WRITE setY ); - //! This property may be set to true if the scope should be forcefully set to the current node (e.g. submenu is open) - Q_PROPERTY( bool foreground READ foreground WRITE setForeground NOTIFY foregroundChanged ); - //! Defines a postfix preference that the current strategy may use - Q_PROPERTY( QString requestedPostfix READ getRequestedPostfix WRITE setRequestedPostfix NOTIFY requestedPostfixChanged ); - //! Defines a priority for the prefix preference that the strategy may use - Q_PROPERTY( int scopePriority READ getScopePriority WRITE setScopePriority NOTIFY scopePriorityChanged ); - //! Defines a index that the current strategy may use to make ordered postfixes (e.g. items in a list) - Q_PROPERTY( int index READ getIndex WRITE setIndex NOTIFY indexChanged ); - - -signals: - //! Signal is emitted upon tag match - void tagMatch(); - void enabledChanged(); - void postfixAssignmentStrategyChanged(); - void scopeOnlyChanged(); - void requestedPostfixChanged(); - void scopePriorityChanged(); - void indexChanged(); - void parentScopeChanged(); - void foregroundChanged(); - void rootChanged(); - -public: - explicit ALTNavScope(QObject* attachee); - ~ALTNavScope(); - - /*! - * \brief Traverses scope tree by current input. Disables mode once no match on future input is possible. - * \param input - */ - void traverse(QString input); - /*! - * \brief Sets scope prefix and recomputes postfixes for children. Updates ALTNavTag - * \param prefix - */ - void setPrefix(QString prefix); - /*! - * \brief Sets scope activity. Propagates state to ALTNavTag and to children if scope or showchildren are true - * \param value - */ - void setScopeActive(bool value); - /*! - * \brief Recomputes postfixes and sets prefixes for children - * \param prefix - */ - void setChildrenPrefix(); - /*! - * \brief Sets child scope activities. - * \param value - */ - void setChildrenActive(bool value); - void match(); - - QString getRequestedPostfix(); - int getScopePriority(); - int getIndex(); - bool foreground(); - QString prefix(); - - - void setEnabled(bool value); - void setStrategy(ALTNavPostfixAssignmentStrategy* strategy); - void setStrategy(AssignmentStrategy strategy); - void setRoot(bool value); - void setScopeOnly(bool value); - - -protected: - void setParentAttachee(QObject* parent); - void setRequestedPostfix(QString postfix); - void setScopePriority(int priority); - void setIndex(int index); - void setForeground(bool onForeground); - void setX(qreal x); - void setY(qreal y); - - -private slots: - void init(); - - /*! - * \brief Attempts to find a valid parent in the attachee ancestor chain. - * Registers with default root otherwise. May be overruled by setting parent property - */ - void registerWithParent(); - - void addChild(ALTNavScope* child); - void removeChild(ALTNavScope* child); - void setParentScope(ALTNavScope* parent); - - -protected: - bool _scopeActive = false; - QString _prefix = ""; - -private: - //ALTNavigation Interface - bool _enabled = false; - bool _root = false; - bool _foreground = false; - bool _scopeOnly = false; - bool _propagateActivity = false; - QString _requestedPostfix = ""; - int _index = -1; - int _scopePriority = 0; - AssignmentStrategy _currentStrategy = AssignmentStrategy::PRIORITIZED; - qreal _x, _y; - - QQuickItem* _attachee; - ALTNavTagBase* _attachedTag = nullptr; - QQuickItem* _parentScopeAttachee = nullptr; - bool _parentOverride = false; - bool _initialized = false; - - QList _childScopes; - ALTNavScope* _parentScope = nullptr; - - - ALTNavPostfixAssignmentStrategy* _postfixBroker = nullptr; - - friend class ALTNavPostfixAssignmentStrategy; - -}; - -#endif // ALTNAVSCOPE_H diff --git a/QMLComponents/ALTNavigation/altnavtag.cpp b/QMLComponents/ALTNavigation/altnavtag.cpp deleted file mode 100644 index 81cb2a62be9..00000000000 --- a/QMLComponents/ALTNavigation/altnavtag.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "altnavtag.h" -#include "altnavcontrol.h" - -#include -#include -#include - - -ALTNavTagBase::ALTNavTagBase(QQuickItem* parent) : QQuickItem{parent} -{ - //connect to control to get input updates so we may update tag accordingly - connect(ALTNavControl::ctrl(), &ALTNavControl::altNavInputChanged, this, &ALTNavTagBase::updateTagText); - setActiveFocusOnTab(false); -} - -ALTNavTagBase::~ALTNavTagBase() -{ - -} - -void ALTNavTagBase::setFullTag(QString fullTag) -{ - _fullTag = fullTag; - updateTagText(); -} - - -void ALTNavTagBase::updateTagText() -{ - int len = _fullTag.length() - ALTNavControl::ctrl()->getCurrentALTNavInput().length(); - if (len >= 0) - { - _tagText = _fullTag.last(len); - emit tagTextChanged(); - } -} - -void ALTNavTagBase::setActive(bool active) -{ - _active = active; - emit activeChanged(); -} diff --git a/QMLComponents/ALTNavigation/altnavtag.h b/QMLComponents/ALTNavigation/altnavtag.h deleted file mode 100644 index a455f14db48..00000000000 --- a/QMLComponents/ALTNavigation/altnavtag.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef ALTNAVTAG_H -#define ALTNAVTAG_H - -#include -#include - -class ALTNavScope; - -/*! - * \brief Base class for the visual ALTNavTag element. - * - * Connects to ALTNavControl to get updates on input to form visual tag using the unique fulltag and current user input. - */ -class ALTNavTagBase : public QQuickItem -{ - Q_OBJECT - - Q_PROPERTY( QString tagText READ getTagText NOTIFY tagTextChanged ); - Q_PROPERTY( bool active READ getActive NOTIFY activeChanged ); - -public: - ALTNavTagBase(QQuickItem* parent = nullptr); - ~ALTNavTagBase(); - - void setFullTag(QString fullTag); - void setActive(bool active); - -private slots: - void updateTagText(); - -signals: - void tagTextChanged(); - void activeChanged(); - -private: - bool getActive() { return _active; }; - QString getTagText() { return _tagText; }; - -private: - QString _tagText = ""; - bool _active = false; - QString _fullTag; - - -}; - -#endif // ALTNAVTAG_H diff --git a/QMLComponents/CMakeLists.txt b/QMLComponents/CMakeLists.txt deleted file mode 100644 index 8c800f054eb..00000000000 --- a/QMLComponents/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -# This will build the QMLComponents library - -list(APPEND CMAKE_MESSAGE_CONTEXT QMLComponents) - -file(GLOB_RECURSE HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/*.h") -file(GLOB_RECURSE SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/*.cpp") - -add_library(QMLComponents ${SOURCE_FILES} ${HEADER_FILES}) - -if(LINUX) - target_link_libraries(QMLComponents PUBLIC ${_LIB_RT}) - target_link_options(QMLComponents PUBLIC -lrt) -endif() - -target_include_directories( - QMLComponents - PUBLIC # JASP - ${PROJECT_SOURCE_DIR}/Common - ${PROJECT_SOURCE_DIR}/Common/QtUtils -) - -target_link_libraries( - QMLComponents - PUBLIC - CommonWithQt - Qt::Core - Qt::Gui - Qt::Widgets - Qt::Qml - Qt::Quick - Qt::QuickLayouts - Qt::QuickControls2 - Qt::QuickControls2Impl - Qt::QuickWidgets - Qt::QuickTemplates2 - $<$>:Qt::Core5Compat> - $<$:/app/lib/$ENV{FLATPAK_ARCH}-linux-gnu/libQt6Core5Compat.so> -) - -file(GLOB_RECURSE QML_RESOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/components/*") - -qt_add_resources( - QMLComponents - "qmlComponents" - PREFIX - "/" - BASE - ${CMAKE_CURRENT_LIST_DIR} - FILES - ${QML_RESOURCE_FILES}) - -list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/QMLComponents/analysisbase.cpp b/QMLComponents/analysisbase.cpp deleted file mode 100644 index 42d7454a3ce..00000000000 --- a/QMLComponents/analysisbase.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "analysisbase.h" -#include "analysisform.h" -#include "log.h" -#include "utilities/qmlutils.h" - -const std::string AnalysisBase::emptyString; -const stringvec AnalysisBase::emptyStringVec; - -AnalysisBase::AnalysisBase(QObject* parent, Version moduleVersion) - : QObject(parent) - , _moduleVersion(moduleVersion) -{ -} - -AnalysisBase::AnalysisBase(QObject* parent, AnalysisBase* duplicateMe) - : QObject(parent) - , _moduleVersion(duplicateMe->moduleVersion()) - , _boundValues(duplicateMe->boundValues()) -{ -} - -QQuickItem* AnalysisBase::formItem() const -{ - return _analysisForm; -} - -void AnalysisBase::destroyForm() -{ - Log::log() << "Analysis(" << this << ")::destroyForm() called" << std::endl; - - if(_analysisForm) - { - Log::log(false) << " it has a AnalysisForm " << _analysisForm << " so let's destroy it" << std::endl; - - _analysisForm->setParent( nullptr); - _analysisForm->setParentItem( nullptr); - - delete _analysisForm; - _analysisForm = nullptr; - - emit formItemChanged(); - } - else - Log::log(false) << " it has no AnalysisForm." << std::endl; -} - -void AnalysisBase::createForm(QQuickItem* parentItem) -{ - Log::log() << "Analysis(" << this << ")::createForm() called with parentItem " << parentItem << std::endl; - - setQmlError(""); - - if(parentItem) - _parentItem = parentItem; - - if(_analysisForm) - { - Log::log() << "It already has a form, so we destroy it." << std::endl; - - if (!parentItem) - parentItem = _analysisForm->parentItem(); - - destroyForm(); - } - else if(!parentItem) - parentItem = _parentItem; - - try - { - Log::log() << std::endl << "Loading QML form from: " << qmlFormPath(false, false) << std::endl; - - QObject * newForm = instantiateQml(QUrl::fromLocalFile(tq(qmlFormPath(false, false))), module(), qmlContext(parentItem)); - - Log::log() << "Created a form, got pointer " << newForm << std::endl; - - _analysisForm = qobject_cast(newForm); - - if(!_analysisForm) - throw std::logic_error("QML file '" + qmlFormPath(false, false) + "' didn't spawn into AnalysisForm, but into: " + (newForm ? fq(newForm->objectName()) : "null")); - - _analysisForm->setAnalysis(this); - _analysisForm->setParent(this); - _analysisForm->setParentItem(parentItem); - - emit formItemChanged(); - } - catch(qmlLoadError & e) - { - setQmlError(e.what()); - _analysisForm = nullptr; - } - catch(std::exception & e) - { - setQmlError(e.what()); - _analysisForm = nullptr; - } -} - -std::string AnalysisBase::qmlFormPath(bool, bool) const -{ - return module() + "/qml/" + name(); -} - -const QString &AnalysisBase::qmlError() const -{ - return _qmlError; -} - -void AnalysisBase::setQmlError(const QString &newQmlError) -{ - if (_qmlError == newQmlError) - return; - _qmlError = newQmlError; - emit qmlErrorChanged(); -} - -// This method tries to find the parent keys in _boundValues Json object -// If found, it sets the path to this reference to parentNames and returns a reference of the sub Json object -Json::Value& AnalysisBase::_getParentBoundValue(const QVector& parentKeys, QVector& parentNames, bool& found, bool createAnyway) -{ - found = (parentKeys.size() == 0); - Json::Value* parentBoundValue = &_boundValues; - - // A parentKey has 3 properties: , and : it assumes that the json boundValue is an abject, one of its member is , - // whom value is an array of json objects. These objects have a member , and one of them has for value . - // if there are several parentKeys, it repeats this operation - // - // { - // anOptionName : "one" - // ... - // : [ - // { - // : "anothervalue" - // anotherKey: "xxx" - // }, - // { - // : "" - // anotherKey: "yyy" // parentBoundValue gets a reference to this Json object - // } - // ] - // } - - for (const auto& parent : parentKeys) - { - found = false; - if (createAnyway && !parentBoundValue->isMember(parent.name)) (*parentBoundValue)[parent.name] = Json::Value(Json::arrayValue); - - if (parentBoundValue->isMember(parent.name)) - { - Json::Value& parentBoundValues = (*parentBoundValue)[parent.name]; - if (!parentBoundValues.isNull() && parentBoundValues.isArray()) - { - for (Json::Value & boundValue : parentBoundValues) - { - if (boundValue.isMember(parent.key)) - { - Json::Value &val = boundValue[parent.key]; - // The value can be a string or an array of strings (for interaction terms) - if (val.isString() && parent.value.size() == 1) - { - if (val.asString() == parent.value[0]) found = true; - } - else if (val.isArray() && val.size() == parent.value.size()) - { - found = true; - size_t i = 0; - for (const Json::Value& compVal : val) - { - if (!compVal.isString() || compVal.asString() != parent.value[i]) found = false; - i++; - } - } - if (found) - { - parentBoundValue = &boundValue; - parentNames.append(parent.name); - break; - } - } - } - - if (!found && createAnyway) - { - Json::Value row(Json::objectValue); - if (parent.value.size() == 1) - row[parent.key] = parent.value[0]; - else - { - Json::Value newValue(Json::arrayValue); - for (size_t i = 0; i < parent.value.size(); i++) - newValue.append(parent.value[i]); - row[parent.key] = newValue; - } - parentBoundValues.append(row); - parentBoundValue = &(parentBoundValues[parentBoundValues.size() - 1]); - found = true; - } - } - } - } - - return *parentBoundValue; -} - -void AnalysisBase::setBoundValue(const std::string &name, const Json::Value &value, const Json::Value &meta, const QVector& parentKeys) -{ - bool found = false; - QVector parents; - Json::Value& parentBoundValue = _getParentBoundValue(parentKeys, parents, found, true); - - if (found && parentBoundValue.isObject()) - { - parentBoundValue[name] = value; - - if ((meta.isObject() || meta.isArray()) && meta.size() > 0) - { - Json::Value* metaBoundValue = &_boundValues[".meta"]; - for (const std::string& parent : parents) - metaBoundValue = &((*metaBoundValue)[parent]); - (*metaBoundValue)[name] = meta; - } - } - - emit boundValuesChanged(); -} - -void AnalysisBase::setBoundValues(const Json::Value &boundValues) -{ - _boundValues = boundValues; -} - -const Json::Value &AnalysisBase::boundValue(const std::string &name, const QVector &parentKeys) -{ - bool found = false; - QVector parentNames; - Json::Value& parentBoundValue = _getParentBoundValue(parentKeys, parentNames, found); - - - if (found && !parentBoundValue.isNull() && parentBoundValue.isObject()) return parentBoundValue[name]; - else return Json::Value::null; -} diff --git a/QMLComponents/analysisbase.h b/QMLComponents/analysisbase.h deleted file mode 100644 index 3cf7c5f70c7..00000000000 --- a/QMLComponents/analysisbase.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef ANALYSISBASE_H -#define ANALYSISBASE_H - -#include -#include -#include "controls/jaspcontrol.h" -#include "appinfo.h" - -class AnalysisForm; - -class AnalysisBase : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQuickItem * formItem READ formItem NOTIFY formItemChanged ) - Q_PROPERTY(QString qmlError READ qmlError WRITE setQmlError NOTIFY qmlErrorChanged ) - -public: - explicit AnalysisBase(QObject *parent = nullptr, Version moduleVersion = AppInfo::version); - AnalysisBase(QObject *parent, AnalysisBase* duplicateMe); - - virtual bool isOwnComputedColumn(const std::string &col) const { return false; } - virtual void refresh() {} - virtual void run() {} - virtual void reloadForm() {} - virtual void exportResults() {} - virtual bool isDuplicate() const { return false; } - virtual bool wasUpgraded() const { return false; } - virtual bool needsRefresh() const { return false; } - virtual const std::string & module() const { return emptyString; } - virtual const std::string & name() const { return emptyString; } - virtual const std::string & title() const { return emptyString; } - virtual void setTitle(const std::string& titel) {} - virtual void preprocessMarkdownHelp(const QString& md) const {} - virtual QString helpFile() { return ""; } - virtual const stringvec & upgradeMsgsForOption(const std::string& name) const { return emptyStringVec; } - virtual const Json::Value & resultsMeta() const { return Json::Value::null; } - virtual const Json::Value & getRSource(const std::string& name) const { return Json::Value::null; } - virtual void initialized(AnalysisForm* form, bool isNewAnalysis) {} - virtual std::string qmlFormPath(bool addFileProtocol = true, - bool ignoreReadyForUse = false) const; - - virtual Q_INVOKABLE QString helpFile() const { return ""; } - virtual Q_INVOKABLE void createForm(QQuickItem* parentItem=nullptr); - virtual void destroyForm(); - - const Json::Value& boundValues() const { return _boundValues; } - const Json::Value& orgBoundValues() const { return _orgBoundValues; } - const Json::Value& boundValue(const std::string& name, - const QVector& parentKeys = {}); - - void setBoundValue(const std::string& name, const Json::Value& value, const Json::Value& meta, const QVector& parentKeys = {}); - void setBoundValues(const Json::Value& boundValues); - void setOrgBoundValues(const Json::Value& orgBoundValues) { _orgBoundValues = orgBoundValues; } - const Json::Value optionsMeta() const { return _boundValues.get(".meta", Json::nullValue); } - void clearOptions() { _boundValues.clear(); } - - const Version & moduleVersion() const { return _moduleVersion; } - - QQuickItem * formItem() const; - - const QString & qmlError() const; - void setQmlError(const QString &newQmlError); - void sendRScript(QString script, QString controlName, bool whiteListedVersion) { emit sendRScriptSignal(script, controlName, whiteListedVersion, tq(module())); } - - -public slots: - virtual void boundValueChangedHandler() {} - virtual void requestColumnCreationHandler( const std::string & columnName, columnType colType) {} - virtual void requestComputedColumnCreationHandler( const std::string & columnName) {} - virtual void requestComputedColumnDestructionHandler(const std::string & columnName) {} - virtual void onUsedVariablesChanged() {} - - -signals: - void sendRScriptSignal(QString script, QString controlName, bool whiteListedVersion, QString module); - void formItemChanged(); - void qmlErrorChanged(); - void boundValuesChanged(); - - -protected: - Json::Value& _getParentBoundValue(const QVector & parentKeys, QVector& parentNames, bool & found, bool createAnyway = false); - - - AnalysisForm* _analysisForm = nullptr; - QQuickItem * _parentItem = nullptr; - QString _qmlError; - Version _moduleVersion; - -private: - Json::Value _boundValues = Json::objectValue, - _orgBoundValues = Json::objectValue; - - - -protected: - static const std::string emptyString; ///< Otherwise we return references to a temporary object (std::string("")) - static const stringvec emptyStringVec; -}; - -#endif // ANALYSISBASE_H diff --git a/QMLComponents/analysisform.cpp b/QMLComponents/analysisform.cpp deleted file mode 100644 index bef51ade220..00000000000 --- a/QMLComponents/analysisform.cpp +++ /dev/null @@ -1,1004 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "analysisform.h" -#include "knownissues.h" -#include "boundcontrols/boundcontrol.h" -#include "qutils.h" -#include "models/listmodeltermsavailable.h" -#include "controls/jasplistcontrol.h" -#include "controls/expanderbuttonbase.h" -#include "log.h" -#include "controls/jaspcontrol.h" -#include "rsyntax/rsyntax.h" - -#include -#include -#include -#include -#include "controls/variableslistbase.h" -#include "preferencesmodelbase.h" - -using namespace std; - -const QString AnalysisForm::rSyntaxControlName = "__RSyntaxTextArea"; - -AnalysisForm::AnalysisForm(QQuickItem *parent) : QQuickItem(parent) -{ - setObjectName("AnalysisForm"); - - _rSyntax = new RSyntax(this); - // _startRSyntaxTimer is used to call setRSyntaxText only once in a event loop. - connect(this, &AnalysisForm::infoChanged, this, &AnalysisForm::helpMDChanged ); - connect(this, &AnalysisForm::formCompletedSignal, this, &AnalysisForm::formCompletedHandler, Qt::QueuedConnection); - connect(this, &AnalysisForm::analysisChanged, this, &AnalysisForm::knownIssuesUpdated, Qt::QueuedConnection); - connect(KnownIssues::issues(), &KnownIssues::knownIssuesUpdated, this, &AnalysisForm::knownIssuesUpdated, Qt::QueuedConnection); - connect(this, &AnalysisForm::showAllROptionsChanged, this, &AnalysisForm::setRSyntaxText, Qt::QueuedConnection); - connect(PreferencesModelBase::preferences(), &PreferencesModelBase::showRSyntaxChanged, this, &AnalysisForm::setRSyntaxText, Qt::QueuedConnection); - connect(PreferencesModelBase::preferences(), &PreferencesModelBase::showAllROptionsChanged, this, &AnalysisForm::showAllROptionsChanged, Qt::QueuedConnection ); - connect(this, &AnalysisForm::analysisChanged, this, &AnalysisForm::setRSyntaxText, Qt::QueuedConnection); -} - -AnalysisForm::~AnalysisForm() -{ - Log::log() << "~AnalysisForm " << this << std::endl; -} - -void AnalysisForm::runRScript(QString script, QString controlName, bool whiteListedVersion) -{ - if(_analysis && !_removed) - { - if(_valueChangedSignalsBlocked == 0) _analysis->sendRScript(script, controlName, whiteListedVersion); - else _waitingRScripts.push(std::make_tuple(script, controlName, whiteListedVersion)); - } -} - -void AnalysisForm::refreshAnalysis() -{ - _analysis->refresh(); -} - -void AnalysisForm::runAnalysis() -{ - _analysis->run(); - refreshTableViewModels(); -} - -QString AnalysisForm::generateWrapper() const -{ - return _rSyntax->generateWrapper(); -} - -void AnalysisForm::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) -{ - if (change == ItemChange::ItemSceneChange && !value.window) - cleanUpForm(); - QQuickItem::itemChange(change, value); -} - -void AnalysisForm::cleanUpForm() -{ - if (!_removed) - { - _removed = true; - for (JASPControl* control : _dependsOrderedCtrls) - // controls will be automatically deleted by the deletion of AnalysisForm - // But they must be first disconnected: sometimes an event seems to be triggered before the item is completely destroyed - control->cleanUp(); - - _formCompleted = false; - } -} - -void AnalysisForm::runScriptRequestDone(const QString& result, const QString& controlName, bool hasError) -{ - if(_removed) - return; - - if (controlName == rSyntaxControlName) - { - JASPControl* rSyntaxControl = getControl(controlName); - if (hasError) - addControlError(rSyntaxControl, result); - else - { - Json::Reader parser; - Json::Value jsonResult; - parser.parse(fq(result), jsonResult); - Json::Value options = jsonResult["options"]; - clearControlError(rSyntaxControl); - clearFormErrors(); - if (_rSyntax->parseRSyntaxOptions(options)) - { - bindTo(options); - _analysis->boundValueChangedHandler(); - } - } - - return; - } - - JASPControl* item = getControl(controlName); - if (!item) - { - QStringList composedName = controlName.split("."); - if (composedName.length() == 3) - { - JASPControl* parentControl = getControl(composedName[0]); - if (parentControl) - item = dynamic_cast(parentControl->getChildControl(composedName[1], composedName[2])); - } - } - - if (item) - item->rScriptDoneHandler(result); - else - Log::log() << "Unknown item " << controlName.toStdString() << std::endl; -} - -void AnalysisForm::addControl(JASPControl *control) -{ - const QString & name = control->name(); - - if (_analysis && control->isBound()) - { - connect(control, &JASPControl::requestColumnCreation, _analysis, &AnalysisBase::requestColumnCreationHandler); - - connect(control, &JASPControl::usedVariablesChanged, _analysis, &AnalysisBase::onUsedVariablesChanged); - } - - if (control->controlType() == JASPControl::ControlType::Expander) - { - ExpanderButtonBase* expander = dynamic_cast(control); - _expanders.push_back(expander); - } - - if (!name.isEmpty() && !control->nameIsOptionValue()) - { - if (_controls.count(name) > 0) - { - control->addControlError(tr("2 controls have the same name: %1").arg(name)); - _controls[name]->addControlError(tr("2 controls have the same name: %1").arg(name)); - } - else - _controls[name] = control; - } - else if (name.isEmpty()) - { - control->setUp(); - control->setInitialized(); - } -} - -void AnalysisForm::addColumnControl(JASPControl* control, bool isComputed) -{ - if (isComputed) - { - connect(control, &JASPControl::requestComputedColumnCreation, _analysis, &AnalysisBase::requestComputedColumnCreationHandler); - connect(control, &JASPControl::requestComputedColumnDestruction, _analysis, &AnalysisBase::requestComputedColumnDestructionHandler); - } - else - connect(control, &JASPControl::requestColumnCreation, _analysis, &AnalysisBase::requestColumnCreationHandler); -} - -void AnalysisForm::_setUpControls() -{ - _setUpModels(); - _setUp(); -} - -void AnalysisForm::_setUpModels() -{ - for (JASPControl* control : _controls.values()) - { - JASPListControl* listControl = qobject_cast(control); - if (listControl) listControl->setUpModel(); - } -} - -void AnalysisForm::sortControls(QList& controls) -{ - for (JASPControl* control : controls) - { - control->addExplicitDependency(); - std::vector depends(control->depends().begin(), control->depends().end()); - - // By adding at the end of the vector new dependencies, this makes sure that these dependencies of these new dependencies are - // added and so on recursively, so that the 'depends' set of each control gets all (direct or indirect) controls it depends on. - // (that's why we cannot use a for-each loop here or an iterator, because it loops on a vector that is growing during the loop). - // Afterwards, if a control depends (directly or indirectly) of another control, the number of elements in its 'depends' set is then - // automatically strictly bigger than the 'depends' set of all controls it depends on. - // We have then simply to use the size of their 'depends' set, to sort the controls. - for (size_t index = 0; index < depends.size(); index++) - { - JASPControl * depend = depends[index]; - const std::set & dependdepends = depend->depends(); - - for (JASPControl* dependdepend : dependdepends) - if (dependdepend == control) - addFormError(tq("Circular dependency between control %1 and %2").arg(control->name()).arg(depend->name())); - else if (control->addDependency(dependdepend)) - depends.push_back(dependdepend); - } - } - - std::sort(controls.begin(), controls.end(), - [](JASPControl* a, JASPControl* b) { - return a->depends().size() < b->depends().size(); - }); -} - -void AnalysisForm::setHasVolatileNotes(bool hasVolatileNotes) -{ - if (_hasVolatileNotes == hasVolatileNotes) - return; - - _hasVolatileNotes = hasVolatileNotes; - emit hasVolatileNotesChanged(); -} - -bool AnalysisForm::parseOptions(Json::Value &options) -{ - if (_rSyntax->parseRSyntaxOptions(options)) - { - bindTo(options); - options = _analysis->boundValues(); - return true; - } - - return false; -} - -void AnalysisForm::_setUp() -{ - QList controls = _controls.values(); - - for (JASPControl* control : controls) - control->setUp(); - - sortControls(controls); - - for (JASPControl* control : controls) - { - _dependsOrderedCtrls.push_back(control); - connect(control, &JASPControl::helpMDChanged, this, &AnalysisForm::helpMDChanged); - } - - _rSyntax->setUp(); - - emit helpMDChanged(); //Because we just got info on our lovely children in _orderedControls -} - -void AnalysisForm::reset() -{ - _analysis->reloadForm(); -} - -void AnalysisForm::exportResults() -{ - _analysis->exportResults(); -} - -QString AnalysisForm::msgsListToString(const QStringList & list) const -{ - if(list.length() == 0) - return ""; - - QString text; - for (const QString & msg : list) - if(msg.size()) - text.append("
  • ").append(msg).append("
  • "); - - return !text.size() ? "" : "
      " + text + "
    "; -} - -void AnalysisForm::setInfo(QString info) -{ - if (_info == info) - return; - - _info = info; - emit infoChanged(); -} - -QString AnalysisForm::_getControlLabel(QString controlName) -{ - return _controls[controlName]->humanFriendlyLabel(); -} - -void AnalysisForm::_addLoadingError(QStringList wrongJson) -{ - if (wrongJson.size() > 0) - { - QString errorMsg; - if (wrongJson.size() == 1) - { - errorMsg = tr("Component %1 was loaded with the wrong type of value and has been reset to its default value.").arg(_getControlLabel(wrongJson[0])); - errorMsg += "
    "; - } - else if (wrongJson.size() < 4) - { - QString names = "
      "; - for(const QString & controlName : wrongJson) - names += "
    • " + _getControlLabel(controlName) + "
    • "; - names += "
    "; - - errorMsg = tr("These components were loaded with the wrong type of value and have been reset to their default values:%1").arg(names); - } - else - { - errorMsg = tr("Many components were loaded with the wrong type of value and have been reset to their default values."); - errorMsg += "
    "; - } - - errorMsg += tr("The file probably comes from an older version of JASP."); - errorMsg += "
    " + tr("That means that the results currently displayed do not correspond to the options selected."); - errorMsg += "
    " + tr("Refreshing the analysis may change the results."); - addFormError(errorMsg); - } -} - -void AnalysisForm::bindTo(const Json::Value & defaultOptions) -{ - std::set controlsJsonWrong; - - for (JASPControl* control : _dependsOrderedCtrls) - { - BoundControl* boundControl = control->boundControl(); - Json::Value optionValue = Json::nullValue; - if (boundControl) - { - std::string name = control->name().toStdString(); - if (defaultOptions.isMember(name)) - optionValue = defaultOptions[name]; - - if (optionValue != Json::nullValue && !boundControl->isJsonValid(optionValue)) - { - optionValue = Json::nullValue; - control->setHasWarning(true); - controlsJsonWrong.insert(name); - } - } - - control->setInitialized(optionValue); - } - - _addLoadingError(tql(controlsJsonWrong)); - - //Ok we can only set the warnings on the components now, because otherwise _addLoadingError() will add a big fat red warning on top of the analysisform without reason... - for (JASPControl* control : _dependsOrderedCtrls) - control->addControlWarning(msgsListToString(tq(_analysis->upgradeMsgsForOption(fq(control->name()))))); - - - //Also check for a warning to show above the analysis: - for(const QString & upgradeMsg : tq(_analysis->upgradeMsgsForOption(""))) - if(upgradeMsg != "") - addFormWarning(upgradeMsg); -} - -void AnalysisForm::addFormError(const QString & error) -{ - _formErrors.append(error); - emit errorsChanged(); -} - -void AnalysisForm::addFormWarning(const QString & warning) -{ - _formWarnings.append(warning); - emit warningsChanged(); -} - - -//This should be moved to JASPControl maybe? -//Maybe even to full QML? Why don't we just use a loader... -void AnalysisForm::addControlError(JASPControl* control, QString message, bool temporary, bool warning) -{ - if (!control) - { - // Quite bad: write it at least to the log - Log::log() << "Control error, but control not found: " << message << std::endl; - return; - } - - if (!message.isEmpty()) - { - QQuickItem* controlErrorMessageItem = nullptr; - - for (QQuickItem* item : _controlErrorMessageCache) - { - JASPControl* errorControl = item->property("control").value(); - if (errorControl == control || !errorControl) - { - controlErrorMessageItem = item; - break; - } - } - - if (!controlErrorMessageItem) - { - // Cannot instantiate _controlErrorMessageComponent in the constructor (it crashes), and it might be too late in the formCompletedHandler since error can be generated earlier - // So create it when it is needed for the first time. - if (!_controlErrorMessageComponent) - _controlErrorMessageComponent = new QQmlComponent(qmlEngine(this), "qrc:///components/JASP/Controls/ControlErrorMessage.qml"); - - controlErrorMessageItem = qobject_cast(_controlErrorMessageComponent->create(QQmlEngine::contextForObject(this))); - if (!controlErrorMessageItem) - { - Log::log() << "Could not create Control Error Item!!" << std::endl; - for (const QQmlError& error : _controlErrorMessageComponent->errors()) - Log::log() << "Error: " << error.description() << std::endl; - return; - } - controlErrorMessageItem->setProperty("form", QVariant::fromValue(this)); - _controlErrorMessageCache.append(controlErrorMessageItem); - } - - QQuickItem* container = this; - if (control->parentListView()) - { - container = control->parentListView()->property("listGridView").value(); - if (!container) - container = control->parentListView(); - } - - controlErrorMessageItem->setProperty("control", QVariant::fromValue(control)); - controlErrorMessageItem->setProperty("warning", warning); - controlErrorMessageItem->setParentItem(container); - QMetaObject::invokeMethod(controlErrorMessageItem, "showMessage", Qt::QueuedConnection, Q_ARG(QVariant, message), Q_ARG(QVariant, temporary)); - } - - if (warning) control->setHasWarning(true); - else control->setHasError(true); -} - -bool AnalysisForm::hasError() -{ - // _controls have only controls created when the form is created, not the ones created dynamically afterwards - // So here we use a workaround: check whether one errorMessage item in _controlErrorMessageCache has a control (do not use visible since it becomes visible too late). - // Controls handling inside a form must indeed be done in anther way! - - for (QQuickItem* item : _controlErrorMessageCache) - if (item->property("control").value() != nullptr) - return true; - - return false; -} - -QString AnalysisForm::getError() -{ - QString message; - - for (QQuickItem* item : _controlErrorMessageCache) - if (item->property("control").value() != nullptr) - message += (message != "" ? ", " : "") + item->property("message").toString(); - - return message; -} - -void AnalysisForm::clearControlError(JASPControl* control) -{ - if (!control) return; - - for (QQuickItem * errorItem : _controlErrorMessageCache) - if (control == errorItem->property("control").value()) - errorItem->setProperty("control", QVariant()); - - control->setHasError(false); - control->setHasWarning(false); -} - -void AnalysisForm::clearFormErrors() -{ - _formErrors.clear(); - emit errorsChanged(); - - for(auto & control : _controls) - { - control->setHasError(false); - control->setHasWarning(false); - } -} - - -void AnalysisForm::clearFormWarnings() -{ - _formWarnings.clear(); - emit warningsChanged(); - - for(auto & control : _controls) - control->setHasWarning(false); -} - -void AnalysisForm::setAnalysis(AnalysisBase * analysis) -{ - if(_analysis == analysis) return; - - if(_analysis && analysis) - throw std::runtime_error("An analysis of an analysisform was replaced by another analysis, this is decidedly NOT supported!"); - - _analysis = analysis; - - Log::log() << "AnalysisForm " << this << " sets Analysis " << _analysis << " on itself" << std::endl; - - setAnalysisUp(); -} - -void AnalysisForm::boundValueChangedHandler(JASPControl *) -{ - if (_valueChangedSignalsBlocked == 0 && _analysis) - _analysis->boundValueChangedHandler(); - else - _valueChangedEmittedButBlocked = true; -} - -void AnalysisForm::setTitle(QString title) -{ - if (_analysis) - _analysis->setTitle(fq(title.simplified())); -} - -void AnalysisForm::setOptionNameConversion(const QVariantList &conv) -{ - if (_rSyntax->setControlNameToRSyntaxMap(conv)) - emit optionNameConversionChanged(); -} - -void AnalysisForm::formCompletedHandler() -{ - Log::log() << "AnalysisForm::formCompletedHandler for " << this << " called." << std::endl; - - _formCompleted = true; - setAnalysisUp(); -} - -void AnalysisForm::setAnalysisUp() -{ - if(!_formCompleted || !_analysis) - return; - - Log::log() << "AnalysisForm::setAnalysisUp() for " << this << std::endl; - - blockValueChangeSignal(true); - - _setUpControls(); - - Json::Value defaultOptions = _analysis->orgBoundValues(); - _analysis->clearOptions(); - bindTo(defaultOptions); - - blockValueChangeSignal(false, false); - - _initialized = true; - - // Don't bind boundValuesChanged before it is initialized: each setup of all controls will generate a boundValuesChanged - connect(_analysis, &AnalysisBase::boundValuesChanged, this, &AnalysisForm::setRSyntaxText, Qt::QueuedConnection ); - - setRSyntaxText(); - emit analysisChanged(); -} - -void AnalysisForm::knownIssuesUpdated() -{ - if(!_formCompleted || !_analysis) - return; - - if(KnownIssues::issues()->hasIssues(_analysis->module(), _analysis->name())) - { - const std::vector & issues = KnownIssues::issues()->getIssues(_analysis->module(), _analysis->name()); - - for(const KnownIssues::issue & issue : issues) - { - for(const std::string & option : issue.options) - if(_controls.count(tq(option)) > 0) - _controls[tq(option)]->setHasWarning(true); - - _formWarnings.append(tq(issue.info)); - } - - emit warningsChanged(); - } -} - -void AnalysisForm::setControlIsDependency(QString controlName, bool isDependency) -{ - if(_controls.count(controlName) > 0) - _controls[controlName]->setProperty("isDependency", isDependency); -} - -void AnalysisForm::setControlMustContain(QString controlName, QStringList containThis) -{ - if(_controls.count(controlName) > 0) - _controls[controlName]->setProperty("dependencyMustContain", containThis); -} - -void AnalysisForm::setMustBe(std::set mustBe) -{ - if(mustBe == _mustBe) - return; - - for(const std::string & mustveBeen : _mustBe) - if(mustBe.count(mustveBeen) == 0) - setControlIsDependency(mustveBeen, false); - - _mustBe = mustBe; - - for(const std::string & mustBecome : _mustBe) - setControlIsDependency(mustBecome, true); //Its ok if it does it twice, others will only be notified on change -} - -void AnalysisForm::setMustContain(std::map> mustContain) -{ - if(mustContain == _mustContain) - return; - - //For now ignore specific thing that must be contained - for(const auto & nameContainsPair : _mustContain) - if(mustContain.count(nameContainsPair.first) == 0) - setControlMustContain(nameContainsPair.first, {}); - - _mustContain = mustContain; - - for(const auto & nameContainsPair : _mustContain) - setControlMustContain(nameContainsPair.first, nameContainsPair.second); //Its ok if it does it twice, others will only be notified on change - -} - -void AnalysisForm::setRunOnChange(bool change) -{ - if (change != _runOnChange) - { - _runOnChange = change; - - blockValueChangeSignal(change, false); - - emit runOnChangeChanged(); - } -} - -void AnalysisForm::blockValueChangeSignal(bool block, bool notifyOnceUnblocked) -{ - if (block) - _valueChangedSignalsBlocked++; - else - { - _valueChangedSignalsBlocked--; - - if (_valueChangedSignalsBlocked < 0) - _valueChangedSignalsBlocked = 0; - - if (_valueChangedSignalsBlocked == 0) - { - if(notifyOnceUnblocked && _analysis && _valueChangedEmittedButBlocked) - _analysis->boundValueChangedHandler(); - - _valueChangedEmittedButBlocked = false; - - if(_analysis && (notifyOnceUnblocked || _analysis->wasUpgraded())) //Maybe something was upgraded and we want to run the dropped rscripts (for instance for https://github.com/jasp-stats/INTERNAL-jasp/issues/1399) - while(_waitingRScripts.size() > 0) - { - const auto & front = _waitingRScripts.front(); - _analysis->sendRScript(std::get<0>(front), std::get<1>(front), std::get<2>(front)); - _waitingRScripts.pop(); - } - else //Otherwise just clean it up - _waitingRScripts = std::queue>(); - } - } -} - -QString AnalysisForm::rSyntaxText() const -{ - Log::log() << "rSyntaxText: " << _rSyntaxText << std::endl; - - return _rSyntaxText; -} - -bool AnalysisForm::needsRefresh() const -{ - return _analysis ? _analysis->needsRefresh() : false; -} - -bool AnalysisForm::isFormulaName(const QString& name) const -{ - return _rSyntax->getFormula(name) != nullptr; -} - -QString AnalysisForm::generateRSyntax(bool useHtml) const -{ - return _rSyntax->generateSyntax(!useHtml && showAllROptions(), useHtml); -} - -QVariantList AnalysisForm::optionNameConversion() const -{ - return _rSyntax->controlNameToRSyntaxMap(); -} - -std::vector > AnalysisForm::getValuesFromRSource(const QString &sourceID, const QStringList &searchPath) -{ - if (!_analysis) return {}; - - const Json::Value& jsonSource = _analysis->getRSource(fq(sourceID)); - return _getValuesFromJson(jsonSource, searchPath); -} - -std::vector > AnalysisForm::_getValuesFromJson(const Json::Value& jsonValues, const QStringList& searchPath) -{ - auto getValueFromJson = [](const Json::Value& jsonValue) -> std::vector - { - if (jsonValue.isString()) return {jsonValue.asString()}; - else if (jsonValue.isIntegral()) return {std::to_string(jsonValue.asInt())}; - else if (jsonValue.isNumeric()) return {std::to_string(jsonValue.asDouble())}; - else if (jsonValue.isArray()) - { - std::vector values; - for (const Json::Value& oneValue: jsonValue) - { - if (oneValue.isString()) values.push_back(oneValue.asString()); - if (oneValue.isIntegral()) values.push_back(std::to_string(oneValue.asInt())); - if (oneValue.isNumeric()) values.push_back(std::to_string(oneValue.asDouble())); - } - return values; - } - else return {}; - }; - - std::vector > result; - - if (jsonValues.isNull()) - return result; - - if (!jsonValues.isArray() && !jsonValues.isObject()) - return {getValueFromJson(jsonValues)}; - - QString path; - QStringList nextPaths; - if (searchPath.length() > 0) - { - path = searchPath[0]; - nextPaths = searchPath; - nextPaths.removeAt(0); - } - - if (jsonValues.isObject()) - { - if (path.isEmpty()) - { - std::vector keys = jsonValues.getMemberNames(); - for (const std::string& key : keys) - result.push_back({key}); - } - else - { - std::string key = fq(path); - if (jsonValues.isMember(key)) - result = _getValuesFromJson(jsonValues[key], nextPaths); - else if (key == "values") - { - for (const Json::Value& jsonValue : jsonValues) - { - std::vector > values = _getValuesFromJson(jsonValue, nextPaths); - if (values.size() > 0) - result.push_back(values[0]); - } - } - else - Log::log() << "Key " << key << " not found in R source " << jsonValues.toStyledString() << std::endl; - } - } - else // jsonValues is an array - { - bool pathIsIndex = false; - uint index = path.isEmpty() ? 0 : path.toUInt(&pathIsIndex); - - if (pathIsIndex) - { - if (jsonValues.size() > index) - result = _getValuesFromJson(jsonValues[index], nextPaths); - else - Log::log() << "Cannot retrieve values from R Source: index (" << index << ") bigger than size of the source (" << jsonValues.size() << ")" << std::endl; - } - else - { - for (const Json::Value& jsonValue : jsonValues) - { - if (path.isEmpty()) - result.push_back(getValueFromJson(jsonValue)); - else if (jsonValue.isObject()) - { - std::string key = fq(path); - if (jsonValue.isMember(key)) - { - std::vector > values =_getValuesFromJson(jsonValue[key], nextPaths); - if (values.size() > 0) - result.push_back(values[0]); - } - else - Log::log() << "Key " << key << " not found in R source " << jsonValue.toStyledString() << std::endl; - } - else - Log::log() << "Caanot find path " << path << " in R source " << jsonValue.toStyledString() << std::endl; - } - } - } - - return result; -} - -void AnalysisForm::setBoundValue(const string &name, const Json::Value &value, const Json::Value &meta, const QVector &parentKeys) -{ - if (_analysis) - _analysis->setBoundValue(name, value, meta, parentKeys); -} - -std::set AnalysisForm::usedVariables() -{ - std::set result; - - for (JASPControl* control : _controls) - { - JASPListControl* listControl = qobject_cast(control); - if (listControl) - { - std::vector usedVariables = listControl->usedVariables(); - result.insert(usedVariables.begin(), usedVariables.end()); - } - } - - return result; -} - -///Generates documentation based on the "info" entered on each component -QString AnalysisForm::helpMD() const -{ - if(!_analysis) return ""; - - QStringList markdown = - { - title(), "\n", - "=====================\n", - _info, "\n\n", - "---\n# ", tr("Options"), "\n" - }; - - QList orderedControls = JASPControl::getChildJASPControls(this); - - std::set markdowned; - - for(JASPControl * control : orderedControls) - if(!markdowned.count(control)) - markdown.push_back(control->helpMD(markdowned)); - - markdown.push_back(metaHelpMD()); - - QString md = markdown.join(""); - - if(_analysis) - _analysis->preprocessMarkdownHelp(md); - - return md; -} - -///Collects "info" from results and lists them underneath the output in the help-md window -QString AnalysisForm::metaHelpMD() const -{ - std::function metaMDer = [&metaMDer](const Json::Value & meta, int deep) - { - QStringList markdown; - - for(const Json::Value & entry : meta) - { - std::string entryType = entry.get("type", "").asString(); - //Sadly enough the following "meta-types" aren't defined properly anywhere, this would be good to do at some point. The types are: table, image, collection, and optionally: htmlNode, column, json - QString friendlyObject = entryType == "table" ? tr("Table") - : entryType == "image" ? tr("Plot") - : entryType == "collection" ? tr("Collection") - : tr("Result"); //Anything else we just call "Result" - - if(entry.get("info", "") != "") - { - for(int i=0; iresultsMeta(), 2); - return meta.isEmpty() ? "" : "---\n# " + tr("Output") + "\n\n" + meta; -} - -void AnalysisForm::setShowRButton(bool showRButton) -{ - if (_showRButton == showRButton) - return; - - _showRButton = showRButton; - - emit showRButtonChanged(); -} - -void AnalysisForm::setDeveloperMode(bool developerMode) -{ - if (_developerMode == developerMode) - return; - - _developerMode = developerMode; - - emit developerModeChanged(); -} - -void AnalysisForm::setRSyntaxText() -{ - if (!initialized() || !PreferencesModelBase::preferences()->showRSyntax()) - return; - - QString text = generateRSyntax(); - - if (text != _rSyntaxText) - { - _rSyntaxText = text; - emit rSyntaxTextChanged(); - } -} - -bool AnalysisForm::showAllROptions() const -{ - return PreferencesModelBase::preferences()->showAllROptions(); -} - -void AnalysisForm::setShowAllROptions(bool showAllROptions) -{ - PreferencesModelBase::preferences()->setShowAllROptions(showAllROptions); -} - -void AnalysisForm::sendRSyntax(QString text) -{ - PreferencesModelBase::preferences()->setShowRSyntax(true); - _analysis->sendRScript(text, rSyntaxControlName, false); -} - -void AnalysisForm::toggleRSyntax() -{ - PreferencesModelBase* pref = PreferencesModelBase::preferences(); - pref->setShowRSyntax(!pref->showRSyntax()); -} - -void AnalysisForm::setActiveJASPControl(JASPControl* control, bool hasActiveFocus) -{ - bool emitSignal = false; - if (hasActiveFocus) - { - if (_activeJASPControl != control) emitSignal = true; - _activeJASPControl = control; - } - else if (control == _activeJASPControl) - { - if (_activeJASPControl) emitSignal = true; - _activeJASPControl = nullptr; - } - - if (emitSignal) - emit activeJASPControlChanged(); -} diff --git a/QMLComponents/analysisform.h b/QMLComponents/analysisform.h deleted file mode 100644 index 500608c64ac..00000000000 --- a/QMLComponents/analysisform.h +++ /dev/null @@ -1,239 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef ANALYSISFORM_H -#define ANALYSISFORM_H - -#include -#include - -#include "boundcontrols/boundcontrol.h" -#include "analysisbase.h" -#include "models/listmodel.h" -#include "models/listmodeltermsavailable.h" -#include "utilities/messageforwarder.h" -#include "qutils.h" -#include - -class ListModelTermsAssigned; -class JASPControl; -class ExpanderButtonBase; -class RSyntax; - -/// -/// The backend for the `Form{}` used in all JASP's well, qml forms -/// This is directly a QQuickItem and connects to Analyses to inform it when the options change. -/// Each element placed inside the Form will be a derivative of JASPControl -/// A JASPControl can be also a BoundControl: it is bound in the sense that any changes to its values will be propagated to Analysis and stored there through `Analysis::setBoundValue` -/// Each time a JASPControl is initialized, it is registered by the form, and when the form is initialized it sets up the JASPControls either by their default values, -/// or by the values stored in a JASP file (when a JASP file is loaded). -/// The interface errors and warnings are managed by this class. -class AnalysisForm : public QQuickItem -{ - Q_OBJECT - Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged ) - Q_PROPERTY(QString errors READ errors NOTIFY errorsChanged ) - Q_PROPERTY(QString warnings READ warnings NOTIFY warningsChanged ) - Q_PROPERTY(bool needsRefresh READ needsRefresh NOTIFY needsRefreshChanged ) - Q_PROPERTY(bool hasVolatileNotes READ hasVolatileNotes NOTIFY hasVolatileNotesChanged ) - Q_PROPERTY(bool runOnChange READ runOnChange WRITE setRunOnChange NOTIFY runOnChangeChanged ) - Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged ) - Q_PROPERTY(QString helpMD READ helpMD NOTIFY helpMDChanged ) - Q_PROPERTY(QVariant analysis READ analysis NOTIFY analysisChanged ) - Q_PROPERTY(QVariantList optionNameConversion READ optionNameConversion WRITE setOptionNameConversion NOTIFY optionNameConversionChanged ) - Q_PROPERTY(bool showRButton READ showRButton NOTIFY showRButtonChanged ) - Q_PROPERTY(bool developerMode READ developerMode NOTIFY developerModeChanged ) - Q_PROPERTY(QString rSyntaxText READ rSyntaxText NOTIFY rSyntaxTextChanged ) - Q_PROPERTY(bool showAllROptions READ showAllROptions WRITE setShowAllROptions NOTIFY showAllROptionsChanged ) - Q_PROPERTY(QString rSyntaxControlName MEMBER rSyntaxControlName CONSTANT ) - Q_PROPERTY(JASPControl* activeJASPControl READ getActiveJASPControl NOTIFY activeJASPControlChanged ) - -public: - explicit AnalysisForm(QQuickItem * = nullptr); - ~AnalysisForm(); - - void bindTo(const Json::Value & defaultOptions); - - void runRScript(QString script, QString controlName, bool whiteListedVersion); - - void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override; - - void setMustBe( std::set mustBe); - void setMustContain( std::map> mustContain); - - bool runOnChange() { return _runOnChange; } - void setRunOnChange(bool change); - void blockValueChangeSignal(bool block, bool notifyOnceUnblocked = true); - QString title() const { return _analysis ? tq(_analysis->title()) : ""; } - QString name() const { return _analysis ? tq(_analysis->name()) : ""; } - QString module() const { return _analysis ? tq(_analysis->module()) : ""; } - QString version() const { return _analysis ? tq(_analysis->moduleVersion().asString()) : ""; } - bool hasVolatileNotes() const { return _hasVolatileNotes; } - bool wasUpgraded() const { return _analysis ? _analysis->wasUpgraded() : false; } - bool formCompleted() const { return _formCompleted; } - bool showRButton() const { return _showRButton; } - bool developerMode() const { return _developerMode; } - QString rSyntaxText() const; - bool showAllROptions() const; - -public slots: - void runScriptRequestDone(const QString& result, const QString& requestId, bool hasError); - void setInfo(QString info); - void setAnalysis(AnalysisBase * analysis); - void boundValueChangedHandler(JASPControl* control); - void setOptionNameConversion(const QVariantList& conv); - void setTitle(QString title); - void setShowRButton(bool showRButton); - void setDeveloperMode(bool developerMode); - void setRSyntaxText(); - void setShowAllROptions(bool showAllROptions); - void sendRSyntax(QString text); - void toggleRSyntax(); - -signals: - void formChanged(AnalysisBase* analysis); - void formCompletedSignal(); - void refreshTableViewModels(); - void errorMessagesItemChanged(); - void languageChanged(); - void needsRefreshChanged(); - void hasVolatileNotesChanged(); - void runOnChangeChanged(); - void infoChanged(); - void helpMDChanged(); - void errorsChanged(); - void warningsChanged(); - void analysisChanged(); - void rSourceChanged(const QString& name); - void optionNameConversionChanged(); - void titleChanged(); - void showRButtonChanged(); - void developerModeChanged(); - void rSyntaxTextChanged(); - void showAllROptionsChanged(); - void activeJASPControlChanged(); - -public: - ListModel * getModel(const QString& modelName) const { return _modelMap.count(modelName) > 0 ? _modelMap[modelName] : nullptr; } // Maps create elements if they do not exist yet - void addModel(ListModel* model) { if (!model->name().isEmpty()) _modelMap[model->name()] = model; } - JASPControl * getControl(const QString& name) { return _controls.contains(name) ? _controls[name] : nullptr; } - void addListView(JASPListControl* listView, JASPListControl* sourceListView); - void addControl(JASPControl* control); - - Q_INVOKABLE void clearFormErrors(); - Q_INVOKABLE void clearFormWarnings(); - Q_INVOKABLE void reset(); - Q_INVOKABLE void exportResults(); - Q_INVOKABLE void addFormError(const QString& message); - Q_INVOKABLE void addFormWarning(const QString& message); - Q_INVOKABLE void refreshAnalysis(); - Q_INVOKABLE void runAnalysis(); - Q_INVOKABLE bool initialized() const { return _initialized; } - Q_INVOKABLE QString generateWrapper() const; - - void addControlError(JASPControl* control, QString message, bool temporary = false, bool warning = false); - void clearControlError(JASPControl* control); - void cleanUpForm(); - bool hasError(); - QString getError(); - - bool isOwnComputedColumn(const std::string& col) const { return _analysis ? _analysis->isOwnComputedColumn(col) : false; } - - bool needsRefresh() const; - - QString info() const { return _info; } - QString helpMD() const; - QString metaHelpMD() const; - QString errors() const { return msgsListToString(_formErrors); } - QString warnings() const { return msgsListToString(_formWarnings); } - QVariant analysis() const { return QVariant::fromValue(_analysis); } - RSyntax* rSyntax() const { return _rSyntax; } - QString generateRSyntax(bool useHtml = false) const; - QVariantList optionNameConversion() const; - bool isFormulaName(const QString& name) const; - - stringvecvec getValuesFromRSource(const QString& sourceID, const QStringList& searchPath); - void addColumnControl(JASPControl* control, bool isComputed); - - const Json::Value& boundValues() const { return _analysis ? _analysis->boundValues() : Json::Value::null; } - const Json::Value& boundValue(const std::string& name, const QVector& parentKeys) { return _analysis ? _analysis->boundValue(name, parentKeys) : Json::Value::null; } - void setBoundValue(const std::string& name, const Json::Value& value, const Json::Value& meta, const QVector& parentKeys = {}); - stringset usedVariables(); - - void sortControls(QList& controls); - QString getSyntaxName(const QString& name) const; - void setHasVolatileNotes(bool hasVolatileNotes); - bool parseOptions(Json::Value& options); - void setActiveJASPControl(JASPControl* control, bool hasActiveFocus); - JASPControl* getActiveJASPControl() { return _activeJASPControl; } - - static const QString rSyntaxControlName; - -private: - - Json::Value & _getParentBoundValue(const QVector& parentKeys); - void _setUpControls(); - void _setUpModels(); - void _setUp(); - QString _getControlLabel(QString controlName); - void _addLoadingError(QStringList wrongJson); - void setControlIsDependency( QString controlName, bool isDependency); - void setControlMustContain( QString controlName, QStringList containThis); - void setControlIsDependency( std::string controlName, bool isDependency) { setControlIsDependency(tq(controlName), isDependency); } - void setControlMustContain( std::string controlName, std::set containThis) { setControlMustContain(tq(controlName), tql(containThis)); } - void setAnalysisUp(); - stringvecvec _getValuesFromJson(const Json::Value& jsonValues, const QStringList& searchPath); - QString msgsListToString(const QStringList & list) const; - -private slots: - void formCompletedHandler(); - void knownIssuesUpdated(); - -private: - AnalysisBase * _analysis = nullptr; - QMap _controls; - - ///Ordered on dependencies within QML, aka an assigned variables list depends on the available list it is connected to. - QVector _dependsOrderedCtrls; - QMap _modelMap; - QVector _expanders; - QMap _controlExpanderMap; - bool _removed = false; - std::set _mustBe; - std::map> _mustContain; - - QStringList _formErrors, - _formWarnings; - QQmlComponent* _controlErrorMessageComponent = nullptr; - QList _controlErrorMessageCache; - bool _runOnChange = true, - _formCompleted = false, - _hasVolatileNotes = false, - _initialized = false, - _valueChangedEmittedButBlocked = false; - QString _info; - int _valueChangedSignalsBlocked = 0; - std::queue> _waitingRScripts; //Sometimes signals are blocked, and thus rscripts. But they shouldnt just disappear right? - RSyntax * _rSyntax = nullptr; - bool _showRButton = false, - _developerMode = false; - QString _rSyntaxText; - JASPControl* _activeJASPControl = nullptr; -}; - -#endif // ANALYSISFORM_H diff --git a/QMLComponents/boundcontrols/boundcontrol.h b/QMLComponents/boundcontrols/boundcontrol.h deleted file mode 100644 index 97944f4a643..00000000000 --- a/QMLComponents/boundcontrols/boundcontrol.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROL_H -#define BOUNDCONTROL_H - -#include - -class BoundControl -{ - -public: - virtual Json::Value createJson() const = 0; - virtual Json::Value createMeta() const = 0; - virtual bool isJsonValid(const Json::Value& optionValue) const = 0; - virtual void bindTo(const Json::Value& value) = 0; - virtual const Json::Value& boundValue() const = 0; - virtual void resetBoundValue() = 0; - virtual void setBoundValue(const Json::Value& value, bool emitChange = true) = 0; - virtual const Json::Value& defaultBoundValue() const = 0; - virtual void setDefaultBoundValue(const Json::Value& defaultValue) = 0; -}; - -#endif // BOUNDCONTROL_H diff --git a/QMLComponents/boundcontrols/boundcontrolbase.cpp b/QMLComponents/boundcontrols/boundcontrolbase.cpp deleted file mode 100644 index 5a93b1ef4c5..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolbase.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . - -#include "boundcontrolbase.h" -#include "controls/jaspcontrol.h" -#include "controls/jasplistcontrol.h" -#include "analysisform.h" -#include "log.h" -#include "models/listmodel.h" -#include "controls/rowcontrols.h" - -BoundControlBase::BoundControlBase(JASPControl* control) : _control(control) -{ -} - - -//To do: define these fields (isRCode, shouldEncode, etc) somewhere centrally through an enum or something -Json::Value BoundControlBase::createMeta() const -{ - Json::Value meta(Json::objectValue); - - if (_isColumn || _control->encodeValue()) - meta["shouldEncode"] = true; - - for(const std::string & key : _isRCode) - if(key.empty()) meta ["isRCode"] = true; - else meta[key]["isRCode"] = true; - - return meta; -} - -void BoundControlBase::setBoundValue(const Json::Value &value, bool emitChange) -{ - AnalysisForm* form = _control->form(); - - if (!form || !_control->isBound() || value == boundValue()) return; - - if (_isColumn && value.isString()) - { - const Json::Value & orgValue = boundValue(); - std::string newName = value.asString(), - orgName = orgValue.asString(); - - if (newName.empty() && !orgName.empty()) - emit _control->requestComputedColumnDestruction(orgName); - - else if (newName != orgName) - { - if (_isComputedColumn) emit _control->requestComputedColumnCreation(newName); - else emit _control->requestColumnCreation(newName, _columnType); - - if (!orgName.empty()) - emit _control->requestComputedColumnDestruction(orgName); - } - } - - form->setBoundValue(getName(), value, createMeta(), _control->getParentKeys()); - - if (emitChange) - emit _control->boundValueChanged(_control); -} - -void BoundControlBase::setIsRCode(std::string key) -{ - _isRCode.insert(key); -} - -const Json::Value & BoundControlBase::boundValue() const -{ - AnalysisForm * form = _control->form(); - - if (form) return form->boundValue(getName(), _control->getParentKeys()); - else return Json::Value::null; -} - -void BoundControlBase::setIsColumn(bool isComputed, columnType type) -{ - _isColumn = true; - _isComputedColumn = isComputed; - _columnType = type; - - AnalysisForm * form = _control->form(); - - if (form) form->addColumnControl(_control, isComputed); -} - - -std::string BoundControlBase::getName() const -{ - return fq(_control->name()); -} - -void BoundControlBase::_readTableValue(const Json::Value &value, const std::string& key, bool hasMultipleTerms, Terms& terms, ListModel::RowControlsValues& allControlValues) -{ - for (const Json::Value& row : value) - { - std::vector term; - const Json::Value& keyValue = row[key]; - if (keyValue.isArray()) - { - for (const Json::Value& component : keyValue) - term.push_back(component.asString()); - } - else if (keyValue.isString()) - term.push_back(keyValue.asString()); - else - Log::log() << "Key (" << key << ") bind value is not an array or a string in " << getName() << ": " << value.toStyledString() << std::endl; - - if (term.size() > 0) - { - terms.add(Term(term)); - - QMap controlMap; - for (auto itr = row.begin(); itr != row.end(); ++itr) - { - const std::string& name = itr.key().asString(); - if (name != key) - controlMap[tq(name)] = *itr; - } - - allControlValues[Term(term).asQString()] = controlMap; - } - } -} - -Json::Value BoundControlBase::_getTableValueOption(const Terms& terms, const ListModel::RowControlsValues& componentValuesMap, const std::string& key, bool hasMultipleTerms) -{ - Json::Value result(Json::arrayValue); - - for (const Term& term : terms) - { - QMap componentValues = componentValuesMap[term.asQString()]; - - Json::Value rowValues(Json::objectValue); - if (hasMultipleTerms) - { - Json::Value keyValue(Json::arrayValue); - for (const std::string& comp : term.scomponents()) - keyValue.append(comp); - rowValues[key] = keyValue; - } - else - { - Json::Value keyValue(term.asString()); - rowValues[key] = keyValue; - } - - QMapIterator it2(componentValues); - while (it2.hasNext()) - { - it2.next(); - rowValues[fq(it2.key())] = it2.value(); - } - result.append(rowValues); - } - - return result; -} - -void BoundControlBase::_setTableValue(const Terms& terms, const ListModel::RowControlsValues& componentValuesMap, const std::string& key, bool hasMultipleTerms) -{ - setBoundValue(_getTableValueOption(terms, componentValuesMap, key, hasMultipleTerms)); -} - diff --git a/QMLComponents/boundcontrols/boundcontrolbase.h b/QMLComponents/boundcontrols/boundcontrolbase.h deleted file mode 100644 index cf063af3c48..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolbase.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLBASE_H -#define BOUNDCONTROLBASE_H - -#include "boundcontrol.h" -#include "columntype.h" -#include "models/listmodel.h" - -class JASPControl; -class Terms; - -class BoundControlBase : public BoundControl -{ -public: - BoundControlBase(JASPControl* control); - virtual ~BoundControlBase() {} - - Json::Value createJson() const override { return Json::nullValue; } - Json::Value createMeta() const override; - void bindTo(const Json::Value& value) override { _orgValue = value; setBoundValue(value, false); } - const Json::Value& boundValue() const override; - void resetBoundValue() override { bindTo(_orgValue); } - void setBoundValue(const Json::Value& value, bool emitChange = true) override; - void setIsRCode(std::string key = ""); - void setIsColumn(bool isComputed, columnType type = columnType::unknown); - const Json::Value& defaultBoundValue() const override { return _defaultValue; } - void setDefaultBoundValue(const Json::Value& defaultValue) override { _defaultValue = defaultValue; } - -protected: - std::string getName() const; - - Json::Value _getTableValueOption(const Terms& terms, const ListModel::RowControlsValues& componentValuesMap, const std::string& key, bool hasMultipleTerms); - void _setTableValue(const Terms& terms, const ListModel::RowControlsValues& componentValuesMap, const std::string& key, bool hasMultipleTerms); - - void _readTableValue(const Json::Value& value, const std::string& key, bool hasMultipleTerms, Terms& terms, ListModel::RowControlsValues& allControlValues); - - JASPControl* _control = nullptr; - bool _isComputedColumn = false, - _isColumn = false; - std::set _isRCode; - Json::Value _orgValue, - _defaultValue; - columnType _columnType = columnType::unknown; -}; - -#endif // BOUNDCONTROLBASE_H diff --git a/QMLComponents/boundcontrols/boundcontrolcontraststableview.cpp b/QMLComponents/boundcontrols/boundcontrolcontraststableview.cpp deleted file mode 100644 index 89b1d376e7e..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolcontraststableview.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolcontraststableview.h" -#include "controls/tableviewbase.h" -#include "models/listmodelcustomcontrasts.h" - -BoundControlContrastsTableView::BoundControlContrastsTableView(TableViewBase* tableView) - : BoundControlTableView (tableView) -{ -} - -Json::Value BoundControlContrastsTableView::createJson() const -{ - Json::Value result = Json::Value(Json::arrayValue); - ListModelCustomContrasts* contrastsModel = qobject_cast(_tableView->tableModel()); - - - QStringList variables; - QVector > allLables; - - contrastsModel->getVariablesAndLabels(variables, allLables); - - if (variables.length() > 0) - { - Json::Value rowNames(Json::arrayValue); - - for (int row = 0; row < allLables[0].length(); row++) - rowNames.append(fq(contrastsModel->getDefaultRowName(size_t(row)))); - - int col = 0; - for (const QString& variable : variables) - { - Json::Value row(Json::objectValue); - row["name"] = fq(variable); - row["levels"] = rowNames; - row["isContrast"] = false; - - Json::Value values(Json::arrayValue); - for (const QVariant & label: allLables[col]) - values.append(fq(label.toString())); - row["values"] = values; - - col++; - - result.append(row); - } - - if (_tableView->initialColumnCount() > 0) - { - Json::Value defaultValue = _defaultValue(); - - for (int colIndex = 0; colIndex < _tableView->initialColumnCount(); colIndex++) - { - Json::Value row(Json::objectValue); - row["name"] = fq(contrastsModel->getDefaultColName(size_t(variables.length() + colIndex))); - row["levels"] = rowNames; - row["isContrast"] = true; - - Json::Value values(Json::arrayValue); - for (size_t i = 0; i < rowNames.size(); i++) - values.append(defaultValue); - row["values"] = values; - - result.append(row); - } - } - } - - return result; -} - -void BoundControlContrastsTableView::fillTableTerms(const Json::Value &value, ListModelTableViewBase::TableTerms &tableTerms) -{ - BoundControlTableView::fillTableTerms(value, tableTerms); - - int index = 0; - for (const Json::Value& row : value) - { - if (!row["isContrast"].asBool()) - tableTerms.variables.push_back(tableTerms.colNames[index]); - index++; - } -} - -void BoundControlContrastsTableView::fillBoundValue(Json::Value& value, const ListModelTableViewBase::TableTerms& tableTerms) -{ - BoundControlTableView::fillBoundValue(value, tableTerms); - - int i = 0; - for (Json::Value& row : value) - { - row["isContrast"] = (i >= tableTerms.variables.length()); - i++; - } -} - diff --git a/QMLComponents/boundcontrols/boundcontrolcontraststableview.h b/QMLComponents/boundcontrols/boundcontrolcontraststableview.h deleted file mode 100644 index 56a7d3dab24..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolcontraststableview.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLCONTRASTSTABLEVIEW_H -#define BOUNDCONTROLCONTRASTSTABLEVIEW_H - -#include "boundcontroltableview.h" - -class BoundControlContrastsTableView : public BoundControlTableView -{ -public: - BoundControlContrastsTableView(TableViewBase* tableView); - - Json::Value createJson() const override; - void fillTableTerms(const Json::Value& value, ListModelTableViewBase::TableTerms& tableTerms) override; - void fillBoundValue(Json::Value& value, const ListModelTableViewBase::TableTerms& tableTerms) override; -}; - -#endif // BOUNDCONTROLCONTRASTSTABLEVIEW_H diff --git a/QMLComponents/boundcontrols/boundcontrolcsemtextarea.cpp b/QMLComponents/boundcontrols/boundcontrolcsemtextarea.cpp deleted file mode 100644 index 80093dea356..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolcsemtextarea.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "boundcontrolcsemtextarea.h" diff --git a/QMLComponents/boundcontrols/boundcontrolcsemtextarea.h b/QMLComponents/boundcontrols/boundcontrolcsemtextarea.h deleted file mode 100644 index 2476702760c..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolcsemtextarea.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef BOUNDCONTROLCSEMTEXTAREA_H -#define BOUNDCONTROLCSEMTEXTAREA_H - -#include "boundcontrollavaantextarea.h" - -class BoundControlCSemTextArea : public BoundControlLavaanTextArea -{ -public: - using BoundControlLavaanTextArea::BoundControlLavaanTextArea; - -protected: - const char * _checkSyntaxRFunctionName() override { return "jaspSem:::checkCSemModel"; } -}; - -#endif // BOUNDCONTROLCSEMTEXTAREA_H diff --git a/QMLComponents/boundcontrols/boundcontrolfilteredtableview.cpp b/QMLComponents/boundcontrols/boundcontrolfilteredtableview.cpp deleted file mode 100644 index d8ddd19dfec..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolfilteredtableview.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolfilteredtableview.h" -#include "controls/tableviewbase.h" -#include "models/listmodelfiltereddataentry.h" - -BoundControlFilteredTableView::BoundControlFilteredTableView(TableViewBase* tableView) - : BoundControlTableView(tableView) -{ -} - -Json::Value BoundControlFilteredTableView::createJson() const -{ - Json::Value result(Json::arrayValue); - Json::Value row(Json::objectValue); - Json::Value values(Json::arrayValue); - - row["colName"] = fq(_tableView->property("colName").toString()); - row["filter"] = fq(_tableView->property("filter").toString()); - row["extraCol"] = fq(_tableView->property("extraCol").toString()); - row["values"] = values; - - result.append(row); - return result; -} - -void BoundControlFilteredTableView::fillTableTerms(const Json::Value &value, ListModelTableViewBase::TableTerms &tableTerms) -{ - if (value.size() > 0) - { - const Json::Value& firstRow = value[Json::UInt(0)]; - - tableTerms.filter = tq(firstRow["filter"].asString()); - - tableTerms.values.push_back({}); - for (const Json::Value& value : firstRow["values"]) - tableTerms.values[0].push_back(value.asDouble()); - - tableTerms.colName = tq(firstRow["colName"].asString()); - - for (const Json::Value& value : firstRow["dataCols"]) - tableTerms.colNames.push_back(tq(value.asString())); - - const Json::Value& extraCol = firstRow["extraCol"]; - if (extraCol.isString()) - tableTerms.extraCol = tq(extraCol.asString()); - else if (extraCol.isArray() && extraCol.size() > 0) - tableTerms.extraCol = tq(extraCol[Json::UInt(0)].asString()); - - for (const Json::Value& value : firstRow["rowIndices"]) - tableTerms.rowIndices.push_back(value.asInt()); - } -} - -void BoundControlFilteredTableView::fillBoundValue(Json::Value &value, const ListModelTableViewBase::TableTerms &tableTerms) -{ - ListModelFilteredDataEntry* filteredModel = qobject_cast(_tableView->tableModel()); - - Json::Value row(Json::objectValue); - - Json::Value stdRowIndices(Json::arrayValue); - for (size_t index : filteredModel->filteredRowToData()) - stdRowIndices.append(static_cast(index + 1)); - - std::string colName = fq(filteredModel->colName()); - if (!colName.empty()) - row["colName"] = colName; - row["filter"] = fq(filteredModel->filter()); - row["rowIndices"] = stdRowIndices; - - Json::Value values(Json::arrayValue); - for (QVariant val : tableTerms.values[0]) - values.append(val.toDouble()); - row["values"] = values; - - Json::Value dataCols(Json::arrayValue); - for (const QString& dataCol : filteredModel->dataColumns()) - dataCols.append(fq(dataCol)); - row["dataCols"] = dataCols; - - Json::Value extraColJson(Json::arrayValue); - std::string extraCol = fq(filteredModel->extraCol()); - if (!extraCol.empty()) - extraColJson.append(extraCol); - row["extraCol"] = extraColJson; - - value.append(row); -} diff --git a/QMLComponents/boundcontrols/boundcontrolfilteredtableview.h b/QMLComponents/boundcontrols/boundcontrolfilteredtableview.h deleted file mode 100644 index abc076a7977..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolfilteredtableview.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLFILTEREDTABLEVIEW_H -#define BOUNDCONTROLFILTEREDTABLEVIEW_H - -#include "boundcontroltableview.h" - -class BoundControlFilteredTableView : public BoundControlTableView -{ -public: - BoundControlFilteredTableView(TableViewBase* tableView); - - Json::Value createJson() const override; - - void fillTableTerms(const Json::Value& value, ListModelTableViewBase::TableTerms& tableTerms) override; - void fillBoundValue(Json::Value& value, const ListModelTableViewBase::TableTerms& tableTerms) override; -}; - -#endif // BOUNDCONTROLFILTEREDTABLEVIEW_H diff --git a/QMLComponents/boundcontrols/boundcontrolgridtableview.cpp b/QMLComponents/boundcontrols/boundcontrolgridtableview.cpp deleted file mode 100644 index 10a0a23e2bc..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolgridtableview.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolgridtableview.h" -#include "controls/tableviewbase.h" - -BoundControlGridTableView::BoundControlGridTableView(TableViewBase* tableView) - : BoundControlTableView(tableView) -{ -} - -Json::Value BoundControlGridTableView::createJson() const -{ - Json::Value result(Json::arrayValue); - - ListModelTableViewBase* model = _tableView->tableModel(); - Terms terms = model->getSourceTerms(); - - Json::Value defaultValue = _defaultValue(); - - int maxColumn = _tableView->initialColumnCount(); - if (_tableView->minColumn() > maxColumn) maxColumn = _tableView->minColumn(); - if (_tableView->maxColumn() >= 0 && maxColumn > _tableView->maxColumn()) maxColumn = _tableView->maxColumn(); - int maxRow = _tableView->initialRowCount(); - if (_tableView->minRow() > maxRow) maxRow = _tableView->minRow(); - if (_tableView->maxRow() >= 0 && maxRow > _tableView->maxRow()) maxRow = _tableView->maxRow(); - - QList initValues; - for (const Term& term : terms) - { - const QStringList& rowValues = term.components(); - if (rowValues.length() > maxRow) maxRow = rowValues.length(); - initValues.append(rowValues); - } - if (initValues.length() > maxColumn) maxColumn = initValues.length(); - if (_tableView->maxColumn() >= 0 && maxColumn > _tableView->maxColumn()) maxColumn = _tableView->maxColumn(); - if (_tableView->maxRow() >= 0 && maxRow > _tableView->maxRow()) maxRow = _tableView->maxRow(); - - for (int rowNb = 0; rowNb < maxRow; rowNb++) - { - Json::Value levels(Json::arrayValue); - Json::Value values(Json::arrayValue); - - for (int colNb = 0; colNb < maxColumn; colNb++) - { - if (initValues.length() > colNb && initValues.at(colNb).length() > rowNb) values.append(fq(initValues.at(colNb).at(rowNb))); - else values.append(defaultValue); - levels.append(fq(_tableView->tableModel()->getDefaultColName(size_t(colNb)))); - } - - Json::Value row(Json::objectValue); - row["levels"] = levels; - row["name"] = fq(_tableView->tableModel()->getDefaultRowName(size_t(rowNb))); - row["values"] = values; - result.append(row); - } - - return result; -} diff --git a/QMLComponents/boundcontrols/boundcontrolgridtableview.h b/QMLComponents/boundcontrols/boundcontrolgridtableview.h deleted file mode 100644 index 4d2eb5f2983..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolgridtableview.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLGRIDTABLEVIEW_H -#define BOUNDCONTROLGRIDTABLEVIEW_H - -#include "boundcontroltableview.h" - -class BoundControlGridTableView : public BoundControlTableView -{ -public: - BoundControlGridTableView(TableViewBase* tableView); - - Json::Value createJson() const override; - -}; - -#endif // BOUNDCONTROLGRIDTABLEVIEW_H diff --git a/QMLComponents/boundcontrols/boundcontroljagstextarea.cpp b/QMLComponents/boundcontrols/boundcontroljagstextarea.cpp deleted file mode 100644 index a6a2baffd1d..00000000000 --- a/QMLComponents/boundcontrols/boundcontroljagstextarea.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontroljagstextarea.h" -#include "controls/textareabase.h" -#include "columnencoder.h" - -void BoundControlJAGSTextArea::bindTo(const Json::Value &value) -{ - if (value.type() != Json::objectValue) return; - BoundControlBase::bindTo(value); - - _textArea->setText(tq(value["modelOriginal"].asString())); - - checkSyntax(); - -} - -Json::Value BoundControlJAGSTextArea::createJson() const -{ - Json::Value result; - std::string text = _textArea->text().toStdString(); - - result["modelOriginal"] = text; - result["model"] = text; - result["columns"] = Json::Value(Json::arrayValue); - result["parameters"] = Json::Value(Json::arrayValue); - - return result; -} - -bool BoundControlJAGSTextArea::isJsonValid(const Json::Value &value) const -{ - if (!value.isObject()) return false; - if (!value["modelOriginal"].isString()) return false; - if (!value["model"].isString()) return false; - //if (!value["columns"].isArray()) return false; - //if (!value["parameters"].isArray()) return false; - - return true; -} - -void BoundControlJAGSTextArea::checkSyntax() -{ - QString text = _textArea->text(); - - // google: jags_user_manual (4.3.0) for documentation on JAGS symbols - - // get the column names of the data set - _usedColumnNames.clear(); - _textEncoded = tq(ColumnEncoder::columnEncoder()->encodeRScript(stringUtils::stripRComments(fq(text)), &_usedColumnNames)); - - QRegularExpression relationSymbol = QRegularExpression("<-|=|~"); - QStringList textByLine = _textEncoded.split(QRegularExpression(";|\n")); - _usedParameters.clear(); - - for (QString & line : textByLine) - { - // comments were already removed by stringUtils::stripRComments - if (line.contains(relationSymbol)) - { - // extract parameter and remove whitespace - QString paramName = line.split(relationSymbol).first().trimmed(); - // remove any link functions (cloglog|log|probit|logit) - if (paramName.contains("(") && paramName.contains(")")) - { - int idxStart, idxEnd; - idxStart = paramName.indexOf("(") + 1; - idxEnd = paramName.indexOf(")") - idxStart; - paramName = paramName.mid(idxStart, idxEnd); - } - - // get rid of any indexing - if (paramName.contains("[")) - paramName = paramName.left(paramName.indexOf("[")); - - if (paramName != "" && !ColumnEncoder::columnEncoder()->shouldDecode(fq(paramName))) - _usedParameters.insert(paramName); - - } - } - - Json::Value boundValue(Json::objectValue); - - boundValue["modelOriginal"] = text.toStdString(); - boundValue["model"] = _textEncoded.toStdString(); - Json::Value columns(Json::arrayValue); - for (const std::string& column : _usedColumnNames) - columns.append(ColumnEncoder::columnEncoder()->encode(column)); - boundValue["columns"] = columns; - Json::Value parameters(Json::arrayValue); - for (const QString& parameter : _usedParameters) - parameters.append(parameter.toStdString()); - boundValue["parameters"] = parameters; - - setBoundValue(boundValue); - - ListModelTermsAvailable* model = _textArea->availableModel(); - model->initTerms(_usedParameters.values()); -} - - diff --git a/QMLComponents/boundcontrols/boundcontroljagstextarea.h b/QMLComponents/boundcontrols/boundcontroljagstextarea.h deleted file mode 100644 index 565619c6300..00000000000 --- a/QMLComponents/boundcontrols/boundcontroljagstextarea.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLJAGSTEXTAREA_H -#define BOUNDCONTROLJAGSTEXTAREA_H - -#include "boundcontroltextarea.h" -#include - -class BoundControlJAGSTextArea : public BoundControlTextArea -{ -public: - BoundControlJAGSTextArea(TextAreaBase* textArea) : BoundControlTextArea(textArea) {} - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value &value) override; - - void checkSyntax() override; - -private: - std::set _usedColumnNames; - QSet _usedParameters; - QString _textEncoded; - -}; - -#endif // BOUNDCONTROLJAGSTEXTAREA_H diff --git a/QMLComponents/boundcontrols/boundcontrollavaantextarea.cpp b/QMLComponents/boundcontrols/boundcontrollavaantextarea.cpp deleted file mode 100644 index 4de9bdc5ed9..00000000000 --- a/QMLComponents/boundcontrols/boundcontrollavaantextarea.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrollavaantextarea.h" -#include "controls/textareabase.h" -#include "log.h" -#include "columnencoder.h" -#include "analysisform.h" -#include - -BoundControlLavaanTextArea::BoundControlLavaanTextArea(TextAreaBase *textArea) - : BoundControlTextArea(textArea) -{ - - QVariant textDocumentVariant = textArea->property("textDocument"); - QQuickTextDocument* textDocumentQQuick = textDocumentVariant.value(); - if (textDocumentQQuick) - { - QTextDocument* doc = textDocumentQQuick->textDocument(); - _lavaanHighlighter = new LavaanSyntaxHighlighter(doc); - //connect(doc, &QTextDocument::contentsChanged, this, &BoundQMLTextArea::contentsChangedHandler); - } - else - Log::log() << "No document object found!" << std::endl; -} - -void BoundControlLavaanTextArea::bindTo(const Json::Value &value) -{ - if (value.type() != Json::objectValue) return; - BoundControlBase::bindTo(value); - - _textArea->setText(tq(value["modelOriginal"].asString())); - - checkSyntax(); - -} - -Json::Value BoundControlLavaanTextArea::createJson() const -{ - Json::Value result; - std::string text = _textArea->text().toStdString(); - - result["modelOriginal"] = text; - result["model"] = text; - result["columns"] = Json::Value(Json::arrayValue); - - return result; -} - -bool BoundControlLavaanTextArea::isJsonValid(const Json::Value &value) const -{ - if (!value.isObject()) return false; - if (!value["modelOriginal"].isString()) return false; - //If we have modelOriginal the rest follows automatically because of checkSyntax and the result - //if (!value["model"].isString()) return false; - //if (!value["columns"].isArray()) return false; - - return true; -} - -void BoundControlLavaanTextArea::checkSyntax() -{ - QString text = _textArea->text(); - - // get the column names of the data set - _usedColumnNames.clear(); - _textEncoded = tq(ColumnEncoder::columnEncoder()->encodeRScript(stringUtils::stripRComments(fq(text)), &_usedColumnNames)); - - // Create R code string - QString encodedColNames = "c("; - for (const std::string& column : _usedColumnNames) - { - encodedColNames.append("'" + tq(ColumnEncoder::columnEncoder()->encode(column)) + "'"); - if (column != *_usedColumnNames.rbegin()) // avoid trailing , - encodedColNames.append(", "); - } - encodedColNames.append(")"); - - QString checkCode = tq(_checkSyntaxRFunctionName()); - checkCode - .append("('") - .append(_textEncoded) - .append("', ") - .append(encodedColNames) - .append(")"); - - _textArea->runRScript(checkCode, false); - -} - -QString BoundControlLavaanTextArea::rScriptDoneHandler(const QString & result) -{ - if (!result.isEmpty()) - return result; - - Json::Value boundValue(Json::objectValue); - - boundValue["modelOriginal"] = _textArea->text().toStdString(); - boundValue["model"] = _textEncoded.toStdString(); - - Json::Value columns(Json::arrayValue); - for (const std::string& column : _usedColumnNames) - columns.append(ColumnEncoder::columnEncoder()->encode(column)); - - boundValue["columns"] = columns; - - setBoundValue(boundValue, !_control->form()->wasUpgraded()); - - return QString(); - -} diff --git a/QMLComponents/boundcontrols/boundcontrollavaantextarea.h b/QMLComponents/boundcontrols/boundcontrollavaantextarea.h deleted file mode 100644 index bdcc78e79d4..00000000000 --- a/QMLComponents/boundcontrols/boundcontrollavaantextarea.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLLAVAANTEXTAREA_H -#define BOUNDCONTROLLAVAANTEXTAREA_H - -#include "boundcontroltextarea.h" -#include "controls/lavaansyntaxhighlighter.h" - -class BoundControlLavaanTextArea : public BoundControlTextArea -{ -public: - BoundControlLavaanTextArea(TextAreaBase* textArea); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value &value) override; - - void checkSyntax() override; - QString rScriptDoneHandler(const QString &result) override; - -protected: - LavaanSyntaxHighlighter* _lavaanHighlighter = nullptr; - - std::set _usedColumnNames; - QString _textEncoded; - virtual const char * _checkSyntaxRFunctionName() { return "jaspSem:::checkLavaanModel"; } - -}; - -#endif // BOUNDCONTROLLAVAANTEXTAREA_H diff --git a/QMLComponents/boundcontrols/boundcontrollayers.cpp b/QMLComponents/boundcontrols/boundcontrollayers.cpp deleted file mode 100644 index 5a18b863b2d..00000000000 --- a/QMLComponents/boundcontrols/boundcontrollayers.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrollayers.h" -#include "models/listmodellayersassigned.h" -#include "controls/jasplistcontrol.h" -#include "analysisform.h" -#include "qutils.h" - -using namespace std; - - -BoundControlLayers::BoundControlLayers(ListModelLayersAssigned* model) : BoundControlBase(model->listView()) -{ - _layersModel = model; -} - -void BoundControlLayers::bindTo(const Json::Value &value) -{ - BoundControlBase::bindTo(value); - vector > variables; - - for (const Json::Value& row : value) - { - const Json::Value& rowVariables = row["variables"]; - vector rowValues; - - if (rowVariables.isString()) - rowValues.push_back(rowVariables.asString()); - else if (rowVariables.isArray()) - { - for (const Json::Value& rowVariable : rowVariables) - rowValues.push_back(rowVariable.asString()); - } - - variables.push_back(rowValues); - } - - _layersModel->initLayers(variables); - -} - -Json::Value BoundControlLayers::createJson() const -{ - return Json::Value(Json::arrayValue); -} - -bool BoundControlLayers::isJsonValid(const Json::Value &optionValue) const -{ - bool valid = optionValue.type() == Json::arrayValue; - if (valid) - { - for (uint i = 0; i < optionValue.size(); i++) - { - const Json::Value& value = optionValue[i]; - valid = value.type() == Json::objectValue; - if (valid) - { - const Json::Value& nameOption = value["name"]; - const Json::Value& variablesOption = value["variables"]; - valid = nameOption.type() == Json::stringValue && variablesOption.type() == Json::arrayValue; - - if (!valid) - break; - } - } - } - - return valid; -} - -void BoundControlLayers::resetBoundValue() -{ - vector > > layers = _layersModel->getLayers(); - Json::Value boundValue(Json::arrayValue); - - for (const auto &layer : layers) - { - Json::Value rowValues(Json::objectValue); - rowValues["name"] = layer.first; - - Json::Value rowVariables(Json::arrayValue); - for (const string &variable : layer.second) - rowVariables.append(variable); - rowValues["variables"] = rowVariables; - boundValue.append(rowValues); - } - - setBoundValue(boundValue); -} diff --git a/QMLComponents/boundcontrols/boundcontrollayers.h b/QMLComponents/boundcontrols/boundcontrollayers.h deleted file mode 100644 index 120c8a32cbc..00000000000 --- a/QMLComponents/boundcontrols/boundcontrollayers.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLLAYERS_H -#define BOUNDCONTROLLAYERS_H - -#include "boundcontrolbase.h" - -class ListModelLayersAssigned; - -class BoundControlLayers : public BoundControlBase -{ - -public: - BoundControlLayers(ListModelLayersAssigned* model); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value &value) override; - void resetBoundValue() override; - -private: - ListModelLayersAssigned* _layersModel = nullptr; - -}; - -#endif // BOUNDCONTROLLAYERS_H diff --git a/QMLComponents/boundcontrols/boundcontrolmeasurescells.cpp b/QMLComponents/boundcontrols/boundcontrolmeasurescells.cpp deleted file mode 100644 index 589234ad1cf..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolmeasurescells.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolmeasurescells.h" -#include "models/listmodelmeasurescellsassigned.h" -#include "models/listmodelfactorlevels.h" -#include "controls/jasplistcontrol.h" -#include "analysisform.h" -#include "qutils.h" - -#include - -using namespace std; - - -BoundControlMeasuresCells::BoundControlMeasuresCells(ListModelMeasuresCellsAssigned* model) : BoundControlBase(model->listView()) -{ - _measuresCellsModel = model; -} - -void BoundControlMeasuresCells::bindTo(const Json::Value &value) -{ - BoundControlBase::bindTo(value); - - Terms variables; - - for (const Json::Value& variable : value) - variables.add(variable.asString()); - _measuresCellsModel->initLevels(getLevels(), variables, true); -} - -Terms BoundControlMeasuresCells::getLevels() const -{ - Terms levels; - for (ListModelFactorLevels* factorsModel : _sourceFactorsModels) - levels.add(factorsModel->getLevels()); - - return levels; -} - -Json::Value BoundControlMeasuresCells::createJson() const -{ - Json::Value result(Json::arrayValue); - size_t nbLevels = getLevels().size(); - - for (int i = 0; i < nbLevels; i++) - result.append(""); - - return result; -} - -bool BoundControlMeasuresCells::isJsonValid(const Json::Value &optionValue) const -{ - return optionValue.type() == Json::arrayValue; -} - -void BoundControlMeasuresCells::addFactorModel(ListModelFactorLevels *factorModel) -{ - _sourceFactorsModels.push_back(factorModel); -} - -void BoundControlMeasuresCells::resetBoundValue() -{ - Json::Value boundValue(Json::arrayValue); - const Terms& terms = _measuresCellsModel->terms(); - - for (const Term& term : terms) - boundValue.append(term.asString()); - - setBoundValue(boundValue); -} diff --git a/QMLComponents/boundcontrols/boundcontrolmeasurescells.h b/QMLComponents/boundcontrols/boundcontrolmeasurescells.h deleted file mode 100644 index 6bbcd9bc940..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolmeasurescells.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLMEASURESCELLS_H -#define BOUNDCONTROLMEASURESCELLS_H - -#include "boundcontrolbase.h" -#include "models/listmodelfactorlevels.h" - -class ListModelMeasuresCellsAssigned; - -class BoundControlMeasuresCells : public BoundControlBase -{ - -public: - BoundControlMeasuresCells(ListModelMeasuresCellsAssigned* model); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value &value) override; - void resetBoundValue() override; - - void addFactorModel(ListModelFactorLevels* factorModel); - Terms getLevels() const; - -private: - ListModelMeasuresCellsAssigned* _measuresCellsModel; - QList _sourceFactorsModels; - - void _initLevels(); -}; - -#endif // BOUNDCONTROLMEASURESCELLS_H diff --git a/QMLComponents/boundcontrols/boundcontrolmultiterms.cpp b/QMLComponents/boundcontrols/boundcontrolmultiterms.cpp deleted file mode 100644 index a07493dd2e7..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolmultiterms.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolmultiterms.h" -#include "controls/jasplistcontrol.h" -#include "models/listmodelmultitermsassigned.h" - -BoundControlMultiTerms::BoundControlMultiTerms(ListModelMultiTermsAssigned* listModel) : BoundControlBase(listModel->listView()) -{ - _listModel = listModel; -} - -void BoundControlMultiTerms::bindTo(const Json::Value& value) -{ - BoundControlBase::bindTo(value); - - std::vector > values; - - for (const Json::Value& rowJson : value) - { - std::vector rowValues; - if (rowJson.isArray()) - { - for (const Json::Value& val : rowJson) - rowValues.push_back(val.asString()); - } else if (rowJson.isString()) - rowValues.push_back(rowJson.asString()); - - values.push_back(rowValues); - } - - _listModel->initTerms(values); -} - -Json::Value BoundControlMultiTerms::createJson() const -{ - return Json::Value(Json::arrayValue); -} - -bool BoundControlMultiTerms::isJsonValid(const Json::Value &optionValue) const -{ - return optionValue.type() == Json::arrayValue; -} - -void BoundControlMultiTerms::resetBoundValue() -{ - const QList& tuples = _listModel->tuples(); - Json::Value boundValue(Json::arrayValue); - for (const Terms& terms : tuples) - { - Json::Value rowValue; - for (std::string val : terms.asVector()) - rowValue.append(val); - boundValue.append(rowValue); - } - - setBoundValue(boundValue); -} diff --git a/QMLComponents/boundcontrols/boundcontrolmultiterms.h b/QMLComponents/boundcontrols/boundcontrolmultiterms.h deleted file mode 100644 index f7fa41bbcc8..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolmultiterms.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLMULTITERMS_H -#define BOUNDCONTROLMULTITERMS_H - -#include "boundcontrolbase.h" - -class ListModelMultiTermsAssigned; - -class BoundControlMultiTerms : public BoundControlBase -{ -public: - BoundControlMultiTerms(ListModelMultiTermsAssigned* listModel); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value &value) override; - void resetBoundValue() override; - - -private: - ListModelMultiTermsAssigned* _listModel; -}; - -#endif // BOUNDCONTROLMULTITERMS_H diff --git a/QMLComponents/boundcontrols/boundcontrolsourcetextarea.cpp b/QMLComponents/boundcontrols/boundcontrolsourcetextarea.cpp deleted file mode 100644 index 1961eca4f57..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolsourcetextarea.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolsourcetextarea.h" -#include "controls/textareabase.h" - -void BoundControlSourceTextArea::bindTo(const Json::Value &value) -{ - BoundControlTextArea::bindTo(value); - - _setSourceTerms(); -} - -void BoundControlSourceTextArea::checkSyntax() -{ - BoundControlTextArea::checkSyntax(); - _setSourceTerms(); -} - -void BoundControlSourceTextArea::_setSourceTerms() -{ - QStringList list = {_textArea->text()}; - for (const QString& separator : _textArea->separators()) - { - QStringList newList; - for (const QString& listPart : list) - newList.append(listPart.split(separator, Qt::SkipEmptyParts)); - list = newList; - } - - QStringList terms; - - for (const QString& term : list) - terms.append(term.trimmed()); - _textArea->model()->initTerms(terms); -} diff --git a/QMLComponents/boundcontrols/boundcontrolsourcetextarea.h b/QMLComponents/boundcontrols/boundcontrolsourcetextarea.h deleted file mode 100644 index f05f4c0aea9..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolsourcetextarea.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLSOURCETEXTAREA_H -#define BOUNDCONTROLSOURCETEXTAREA_H - -#include "boundcontroltextarea.h" - -class BoundControlSourceTextArea : public BoundControlTextArea -{ -public: - BoundControlSourceTextArea(TextAreaBase* textArea) - : BoundControlTextArea(textArea) {} - - void bindTo(const Json::Value &value) override; - void checkSyntax() override; - -protected: - void _setSourceTerms(); - -}; - -#endif // BOUNDCONTROLSOURCETEXTAREA_H diff --git a/QMLComponents/boundcontrols/boundcontroltableview.cpp b/QMLComponents/boundcontrols/boundcontroltableview.cpp deleted file mode 100644 index 97c9d86cdaf..00000000000 --- a/QMLComponents/boundcontrols/boundcontroltableview.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontroltableview.h" -#include "controls/tableviewbase.h" -#include "models/listmodeltableviewbase.h" - -BoundControlTableView::BoundControlTableView(TableViewBase* tableView) - : BoundControlBase(tableView), _tableView(tableView) -{ -} - -bool BoundControlTableView::isJsonValid(const Json::Value &value) const -{ - return value.isArray(); -} - -Json::Value BoundControlTableView::createJson() const -{ - Json::Value result(Json::arrayValue); - - Terms terms = _tableView->model()->getSourceTerms(); - - Json::Value levels(Json::arrayValue); - - for (const Term& term : terms) - levels.append(term.asString()); - - for (int row = int(terms.size()); row < _tableView->initialRowCount(); row++) - levels.append(fq(_tableView->tableModel()->getDefaultRowName(size_t(row)))); - - for (int colIndex = 0; colIndex < _tableView->initialColumnCount(); colIndex++) - { - Json::Value row(Json::objectValue); - row["levels"] = levels; - row["name"] = fq(_tableView->tableModel()->getDefaultColName(size_t(colIndex))); - - Json::Value values(Json::arrayValue); - for (int rowIndex = 0; rowIndex < int(levels.size()); rowIndex++) - values.append(_defaultValue(colIndex, rowIndex)); - - row["values"] = values; - result.append(row); - } - - return result; -} - -void BoundControlTableView::fillTableTerms(const Json::Value &value, ListModelTableViewBase::TableTerms &tableTerms ) -{ - int index = 0; - - for (const Json::Value& row : value) - { - tableTerms.colNames.push_back(tq(row["name"].asString())); - if (index == 0) - { - for (const Json::Value& level : row["levels"]) - tableTerms.rowNames.push_back(tq(level.asString())); - } - tableTerms.values.push_back({}); - for (const Json::Value& value : row["values"]) - { - QVariant val; - if (value.isInt()) val = value.asInt(); - else if (value.isDouble()) val = value.asDouble(); - else if (value.isString()) val = tq(value.asString()); - tableTerms.values[tableTerms.values.size() - 1].push_back(val); - } - - if (_tableView->tableModel()->isRCodeColumn(index)) - setIsRCode("values"); - index++; - } - -} - -void BoundControlTableView::bindTo(const Json::Value &value) -{ - BoundControlBase::bindTo(value); - - ListModelTableViewBase::TableTerms tableTerms; - QMap extra; - - fillTableTerms(value, tableTerms); - - _tableView->tableModel()->initTableTerms(tableTerms); -} - -void BoundControlTableView::fillBoundValue(Json::Value &boundValue, const ListModelTableViewBase::TableTerms &tableTerms) -{ - Json::Value levels(Json::arrayValue); - for (const QString& rowName : tableTerms.rowNames) - levels.append(fq(rowName)); - - for (int colIndex = 0; colIndex < tableTerms.colNames.size(); colIndex++) - { - Json::Value row(Json::objectValue); - row["name"] = fq(tableTerms.colNames[colIndex]); - row["levels"] = levels; - - Json::Value values(Json::arrayValue); - for (const QVariant& val : tableTerms.values[colIndex]) - { - if (val.typeId() == QMetaType::Int) values.append(val.toInt()); - else if (val.typeId() == QMetaType::Double) values.append(val.toDouble()); - else values.append(fq(val.toString())); - } - row["values"] = values; - - boundValue.append(row); - } -} - -Json::Value BoundControlTableView::_defaultValue(int colIndex, int rowIndex) const -{ - Json::Value result; - QVariant defaultValue = _tableView->defaultValue(colIndex, rowIndex); - - JASPControl::ItemType itemType = _tableView->itemTypePerItem(colIndex, rowIndex); - - if (itemType == JASPControl::ItemType::Double) - result = defaultValue.toDouble(); - else if (itemType == JASPControl::ItemType::Integer) - result = defaultValue.toInt(); - else - result = fq(defaultValue.toString()); - - return result; -} - -void BoundControlTableView::resetBoundValue() -{ - Json::Value boundValue(Json::arrayValue); - const ListModelTableViewBase::TableTerms& tableTerms = _tableView->tableModel()->tableTerms(); - - fillBoundValue(boundValue, tableTerms); - - setBoundValue(boundValue); -} diff --git a/QMLComponents/boundcontrols/boundcontroltableview.h b/QMLComponents/boundcontrols/boundcontroltableview.h deleted file mode 100644 index fd4b1a749b7..00000000000 --- a/QMLComponents/boundcontrols/boundcontroltableview.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLTABLEVIEW_H -#define BOUNDCONTROLTABLEVIEW_H - -#include "boundcontrolbase.h" -#include "models/listmodeltableviewbase.h" - -class TableViewBase; - -class BoundControlTableView : public BoundControlBase -{ -public: - BoundControlTableView(TableViewBase* tableView); - - bool isJsonValid(const Json::Value& value) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - void resetBoundValue() override; - -protected: - virtual void fillTableTerms(const Json::Value& value, ListModelTableViewBase::TableTerms& tableTerms); - virtual void fillBoundValue(Json::Value& value, const ListModelTableViewBase::TableTerms& tableTerms); - Json::Value _defaultValue(int colIndex = -1, int rowIndex = -1) const; - - TableViewBase * _tableView = nullptr; -}; - -#endif // BOUNDCONTROLTABLEVIEW_H diff --git a/QMLComponents/boundcontrols/boundcontrolterms.cpp b/QMLComponents/boundcontrols/boundcontrolterms.cpp deleted file mode 100644 index 7e9856c88fa..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolterms.cpp +++ /dev/null @@ -1,377 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontrolterms.h" -#include "controls/variableslistbase.h" -#include "log.h" -#include "analysisform.h" -#include "models/listmodeltermsavailable.h" -#include "models/listmodeltermsassigned.h" -#include "models/listmodelinteractionassigned.h" -#include "controls/rowcontrols.h" - -BoundControlTerms::BoundControlTerms(ListModelAssignedInterface* listModel, bool isSingleRow) : BoundControlBase(listModel->listView()) -{ - _termsModel = listModel; - _listView = qobject_cast(_control); - _isSingleRow = isSingleRow; - _optionKey = _listView->optionKey().toStdString(); -} - - -// For interaction model, if there is no row component, the R Syntax tries to simplify the option value -// The right json value is an array of abjects of array of strings, like this: -// [ -// { -// : [ value1 ] -// } -// { -// : [ component1, component2] // In case of interaction, a value is composed by 2 components. -// } -// ] -// -// But with R syntax, an array of strings, or an array of array of strings is allowed (the optionKey is not necessary, since no other key is used): -// [ -// value1, -// [ component1, component2] -// ] -// -Json::Value BoundControlTerms::_adjustBindingValue(const Json::Value &value) const -{ - Json::Value valueAdjusted = value; - - if (!_listView->hasRowComponent() && _listView->containsInteractions() && value.isArray()) - { - valueAdjusted = Json::Value(Json::arrayValue); - for (const Json::Value& aValue : value) - { - if (aValue.isObject()) - valueAdjusted.append(aValue); - else - { - Json::Value row(Json::objectValue); - Json::Value keyValue(Json::arrayValue); - if (aValue.isString()) - keyValue.append(aValue); - else if (aValue.isArray()) - { - for (const Json::Value& comp : aValue) - { - if (comp.isString()) - keyValue.append(comp); - else - Log::log() << "Wrong Json type when binding " << getName() << ": " << value.toStyledString() << std::endl; - } - } - else - Log::log() << "Wrong Json type when binding " << getName() << ": " << value.toStyledString() << std::endl; - - row[_optionKey] = keyValue; - valueAdjusted.append(row); - } - } - } - - return valueAdjusted; -} - -void BoundControlTerms::bindTo(const Json::Value &value) -{ - Json::Value valueAdjusted = _adjustBindingValue(value); - - Terms terms; - ListModel::RowControlsValues allControlValues; - - if (_listView->hasRowComponent() || _listView->containsInteractions()) - _readTableValue(valueAdjusted, _optionKey, _listView->containsInteractions(), terms, allControlValues); - else - { - if (valueAdjusted.isArray()) - { - for (const Json::Value& variable : valueAdjusted) - terms.add(Term(variable.asString())); - } - else if (valueAdjusted.isString()) - { - std::string str = valueAdjusted.asString(); - if (!str.empty()) - terms.add(Term(str)); - } - else - Log::log() << "Control " << _control->name() << " is bound with a value that is neither an array, an object bor a string :" << valueAdjusted.toStyledString() << std::endl; - } - - ListModelAssignedInterface* assignedModel = qobject_cast(_listView->model()); - if (assignedModel && !assignedModel->checkAllowedTerms(terms)) - valueAdjusted = addTermsToOption(Json::Value::null, terms); - - BoundControlBase::bindTo(valueAdjusted); - - _termsModel->initTerms(terms, allControlValues); -} - -Json::Value BoundControlTerms::createJson() const -{ - const Terms& terms = _termsModel->terms(); - - if (_listView->containsInteractions() || _listView->hasRowComponent()) - { - Json::Value jsonValue(Json::arrayValue); - for (const Term& term : terms) - { - Json::Value row(Json::objectValue); - if (_listView->containsInteractions()) - { - Json::Value keyValue(Json::arrayValue); - for (const std::string& comp : term.scomponents()) - keyValue.append(comp); - row[_optionKey] = keyValue; - } - else - { - Json::Value keyValue(term.asString()); - row[_optionKey] = keyValue; - } - - if (_listView->hasRowComponent()) - { - auto allRowControls = _termsModel->getAllRowControls(); - if (allRowControls.contains(term.asQString())) - { - RowControls* rowControls = allRowControls[term.asQString()]; - const QMap& controlsMap = rowControls->getJASPControlsMap(); - for (const QString& controlName : controlsMap.keys()) - { - JASPControl* control = controlsMap[controlName]; - BoundControl* boundControl = control->boundControl(); - if (boundControl) - row[fq(controlName)] = boundControl->createJson(); - } - } - } - jsonValue.append(row); - } - - return jsonValue; - } - else if (_isSingleRow) - { - if (terms.size() > 0) return Json::Value(terms.at(0).asString()); - else return Json::Value(""); - } - else - { - Json::Value jsonValue(Json::arrayValue); - for (const Term& term : terms) - jsonValue.append(term.asString()); - return jsonValue; - } -} - -bool BoundControlTerms::isJsonValid(const Json::Value &optionValue) const -{ - bool valid = true; - if (_listView->hasRowComponent() || _listView->containsInteractions()) - { - valid = optionValue.type() == Json::arrayValue; - if (valid) - { - for (uint i = 0; i < optionValue.size(); i++) - { - const Json::Value& value = optionValue[i]; - - if (!_listView->hasRowComponent() && (value.type() == Json::stringValue || value.type() == Json::arrayValue)) - { - // If there is no row component, allow stringValue (only one value) or arrayValue (for several values) - valid = true; - } - else if (value.type() == Json::objectValue) - { - const Json::Value& components = value[_optionKey]; - valid = components.type() == Json::arrayValue || components.type() == Json::stringValue; - } - if (!valid) - { - Log::log() << "Wrong type: " << value.toStyledString() << std::endl; - break; - } - } - } - } - else if (_isSingleRow) - valid = optionValue.type() == Json::stringValue; - else - { - valid = optionValue.type() == Json::arrayValue; - if (valid) - { - for (uint i = 0; i < optionValue.size(); i++) - { - const Json::Value& value = optionValue[i]; - valid = value.type() == Json::stringValue; - if (!valid) - break; - } - } - } - - return valid; -} - -void BoundControlTerms::resetBoundValue() -{ - const Terms& terms = _termsModel->terms(); - - if (_listView->hasRowComponent() || _listView->containsInteractions()) - _setTableValue(terms, _termsModel->getTermsWithComponentValues(), _optionKey, _listView->containsInteractions()); - else if (_isSingleRow) - { - std::string str = terms.size() > 0 ? terms[0].asString() : ""; - Json::Value boundValue(str); - setBoundValue(boundValue); - } - else - { - Json::Value boundValue(Json::arrayValue); - for (const Term& term : terms) - boundValue.append(term.asString()); - setBoundValue(boundValue); - } -} - -Json::Value BoundControlTerms::addTermsToOption(const Json::Value &option, const Terms &terms, const ListModel::RowControlsValues &extraTermsMap) const -{ - Json::Value result = option; - Terms termsAlreadyInOptions = _getValuesFromOptions(option); - - if (_listView->hasRowComponent() || _listView->containsInteractions()) - { - Terms termsToAdd; - for (const Term& term : terms) - { - if (!termsAlreadyInOptions.contains(term)) - continue; // Don't add term that is already in option. - - termsToAdd.add(term); - } - - for (const Term& term : terms) - { - if (termsAlreadyInOptions.contains(term)) - continue; // Don't add term that is already in option. - - Json::Value rowValues(Json::objectValue); - if (_listView->containsInteractions()) - { - Json::Value keyValue(Json::arrayValue); - for (const std::string& comp : term.scomponents()) - keyValue.append(comp); - rowValues[_optionKey] = keyValue; - } - else - { - Json::Value keyValue(term.asString()); - rowValues[_optionKey] = keyValue; - } - - QString termStr = term.asQString(); - if (extraTermsMap.contains(termStr)) - { - const QMap& controlsMap = extraTermsMap[termStr]; - QMapIterator it(controlsMap); - while (it.hasNext()) - { - it.next(); - rowValues[fq(it.key())] = it.value(); - } - } - result.append(rowValues); - } - } - else if (_isSingleRow) - result = terms.size() > 0 ? terms[0].asString() : ""; - - else - for (const Term& term : terms) - if (!termsAlreadyInOptions.contains(term)) - result.append(term.asString()); - - return result; -} - -bool BoundControlTerms::areTermsInOption(const Json::Value &option, Terms &terms) const -{ - if (terms.size() == 0) return false; - - bool result = true; - Terms termsInOptions = _getValuesFromOptions(option); - Terms termsToSearch = terms; - - for (const Term& term : termsToSearch) - if (termsInOptions.contains(term)) terms.remove(term); - else result = false; - - return result; -} - -Terms BoundControlTerms::_getValuesFromOptions(const Json::Value& option) const -{ - Terms result; - - if (_listView->hasRowComponent() || _listView->containsInteractions()) - { - if (!option.isArray()) - return result; // Just to be sure - - for (const Json::Value& row : option) - if (_listView->containsInteractions()) - { - if (row.isArray()) - { - std::vector term; - for (const Json::Value& val : row) - if (val.isString()) - term.push_back(val.asString()); - - result.add(Term(term)); - } - } - else if (row.isString()) - result.add(row.asString()); - - } - else if (_isSingleRow) - { - if (!option.isString()) - return result; // Just to be sure - result.add(option.asString()); - } - else - { - if (!option.isArray()) - return result; - - for (const Json::Value& row : option) - if (row.isString()) - result.add(row.asString()); - } - - return result; -} - - diff --git a/QMLComponents/boundcontrols/boundcontrolterms.h b/QMLComponents/boundcontrols/boundcontrolterms.h deleted file mode 100644 index 9ddbf8f77c7..00000000000 --- a/QMLComponents/boundcontrols/boundcontrolterms.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDQMLLISTVIEWTERMS_H -#define BOUNDQMLLISTVIEWTERMS_H - -#include "boundcontrolbase.h" -#include "models/listmodelassignedinterface.h" - -class BoundControlTerms : public BoundControlBase -{ - -public: - BoundControlTerms(ListModelAssignedInterface* listModel, bool isSingleRow = false); - - bool isJsonValid(const Json::Value& value) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value &value) override; - void resetBoundValue() override; - - Json::Value addTermsToOption(const Json::Value &option, const Terms &terms, const ListModel::RowControlsValues &extraTermsMap = {}) const; - bool areTermsInOption(const Json::Value& option, Terms& terms) const; - -private: - Terms _getValuesFromOptions(const Json::Value& option) const; - Json::Value _adjustBindingValue(const Json::Value &value) const; - - - ListModelAssignedInterface* _termsModel = nullptr; - JASPListControl* _listView = nullptr; - bool _isSingleRow = false; - std::string _optionKey; -}; - -#endif // BOUNDQMLLISTVIEWTERMS_H diff --git a/QMLComponents/boundcontrols/boundcontroltextarea.cpp b/QMLComponents/boundcontrols/boundcontroltextarea.cpp deleted file mode 100644 index 3178ea33196..00000000000 --- a/QMLComponents/boundcontrols/boundcontroltextarea.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "boundcontroltextarea.h" -#include "controls/textareabase.h" -#include "r_functionwhitelist.h" - -BoundControlTextArea::BoundControlTextArea(TextAreaBase* textArea) - : BoundControlBase(textArea), _textArea(textArea) -{ -} - -void BoundControlTextArea::bindTo(const Json::Value &value) -{ - BoundControlBase::bindTo(value); - _textArea->setText(tq(value.asString())); -} - -bool BoundControlTextArea::isJsonValid(const Json::Value &optionValue) const -{ - return optionValue.type() == Json::stringValue; -} - -Json::Value BoundControlTextArea::createJson() const -{ - return Json::Value(_textArea->text().toStdString()); -} - -void BoundControlTextArea::checkSyntax() -{ - QString text = _textArea->text(); - JASPControl::TextType textType = _textArea->textType(); - - if (textType == JASPControl::TextType::TextTypeRcode) - { - setIsRCode(); - try - { - R_FunctionWhiteList::scriptIsSafe(text.toStdString()); - _textArea->setHasScriptError(false); - _textArea->setProperty("infoText", QObject::tr("valid R code")); - } - catch(filterException & e) - { - _textArea->setHasScriptError(true); - std::string errorMessage(e.what()); - _textArea->setProperty("infoText", errorMessage.c_str()); - } - } - - setBoundValue(fq(text)); -} diff --git a/QMLComponents/boundcontrols/boundcontroltextarea.h b/QMLComponents/boundcontrols/boundcontroltextarea.h deleted file mode 100644 index 4bba1045601..00000000000 --- a/QMLComponents/boundcontrols/boundcontroltextarea.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef BOUNDCONTROLTEXTAREA_H -#define BOUNDCONTROLTEXTAREA_H - -#include "boundcontrolbase.h" - -class TextAreaBase; - -class BoundControlTextArea : public BoundControlBase -{ -public: - friend TextAreaBase; - - BoundControlTextArea(TextAreaBase* textArea); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - - virtual void checkSyntax(); - virtual QString rScriptDoneHandler(const QString &result) { throw std::runtime_error("runRScript done but handler not implemented!\nImplement an override for RScriptDoneHandler!\nResult was: " + result.toStdString()); }; - -protected: - TextAreaBase* _textArea = nullptr; -}; - -#endif // BOUNDCONTROLTEXTAREA_H diff --git a/QMLComponents/components/JASP/Controls/AddColumnField.qml b/QMLComponents/components/JASP/Controls/AddColumnField.qml deleted file mode 100644 index c08c23ab463..00000000000 --- a/QMLComponents/components/JASP/Controls/AddColumnField.qml +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP.Controls 1.0 -import JASP 1.0 - -TextField -{ - inputType: "addColumn" - - property int columnType: columnTypeScale //Or columnTypeNominal, columnTypeNominalText or columnTypeOrdinal -} diff --git a/QMLComponents/components/JASP/Controls/AssignButton.qml b/QMLComponents/components/JASP/Controls/AssignButton.qml deleted file mode 100644 index 8df82419f75..00000000000 --- a/QMLComponents/components/JASP/Controls/AssignButton.qml +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.11 - -Button -{ - id: button - - property var leftSource - property var rightSource - property bool leftToRight: true - - property var sourceM: leftToRight ? leftSource : rightSource - property var targetM: leftToRight ? rightSource : leftSource - - readonly property string iconToLeft: jaspTheme.iconPath + "arrow-left.png" - readonly property string iconToRight: jaspTheme.iconPath + "arrow-right.png" - - Connections - { - target: sourceM && sourceM.model? sourceM.model : null - function onSelectedItemsTypesChanged() { Qt.callLater(setState); } - } - - Connections - { - target: targetM && targetM.model ? targetM.model : null - function onSelectedItemsTypesChanged() { Qt.callLater(setState); } - } - - text: "" - enabled: false - visible: sourceM.visible && targetM.visible - - iconSource: leftToRight ? iconToRight : iconToLeft - - control.buttonPadding: 2 - control.implicitWidth: 40 * preferencesModel.uiScale - control.implicitHeight: 20 * preferencesModel.uiScale - - onClicked: sourceM.moveSelectedItems(targetM) - - function setIconToRight() { if (leftSource.activeFocus) leftToRight = true; setState(); } - function setIconToLeft() { if (rightSource.activeFocus) leftToRight = false; setState(); } - function setState() - { - enabled = sourceM.enabled && targetM.enabled && sourceM.model && sourceM.model.selectedItems().length > 0 && targetM.areTypesAllowed(sourceM.model.selectedItemsTypes()); - } - - -} diff --git a/QMLComponents/components/JASP/Controls/AssignedPairsVariablesList.qml b/QMLComponents/components/JASP/Controls/AssignedPairsVariablesList.qml deleted file mode 100644 index 7e6e673c3b9..00000000000 --- a/QMLComponents/components/JASP/Controls/AssignedPairsVariablesList.qml +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import JASP 1.0 - -VariablesList -{ - listViewType : JASP.AssignedVariables - dropMode : JASP.DropReplace - showElementBorder : true - columns : 2 - showVariableTypeIcon : false -} diff --git a/QMLComponents/components/JASP/Controls/AssignedRepeatedMeasuresCells.qml b/QMLComponents/components/JASP/Controls/AssignedRepeatedMeasuresCells.qml deleted file mode 100644 index 9a1e7ae5ace..00000000000 --- a/QMLComponents/components/JASP/Controls/AssignedRepeatedMeasuresCells.qml +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import JASP 1.0 - -VariablesList -{ - listViewType : JASP.RepeatedMeasures - dropMode : JASP.DropReplace - showElementBorder : true - columns : 2 - showVariableTypeIcon : false - suggestedColumns : ["scale"] - height : 140 -} diff --git a/QMLComponents/components/JASP/Controls/AssignedVariablesList.qml b/QMLComponents/components/JASP/Controls/AssignedVariablesList.qml deleted file mode 100644 index f78d5cadfda..00000000000 --- a/QMLComponents/components/JASP/Controls/AssignedVariablesList.qml +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import JASP 1.0 - -VariablesList -{ - listViewType: JASP.AssignedVariables - dropMode: JASP.DropInsert -} diff --git a/QMLComponents/components/JASP/Controls/AvailableVariablesList.qml b/QMLComponents/components/JASP/Controls/AvailableVariablesList.qml deleted file mode 100644 index 250a7a7f82e..00000000000 --- a/QMLComponents/components/JASP/Controls/AvailableVariablesList.qml +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import JASP 1.0 - -VariablesList -{ - listViewType: JASP.AvailableVariables - showSortMenu: true - isBound: false -} diff --git a/QMLComponents/components/JASP/Controls/BasicThreeButtonTableView.qml b/QMLComponents/components/JASP/Controls/BasicThreeButtonTableView.qml deleted file mode 100644 index 633eec3265b..00000000000 --- a/QMLComponents/components/JASP/Controls/BasicThreeButtonTableView.qml +++ /dev/null @@ -1,152 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.0 -import QtQuick.Layouts 1.11 -import JASP.Controls 1.0 - -Item -{ - id : basicButtonTableView - width : implicitWidth - height : implicitHeight - implicitWidth : parent.width - implicitHeight : 150 * preferencesModel.uiScale + tableView.y + tableView.anchors.topMargin - - property int preferredHeight: implicitHeight - property int preferredWidth: implicitWidth - - Layout.preferredWidth: preferredWidth - Layout.preferredHeight: preferredHeight - - property bool buttonsInRow : false - property alias name : tableView.name - property alias source : tableView.source - property alias values : tableView.values - property alias tableView : tableView - property alias factorsSource : tableView.factorsSource - property alias control : tableView //Needed for RowComponent - property alias info : tableView.info - - property alias itemType : tableView.itemType - property alias itemTypePerColumn : tableView.itemTypePerColumn - property alias itemTypePerRow : tableView.itemTypePerRow - property alias modelType : tableView.modelType - - property alias cornerText : tableView.cornerText - property alias minimum : tableView.minimum - property alias initialColumnCount : tableView.initialColumnCount - property alias initialRowCount : tableView.initialRowCount - property alias columnName : tableView.colName - property alias decimals : tableView.decimals - property alias scaleFactor : tableView.scaleFactor - property alias isFirstColEditable : tableView.isFirstColEditable - property alias columnNames : tableView.columnNames - property alias rowNames : tableView.rowNames - property alias defaultValue : tableView.defaultValue - - property bool showButtons : true - - property alias buttonAddText : addButton.text - property alias buttonDeleteText : deleteButton.text - property alias buttonResetText : resetButton.text - - property alias buttonAddEnabled : addButton.enabled - property alias buttonDeleteEnabled : deleteButton.enabled - property alias buttonResetEnabled : resetButton.enabled - - property alias showAddButton : addButton.visible - property alias showDeleteButton : deleteButton.visible - property alias showResetButton : resetButton.visible - - - signal addClicked(); - signal deleteClicked(); - signal resetClicked(); - - signal tableViewCompleted(); - - function getColHeaderText(headerText, columnIndex) { return (columnNames.length > columnIndex) ? columnNames[columnIndex] : headerText; } - function getRowHeaderText(headerText, rowIndex) { return (rowNames.length > rowIndex) ? rowNames[rowIndex] : headerText; } - function getDefaultValue(columnIndex, rowIndex) { return defaultValue } - function getValidator(columnIndex, rowIndex) { return tableView.validator } - function getEditable(columnIndex, rowIndex) { return true } - - Grid - { - id : buttonColumn - columns : buttonsInRow ? 3 : 1 - rows : buttonsInRow ? 1 : 3 - anchors.top : parent.top - anchors.left : parent.left - anchors.leftMargin : jaspTheme.generalAnchorMargin - width : basicButtonTableView.showButtons ? (basicButtonTableView.width * (buttonsInRow ? 1 : 1 / 4) - jaspTheme.generalAnchorMargin * 2) : 0 - //height : showButtons ? (buttonsInRow ? jaspTheme.defaultRectangularButtonHeight : jaspTheme.defaultRectangularButtonHeight * 3 + spacing * 2) : 0 - spacing : jaspTheme.columnGroupSpacing - visible : basicButtonTableView.showButtons - - RoundedButton - { - id : addButton - text : qsTr("Add") - width : buttonsInRow ? basicButtonTableView.width * 1/4 - jaspTheme.generalAnchorMargin * 2 : buttonColumn.width - onClicked : { forceActiveFocus(); basicButtonTableView.addClicked() } - } - - RoundedButton - { - id : deleteButton - text : qsTr("Delete") - width : buttonsInRow ? basicButtonTableView.width * 1/4 - jaspTheme.generalAnchorMargin * 2 : buttonColumn.width - onClicked : { forceActiveFocus(); basicButtonTableView.deleteClicked() } - } - - RoundedButton - { - id : resetButton - text : qsTr("Reset") - width : buttonsInRow ? basicButtonTableView.width * 1/4 - jaspTheme.generalAnchorMargin * 2 : buttonColumn.width - onClicked : { forceActiveFocus(); basicButtonTableView.resetClicked() } - } - } - - TableView - { - id : tableView - - anchors.top : buttonColumn.visible && buttonsInRow ? buttonColumn.bottom : parent.top - anchors.left : buttonColumn.visible && !buttonsInRow ? buttonColumn.right : parent.left - anchors.leftMargin: jaspTheme.generalAnchorMargin - anchors.topMargin: buttonColumn.visible && buttonsInRow ? jaspTheme.generalAnchorMargin : 0 - width : tableView.tableWidth < maxWidth ? tableView.tableWidth : maxWidth - height : tableView.tableHeight < maxHeight ? tableView.tableHeight : maxHeight - - property int maxWidth : basicButtonTableView.width * ((basicButtonTableView.showButtons && !buttonsInRow) ? (3 / 4) : 1) - property int maxHeight : basicButtonTableView.height - - function getColHeaderText(defaultName, colIndex) { return basicButtonTableView.getColHeaderText(defaultName, colIndex) } - function getRowHeaderText(defaultName, rowIndex) { return basicButtonTableView.getRowHeaderText(defaultName, rowIndex) } - function getDefaultValue(columnIndex, rowIndex) { return basicButtonTableView.getDefaultValue(columnIndex, rowIndex) } - function getValidator(columnIndex, rowIndex) { return basicButtonTableView.getValidator(columnIndex, rowIndex) } - function getEditable(columnIndex, rowIndex) { return basicButtonTableView.getEditable(columnIndex, rowIndex) } - - Component.onCompleted : basicButtonTableView.tableViewCompleted() - } - -} diff --git a/QMLComponents/components/JASP/Controls/BayesFactorType.qml b/QMLComponents/components/JASP/Controls/BayesFactorType.qml deleted file mode 100644 index 317f74391cf..00000000000 --- a/QMLComponents/components/JASP/Controls/BayesFactorType.qml +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.8 -import JASP.Controls 1.0 - - -RadioButtonGroup -{ - title: qsTr("Bayes Factor") ; name: "bayesFactorType" - - RadioButton { label: qsTr("BF\u2081\u2080") ; name: "BF10"; checked: true; info: qsTr("Bayes factor to quantify evidence for the alternative hypothesis relative to the null hypothesis.") } - RadioButton { label: qsTr("BF\u2080\u2081") ; name: "BF01" ; info: qsTr("Bayes factor to quantify evidence for the null hypothesis relative to the alternative hypothesis.") } - RadioButton { label: qsTr("Log(BF\u2081\u2080)") ; name: "LogBF10" ; info: qsTr("Natural logarithm of BF10.") } -} diff --git a/QMLComponents/components/JASP/Controls/Button.qml b/QMLComponents/components/JASP/Controls/Button.qml deleted file mode 100644 index b853acedf1f..00000000000 --- a/QMLComponents/components/JASP/Controls/Button.qml +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// -import QtQuick 2.11 -import JASP 1.0 - -JASPControl -{ - id: button - controlType: JASPControl.Button - implicitHeight: control.implicitHeight - implicitWidth: control.implicitWidth - isBound: false - shouldStealHover: false - innerControl: control - focusIndicator: focusIndicator - - readonly property alias control: control - property alias text: control.text - property alias label: control.text - property alias iconSource: control.iconSource - readonly property alias pressed: control._pressed - - signal clicked() - - Component.onCompleted: control.clicked.connect(clicked); - - RoundedButton - { - id: control - anchors.fill: parent - } - - Rectangle - { - id: focusIndicator - anchors.fill: parent - color: "transparent" - border.width: 0 - border.color: "transparent" - radius: jaspTheme.jaspControlHighlightWidth - } -} diff --git a/QMLComponents/components/JASP/Controls/CIField.qml b/QMLComponents/components/JASP/Controls/CIField.qml deleted file mode 100644 index 2a9556833f8..00000000000 --- a/QMLComponents/components/JASP/Controls/CIField.qml +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP.Controls 1.0 -import JASP 1.0 - -PercentField -{ - id: ciField - - defaultValue: 95 - decimals: 1 - inclusive: JASP.None - fieldWidth: jaspTheme.font.pixelSize * (ciField.decimals + 3) -} diff --git a/QMLComponents/components/JASP/Controls/CheckBox.qml b/QMLComponents/components/JASP/Controls/CheckBox.qml deleted file mode 100644 index bb7bcb7ad0a..00000000000 --- a/QMLComponents/components/JASP/Controls/CheckBox.qml +++ /dev/null @@ -1,153 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import QtQuick.Layouts 1.3 as L -import JASP 1.0 - - -CheckBoxBase -{ - id: checkBox - implicitWidth: childrenOnSameRow - ? control.implicitWidth + (childControlsArea.children.length > 0 ? jaspTheme.columnGroupSpacing + childControlsArea.implicitWidth : 0) - : Math.max(control.implicitWidth, control.padding + checkIndicator.width + control.spacing + childControlsArea.implicitWidth) - implicitHeight: childrenOnSameRow - ? Math.max(control.implicitHeight, childControlsArea.implicitHeight) - : control.implicitHeight + (childControlsArea.children.length > 0 ? jaspTheme.rowGroupSpacing + childControlsArea.implicitHeight : 0) - focusIndicator: focusIndicator - childControlsArea: childControlsArea - innerControl: control - title: text - - default property alias content: childControlsArea.children - property alias control: control - property alias childrenArea: childControlsArea - property alias text: control.text - property alias font: label.font - property alias fontInfo: label.fontInfo - property alias label: control.text - property alias labelTextFormat: label.textFormat - property alias checked: control.checked - property bool childrenOnSameRow: false - property alias columns: childControlsArea.columns - property bool enableChildrenOnChecked: true - property bool forwardKeys: false - - function click() { control.toggle(); } - function toggle() { control.toggle(); } - - - CheckBox - { - id: control - padding: jaspTheme.jaspControlPadding - focus: true - // When the checked is changed by a binding, run the clicked slot without emiting the clicked signal - // The clicked signal should be emitted only when the user really clicks on the CheckBox. - onCheckedChanged: checkBox.clickedSlot() - Keys.onReturnPressed: (event)=> checked = !checked - Keys.onEnterPressed: checked = !checked - Keys.forwardTo: forwardKeys ? [checkBox] : [] // If a forward is set on the parent we want to hook on that chain, eg modules menu - - // When the user clicks on the CheckBox, the clicked signal of the parent (CheckBoxBase) must be emitted. - Component.onCompleted: control.clicked.connect(checkBox.clicked) - - indicator: Rectangle - { - id: checkIndicator - width: height - height: label.height - y: control.padding - x: control.padding - - color: control.checked ? (control.enabled ? jaspTheme.buttonBackgroundColor : jaspTheme.controlDisabledBackgroundColor) : jaspTheme.controlBackgroundColor - border.color: control.enabled ? (control.checked ? jaspTheme.buttonBackgroundColor : jaspTheme.borderColor) : jaspTheme.controlDisabledBackgroundColor - border.width: 1 - radius: jaspTheme.borderRadius - - Text - { - visible: control.checked ? true : false - color: jaspTheme.white - text: "\u2713" - font: jaspTheme.font - anchors.horizontalCenter: parent.horizontalCenter - renderType: Text.QtRendering //Prettier - } - } - - Rectangle - { - id: focusIndicator - anchors.centerIn: checkIndicator - width: checkIndicator.width + jaspTheme.jaspControlHighlightWidth - height: checkIndicator.height + jaspTheme.jaspControlHighlightWidth - color: "transparent" - border.width: 0 - border.color: "transparent" - radius: jaspTheme.jaspControlHighlightWidth - } - - contentItem: Label - { - id: label - text: control.text - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - font: jaspTheme.font - leftPadding: checkIndicator.width + control.spacing - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle - { - color: "transparent" - } - } - - GridLayout - { - id: childControlsArea - anchors - { - top: childrenOnSameRow ? control.top : control.bottom - topMargin: childrenOnSameRow ? 0 : jaspTheme.rowGroupSpacing - left: childrenOnSameRow ? control.right : control.left - leftMargin: childrenOnSameRow ? jaspTheme.columnGroupSpacing : control.padding + checkIndicator.width + control.spacing - } - enabled: enableChildrenOnChecked ? control.checked : true - visible: children.length > 0 - columns: childrenOnSameRow ? children.length : 1 - rowSpacing: jaspTheme.rowGroupSpacing - columnSpacing: jaspTheme.columnGridSpacing - } - - Component.onCompleted: - { - if (childControlsArea.children.length > 0) - { - if (childrenOnSameRow) - { - if (childControlsArea.implicitHeight < control.implicitHeight) - childControlsArea.anchors.topMargin = control.padding - 1 // border width - } - } - } - -} diff --git a/QMLComponents/components/JASP/Controls/Chi2TestTableView.qml b/QMLComponents/components/JASP/Controls/Chi2TestTableView.qml deleted file mode 100644 index 240c9ee7916..00000000000 --- a/QMLComponents/components/JASP/Controls/Chi2TestTableView.qml +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.0 -import QtQuick.Layouts 1.11 -import JASP.Controls 1.0 -import JASP 1.0 - -BasicThreeButtonTableView -{ - id : chi2TestTableView - - modelType : JASP.MultinomialChi2Model - - property int maxNumHypotheses : 10 - property string colHeader : "" - - buttonAddText : qsTr("Add Column") - onAddClicked : tableView.addColumn() - buttonAddEnabled : (tableView.columnCount > 0 && tableView.columnCount < maxNumHypotheses) - - buttonDeleteText : qsTr("Delete Column") - onDeleteClicked : tableView.removeAColumn() - buttonDeleteEnabled : tableView.columnCount > 1 - - buttonResetText : qsTr("Reset") - onResetClicked : tableView.reset() - buttonResetEnabled : tableView.columnCount > 0 - - function getColHeaderText(headerText, columnIndex) { return colHeader ? colHeader : "Hâ‚€ (" + String.fromCharCode(97 + columnIndex) + ")" ; } -} diff --git a/QMLComponents/components/JASP/Controls/ColorPalette.qml b/QMLComponents/components/JASP/Controls/ColorPalette.qml deleted file mode 100644 index 05432320518..00000000000 --- a/QMLComponents/components/JASP/Controls/ColorPalette.qml +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.8 -import JASP.Controls 1.0 - -DropDown -{ - name: "colorPalette" - label: qsTr("Color palette") - indexDefaultValue: 0 - values: - [ - { label: qsTr("Colorblind"), value: "colorblind" }, - { label: qsTr("Colorblind #2"), value: "colorblind2" }, - { label: qsTr("Colorblind #3"), value: "colorblind3" }, - { label: qsTr("Viridis"), value: "viridis" }, - { label: qsTr("ggplot2"), value: "ggplot2" }, - { label: qsTr("Gray"), value: "gray" }, - { label: qsTr("Blue"), value: "blue" }, - { label: qsTr("Sports teams: NBA"), value: "sportsTeamsNBA" }, - { label: qsTr("Grand Budapest"), value: "grandBudapest" } - ] -} diff --git a/QMLComponents/components/JASP/Controls/ColumnLayout.qml b/QMLComponents/components/JASP/Controls/ColumnLayout.qml deleted file mode 100644 index c4a362ea5c0..00000000000 --- a/QMLComponents/components/JASP/Controls/ColumnLayout.qml +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Layouts 1.3 - - -ColumnLayout -{ - spacing: jaspTheme.rowGridSpacing - Layout.alignment: Qt.AlignTop | Qt.AlignLeft -} diff --git a/QMLComponents/components/JASP/Controls/ComboBox.qml b/QMLComponents/components/JASP/Controls/ComboBox.qml deleted file mode 100644 index df5fd3766f7..00000000000 --- a/QMLComponents/components/JASP/Controls/ComboBox.qml +++ /dev/null @@ -1,280 +0,0 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 as QTC -import QtQuick.Layouts 1.3 -import JASP 1.0 - - -ComboBoxBase -{ - id: comboBox - implicitHeight: control.height + ((controlLabel.visible && setLabelAbove) ? rectangleLabel.height : 0) - implicitWidth: setLabelAbove ? Math.max(control.width, rectangleLabel.width) : (rectangleLabel.width + jaspTheme.labelSpacing + control.width) - background: useExternalBorder ? externalControlBackground : control.background - innerControl: control - title: label - - property alias control: control - property alias controlLabel: controlLabel - property alias label: controlLabel.text - property alias currentLabel: comboBox.currentText - property alias value: comboBox.currentValue - property alias indexDefaultValue: comboBox.currentIndex - property alias fieldWidth: control.modelWidth - property bool showVariableTypeIcon: containsVariables - property var enabledOptions: [] - property bool setLabelAbove: false - property int controlMinWidth: 0 - property bool useExternalBorder: true - property bool showBorder: true - property bool showEmptyValueAsNormal: false - property bool addLineAfterEmptyValue: false - - onControlMinWidthChanged: _resetWidth(textMetrics.width) - - function resetWidth(values) - { - var maxWidth = 0 - var maxValue = "" - textMetrics.initialized = false; - - if (addEmptyValue) - values.push(placeholderText) - - for (var i = 0; i < values.length; i++) - { - textMetrics.text = values[i] - if (textMetrics.width > maxWidth) - { - maxWidth = textMetrics.width - maxValue = values[i] - } - } - - textMetrics.text = maxValue; - textMetrics.initialized = true; - _resetWidth(maxWidth) - } - - function _resetWidth(maxWidth) - { - var newWidth = maxWidth + ((comboBox.showVariableTypeIcon ? 20 : 4) * preferencesModel.uiScale); - control.modelWidth = newWidth; - if (control.width < controlMinWidth) - control.modelWidth += (controlMinWidth - control.width); - comboBox.width = comboBox.implicitWidth; // the width is not automatically updated by the implicitWidth... - } - - Component.onCompleted: control.activated.connect(activated); - - Rectangle - { - id: rectangleLabel - width: controlLabel.width - height: control.height - color: debug ? jaspTheme.debugBackgroundColor : "transparent" - visible: controlLabel.text && comboBox.visible ? true : false - Label - { - id: controlLabel - font: jaspTheme.font - anchors.verticalCenter: parent.verticalCenter - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - width: implicitWidth - } - } - - QTC.ComboBox - { - id: control - model: comboBox.model - anchors.left: !rectangleLabel.visible || comboBox.setLabelAbove ? comboBox.left : rectangleLabel.right - anchors.leftMargin: !rectangleLabel.visible || comboBox.setLabelAbove ? 0 : jaspTheme.labelSpacing - anchors.top: rectangleLabel.visible && comboBox.setLabelAbove ? rectangleLabel.bottom: comboBox.top - - focus: true - padding: 2 * preferencesModel.uiScale //jaspTheme.jaspControlPadding - - width: modelWidth + extraWidth - height: jaspTheme.comboBoxHeight - font: jaspTheme.font - property int modelWidth: 30 * preferencesModel.uiScale - property int extraWidth: 5 * padding + dropdownIcon.width - property bool isEmptyValue: comboBox.addEmptyValue && comboBox.currentIndex === 0 - property bool showEmptyValueStyle: !comboBox.showEmptyValueAsNormal && isEmptyValue - - TextMetrics - { - id: textMetrics - font: control.font - - property bool initialized: false - - onWidthChanged: - { - if (initialized) - _resetWidth(width) - } - } - - contentItem: Rectangle - { - color: jaspTheme.controlBackgroundColor - Image - { - id: contentIcon - height: 15 * preferencesModel.uiScale - width: 15 * preferencesModel.uiScale - x: 3 * preferencesModel.uiScale - anchors.verticalCenter: parent.verticalCenter - source: !visible ? "" : ((comboBox.currentColumnTypeIcon && comboBox.isBound) ? comboBox.currentColumnTypeIcon : comboBox.values[comboBox.currentIndex].columnTypeIcon) - visible: comboBox.showVariableTypeIcon && !control.isEmptyValue && (comboBox.currentColumnType || !comboBox.isBound) - } - - Text - { - anchors.left: contentIcon.visible ? contentIcon.right : parent.left - anchors.leftMargin: 4 * preferencesModel.uiScale - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: control.showEmptyValueStyle ? parent.horizontalCenter : undefined - text: comboBox.currentText - font: control.font - color: (!enabled || control.showEmptyValueStyle) ? jaspTheme.grayDarker : jaspTheme.black - } - } - - indicator: Image - { - id: dropdownIcon - x: control.width - width - 3 //control.spacing - y: control.topPadding + (control.availableHeight - height) / 2 - width: 12 * preferencesModel.uiScale - height: 12 * preferencesModel.uiScale - source: jaspTheme.iconPath + "/toolbutton-menu-indicator.svg" - - } - - background: Rectangle - { - id: comboBoxBackground - border.width: comboBox.showBorder && !control.activeFocus ? 1 : 0 - border.color: comboBox.showBorder ? jaspTheme.borderColor : "transparent" - radius: 2 - color: jaspTheme.controlBackgroundColor - } - - Rectangle - { - id: externalControlBackground - height: parent.height + jaspTheme.jaspControlHighlightWidth - width: parent.width + jaspTheme.jaspControlHighlightWidth - color: "transparent" - border.width: 1 - border.color: "transparent" - anchors.centerIn: parent - opacity: debug ? .3 : 1 - visible: comboBox.useExternalBorder - radius: jaspTheme.jaspControlHighlightWidth - } - - popup: QTC.Popup - { - y: control.height - 1 - width: comboBoxBackground.width - padding: 1 - - enter: Transition { NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 } enabled: preferencesModel.animationsOn } - - JASPScrollBar - { - id: scrollBar - flickable: popupView - manualAnchor: true - vertical: true - z: 1337 - - anchors - { - top: parent.top - right: parent.right - bottom: parent.bottom - } - } - - - contentItem: ListView - { - id: popupView - width: comboBoxBackground.width - implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null - currentIndex: control.highlightedIndex - clip: true - - Rectangle - { - anchors.centerIn: parent - width: parent.width + 4 - height: parent.height + 4 - border.color: jaspTheme.focusBorderColor - border.width: 2 - color: "transparent" - } - } - } - - delegate: QTC.ItemDelegate - { - height: jaspTheme.comboBoxHeight - width: comboBoxBackground.width - enabled: comboBox.enabledOptions.length == 0 || comboBox.enabledOptions.length <= index || comboBox.enabledOptions[index] - - contentItem: Rectangle - { - id: itemRectangle - anchors.fill: parent - anchors.rightMargin: scrollBar.visible ? scrollBar.width + 2 : 0 - color: comboBox.currentIndex === index ? jaspTheme.itemSelectedColor : (control.highlightedIndex === index ? jaspTheme.itemHoverColor : jaspTheme.controlBackgroundColor) - - property bool isEmptyValue: comboBox.addEmptyValue && index === 0 - property bool showEmptyValueStyle: !comboBox.showEmptyValueAsNormal && isEmptyValue - property bool showLine: comboBox.addLineAfterEmptyValue && index === 0 - - - Image - { - id: delegateIcon - x: 1 * preferencesModel.uiScale - height: 15 * preferencesModel.uiScale - width: 15 * preferencesModel.uiScale - source: visible ? (comboBox.isBound ? model.columnTypeIcon : comboBox.values[index].columnTypeIcon) : "" - visible: comboBox.showVariableTypeIcon && !itemRectangle.isEmptyValue - - anchors.verticalCenter: parent.verticalCenter - } - - Text - { - x: (delegateIcon.visible ? 20 : 4) * preferencesModel.uiScale - text: itemRectangle.isEmptyValue ? comboBox.placeholderText : (model && model.name ? model.name : "") - font: jaspTheme.font - color: itemRectangle.showEmptyValueStyle || !enabled ? jaspTheme.grayDarker : (comboBox.currentIndex === index ? jaspTheme.white : jaspTheme.black) - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: itemRectangle.showEmptyValueStyle ? parent.horizontalCenter : undefined - } - - Rectangle - { - anchors - { - left: parent.left - right: parent.right - bottom: parent.bottom - } - visible: itemRectangle.showLine - height: 1 - color: jaspTheme.focusBorderColor - } - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/ComponentsList.qml b/QMLComponents/components/JASP/Controls/ComponentsList.qml deleted file mode 100644 index 0fc2e303a7d..00000000000 --- a/QMLComponents/components/JASP/Controls/ComponentsList.qml +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.0 -import QtQuick.Controls 2.4 as QtControls -import JASP 1.0 -import QtQuick.Layouts 1.3 - -ComponentsListBase -{ - id : componentsList - background : itemRectangle - implicitWidth : parent.width - implicitHeight : itemTitles.height + itemTitle.height + itemGrid.height + 2 * jaspTheme.contentMargin + (showAddIcon ? addIconItem.height : 0) - shouldStealHover : false - innerControl : itemGrid - addItemManually : !source && !rSource - - property alias label : componentsList.title - property alias columns : itemGrid.columns - property alias rows : itemGrid.rows - property alias itemGrid : itemGrid - property alias itemRectangle : itemRectangle - property alias itemScrollbar : itemScrollbar - property alias itemTitle : itemTitle - property alias itemTitles : itemTitles - property alias rowSpacing : itemGrid.rowSpacing - property alias columnSpacing : itemGrid.columnSpacing - property alias addIconItem : addIconItem - property bool showAddIcon : addItemManually - property string removeIcon : "cross.png" - property string addIcon : "duplicate.png" - property string addTooltip : qsTr("Add a row") - property string removeTooltip : qsTr("Remove a row") - property bool addBorder : true - property var titles - - Item - { - id : itemTitles - anchors.top : parent.top - anchors.left : parent.left - height : titles ? jaspTheme.variablesListTitle : 0 - width : parent.width - visible : !title && titles - - Repeater - { - id: rep - model: titles - Text - { - property int defaultOffset: index === 0 ? 0 : rep.itemAt(index-1).x + rep.itemAt(index-1).width + jaspTheme.contentMargin - - x : (addBorder ? jaspTheme.contentMargin : 0) + (componentsList.offsets.length > index ? componentsList.offsets[index] : defaultOffset) - text : titles[index] - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - - } - } - } - - Text - { - id : itemTitle - anchors.top : parent.top - anchors.left : parent.left - text : title - height : title ? jaspTheme.variablesListTitle : 0 - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Rectangle - { - id : itemRectangle - anchors.top : itemTitles.visible ? itemTitles.bottom : itemTitle.bottom - anchors.left : parent.left - height : componentsList.height - itemTitle.height - width : parent.width - color : debug ? jaspTheme.debugBackgroundColor : jaspTheme.analysisBackgroundColor - border.width : addBorder ? 1 : 0 - border.color : jaspTheme.borderColor - radius : jaspTheme.borderRadius - - JASPScrollBar - { - id : itemScrollbar - flickable : itemFlickable - manualAnchor : true - vertical : true - z : 1337 - - anchors - { - top : parent.top - right : parent.right - bottom : parent.bottom - margins : 2 - } - } - - Flickable - { - id : itemFlickable - anchors.fill : parent - anchors.margins : addBorder ? jaspTheme.contentMargin : 0 - anchors.rightMargin : itemScrollbar.width + anchors.margins - clip : true - boundsBehavior : Flickable.StopAtBounds - contentWidth : itemGrid.width - contentHeight : itemGrid.height - - Grid - { - id : itemGrid - width : itemRectangle.width - 2 * jaspTheme.contentMargin - (itemScrollbar.visible ? itemScrollbar.width + 2 : 0) - focus : true - columns : 1 - rowSpacing : 1 - columnSpacing : 1 - - Repeater - { - id : itemRepeater - model : componentsList.model - delegate : components - } - } - } - } - - MenuButton - { - id : addIconItem - width : height - radius : height - visible : showAddIcon && (maximumItems <= 0 || maximumItems > componentsList.count) - iconSource : jaspTheme.iconPath + addIcon - onClicked : addItem() - toolTip : addTooltip - opacity : enabled ? 1 : .5 - anchors - { - bottom : parent.bottom - horizontalCenter: parent.horizontalCenter - } - } - - Component - { - id: components - - FocusScope - { - id : itemWrapper - height : rowComponentItem ? rowComponentItem.height : 0 - width : componentsList.itemGrid.width - - property var rowComponentItem : model.rowComponent - property bool isDeletable : addItemManually && (!model.type || model.type.includes("deletable")) - - Component.onCompleted: - { - if (rowComponentItem) - { - rowComponentItem.parent = itemWrapper; - rowComponentItem.anchors.left = itemWrapper.left - rowComponentItem.anchors.verticalCenter = itemWrapper.verticalCenter - } - } - - Image - { - id : removeIconID - source : jaspTheme.iconPath + removeIcon - anchors.right : parent.right - anchors.verticalCenter : parent.verticalCenter - visible : rowComponentItem.enabled && itemWrapper.isDeletable && componentsList.count > componentsList.minimumItems - height : jaspTheme.iconSize - width : jaspTheme.iconSize - z : 2 - - QtControls.ToolTip.text : removeTooltip - QtControls.ToolTip.timeout : jaspTheme.toolTipTimeout - QtControls.ToolTip.delay : jaspTheme.toolTipDelay - QtControls.ToolTip.visible : removeTooltip !== "" && deleteMouseArea.containsMouse - - MouseArea - { - id : deleteMouseArea - anchors.fill : parent - onClicked : removeItem(index) - cursorShape : Qt.PointingHandCursor - } - } - } - - } - -} diff --git a/QMLComponents/components/JASP/Controls/ComputedColumnField.qml b/QMLComponents/components/JASP/Controls/ComputedColumnField.qml deleted file mode 100644 index a7f72a4b359..00000000000 --- a/QMLComponents/components/JASP/Controls/ComputedColumnField.qml +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP.Controls 1.0 -import JASP 1.0 - -TextField -{ - inputType: "computedColumn" -} diff --git a/QMLComponents/components/JASP/Controls/ContrastsList.qml b/QMLComponents/components/JASP/Controls/ContrastsList.qml deleted file mode 100644 index 1431b722fb6..00000000000 --- a/QMLComponents/components/JASP/Controls/ContrastsList.qml +++ /dev/null @@ -1,109 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.0 -import JASP.Controls 1.0 -import QtQuick.Layouts 1.3 as L -import JASP 1.0 - -Item -{ - id : contrastsList - implicitHeight : itemContrastVariables.height + (itemCustomContrasts.visible ? itemCustomContrasts.height : 0) - height : implicitHeight - implicitWidth : parent.width - width : implicitWidth - L.Layout.columnSpan : parent.columns - - property alias source : itemContrastVariables.source - property string repeatedMeasureFactors : "repeatedMeasuresFactors" - property bool addCustom : true - property alias itemContrastVariables : itemContrastVariables - property alias itemCustomContrasts : itemCustomContrasts - property alias variablesHeight : itemContrastVariables.height - property alias customContrastsHeight : itemCustomContrasts.preferredHeight - property var contrastValues : - [ - { label: qsTr("none") , value: "none" }, - { label: qsTr("deviation") , value: "deviation" }, - { label: qsTr("simple") , value: "simple" }, - { label: qsTr("difference") , value: "difference" }, - { label: qsTr("Helmert") , value: "Helmert" }, - { label: qsTr("repeated") , value: "repeated" }, - { label: qsTr("polynomial") , value: "polynomial" }, - { label: qsTr("custom") , value: "custom" } - ] - - readonly property var constrastCustomValue: [{ label: qsTr("custom"), value: "custom"}] - - onAddCustomChanged: - { - if (addCustom) contrastValues.push( constrastCustomValue[0] ) - else contrastValues.pop() - } - - VariablesList - { - id : itemContrastVariables - title : qsTr("Factors") - source : "fixedFactors" - name : "contrasts" - listViewType : JASP.AssignedVariables - height : 200 * preferencesModel.uiScale - draggable : false - - rowComponent: DropDown - { - id : contrastValuesItem - name : "contrast" - values : contrastsList.contrastValues - } - - } - - ComponentsList - { - id : itemCustomContrasts - name : "customContrasts" - anchors.top : itemContrastVariables.bottom - anchors.topMargin : jaspTheme.rowSpacing - visible : count > 0 - source : [ { name: "contrasts", condition: "contrast == 'custom'" }] - - rowComponent: Group - { - Text - { - height : 30 * preferencesModel.uiScale - text : qsTr("Custom for %1").arg(rowValue) - } - - CustomContrastsTableView - { - preferredWidth : itemCustomContrasts.width - name : "values" - itemType : JASP.Double - minimum : -Infinity - decimals : 3 - //buttonsInRow : false - columnName : rowValue - factorsSource : contrastsList.repeatedMeasureFactors - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/ControlErrorMessage.qml b/QMLComponents/components/JASP/Controls/ControlErrorMessage.qml deleted file mode 100644 index 503e44875e9..00000000000 --- a/QMLComponents/components/JASP/Controls/ControlErrorMessage.qml +++ /dev/null @@ -1,180 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// -import QtQuick 2.11 -import JASP 1.0 - -Rectangle -{ - id : controlErrorMessage - color : warning ? jaspTheme.controlWarningBackgroundColor : jaspTheme.controlErrorBackgroundColor - visible : opacity > 0 - opacity : 0 - width : messageText.width + 2 * paddingWidth - height : messageText.height + 2 * paddingHeight - z : 10 - radius : 4 - border.color : foreCol - border.width : 1 - - property color foreCol: warning ? jaspTheme.controlWarningTextColor : jaspTheme.controlErrorTextColor - - property var control - property bool tmp : false - property bool warning : false - property var form - property var container : parent - property int containerWidth : container ? (container === form ? form.availableWidth : container.width) : 0 - property int paddingWidth : 10 * jaspTheme.uiScale - property int paddingHeight : 6 * jaspTheme.uiScale - property alias message : messageText.text - - onContainerWidthChanged: if (visible) showMessage() - onControlChanged: if (!control) controlErrorMessage.opacity = 0 - onVisibleChanged: if (!visible && control) - { - control.hasError = false; - control.hasWarning = false; - control = null; - parent = null; - } - - Timer - { - id : messageTimer - running : false - repeat : false - interval : 4000 - onTriggered : controlErrorMessage.opacity = 0 - } - - Behavior on opacity - { - enabled: preferencesModel.animationsOn; - - NumberAnimation - { - duration : 300 - easing.type : Easing.InOutQuad - } - } - - onParentChanged: repositionMessage(); - onContainerChanged: if(parent != container) repositionMessage(); - - - Connections - { - target: container - function onXChanged (x) { controlErrorMessage.repositionMessage() } - function onWidthChanged (width) { controlErrorMessage.repositionMessage() } - function onYChanged (y) { controlErrorMessage.repositionMessage() } - function onHeightChanged (height) { controlErrorMessage.repositionMessage() } - } - - Connections - { - target: !form ? null : form._contentArea - function onXChanged (x) { controlErrorMessage.repositionMessage() } - function onWidthChanged (width) { controlErrorMessage.repositionMessage() } - function onYChanged (y) { controlErrorMessage.repositionMessage() } - function onHeightChanged (height) { controlErrorMessage.repositionMessage() } - } - - function repositionMessage() - { - if(controlErrorMessage.opacity == 0 || !messageText.text || !control || !container) - return; - - positionMessage(); - } - - function showMessage(message, temporary) - { - messageTimer.stop(); - if (!message || !control || !container) return; - - controlErrorMessage.tmp = temporary - messageText.text = message - messageText.wrapMode = Text.NoWrap - - positionMessage(); - - controlErrorMessage.opacity = 1 - if (temporary) messageTimer.start(); - } - - function positionMessage() - { - messageText.width = messageText.implicitWidth - - var controlPoint = control.mapToItem(parent, control.width / 2, 0) - - var x = controlPoint.x - (controlErrorMessage.width / 2) - var y = controlPoint.y - controlErrorMessage.height - paddingHeight - - var maxWidth = containerWidth - - x = Math.max(x, 0) - - if (x + controlErrorMessage.width > maxWidth) - { - if (controlErrorMessage.width < maxWidth) - x = maxWidth - controlErrorMessage.width - else - { - x = 0 - messageText.wrapMode = Text.Wrap - messageText.width = maxWidth - } - } - - //make sure it comes below formwarningsmessages etc - var minimumY = form === container ? form.minimumYMsgs : 0 - y = Math.max(minimumY, y) - - //If it overlaps with control move it below - if (y + controlErrorMessage.height > controlPoint.y) - y = controlPoint.y + control.height + paddingHeight - - controlErrorMessage.x = x - controlErrorMessage.y = y - } - - - - CrossButton - { - onCrossClicked: - { - controlErrorMessage.opacity = 0 - if (controlErrorMessage.control) - controlErrorMessage.control.forceActiveFocus() - } - } - - Text - { - id : messageText - font : jaspTheme.font - color : controlErrorMessage.foreCol - anchors.verticalCenter : parent.verticalCenter - anchors.left : parent.left - anchors.leftMargin : 2 * jaspTheme.uiScale - textFormat : Text.RichText - } -} diff --git a/QMLComponents/components/JASP/Controls/CrossButton.qml b/QMLComponents/components/JASP/Controls/CrossButton.qml deleted file mode 100644 index b643de2b7b8..00000000000 --- a/QMLComponents/components/JASP/Controls/CrossButton.qml +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// -import QtQuick 2.11 -import JASP 1.0 - -Item -{ - id : crossRectangle - width : 12 * jaspTheme.uiScale - height : 12 * jaspTheme.uiScale - anchors.top : parent.top - anchors.right : parent.right - - property int crossThickness : (crossArea.containsMouse ? 3 : 2) * jaspTheme.uiScale - property int crossLengthOffset : 2 * jaspTheme.uiScale - - property bool warning: false - - signal crossClicked(); - - Rectangle - { - anchors.centerIn : parent - height : crossRectangle.crossThickness - width : parent.width - crossRectangle.crossLengthOffset - rotation : 45 - color : warning ? jaspTheme.controlWarningTextColor : jaspTheme.controlErrorTextColor - } - - Rectangle - { - anchors.centerIn : parent - height : crossRectangle.crossThickness - width : parent.width - crossRectangle.crossLengthOffset - rotation : -45 - color : warning ? jaspTheme.controlWarningTextColor : jaspTheme.controlErrorTextColor - } - - MouseArea - { - id : crossArea - anchors.fill : parent - onClicked : crossRectangle.crossClicked() - hoverEnabled : true - cursorShape : Qt.PointingHandCursor - } -} - diff --git a/QMLComponents/components/JASP/Controls/CustomContrastsTableView.qml b/QMLComponents/components/JASP/Controls/CustomContrastsTableView.qml deleted file mode 100644 index 8dfb8b7c930..00000000000 --- a/QMLComponents/components/JASP/Controls/CustomContrastsTableView.qml +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.0 -import QtQuick.Layouts 1.11 -import JASP.Controls 1.0 -import JASP 1.0 - -BasicThreeButtonTableView -{ - id : customContrastsTV - - preferredHeight : Math.max(150 * preferencesModel.uiScale,10 * preferencesModel.uiScale + tableView.y + tableView.tableHeight) - - modelType : JASP.CustomContrasts - itemType : JASP.Double - minimum : -Infinity - initialColumnCount : 1 - initialRowCount : 0 - buttonsInRow : true - - cornerText : "" - - buttonAddText : qsTr("Add Contrast") - onAddClicked : tableView.addColumn() - - buttonDeleteText : qsTr("Delete Contrast") - onDeleteClicked : tableView.removeAColumn() - buttonDeleteEnabled : tableView.columnCount > (tableView.variableCount + 1) - - buttonResetText : qsTr("Reset") - onResetClicked : tableView.reset() - buttonResetEnabled : tableView.columnCount > (tableView.variableCount + 1) -} diff --git a/QMLComponents/components/JASP/Controls/Divider.qml b/QMLComponents/components/JASP/Controls/Divider.qml deleted file mode 100644 index 4a9ba1d3fbb..00000000000 --- a/QMLComponents/components/JASP/Controls/Divider.qml +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.0 -import QtQuick.Layouts 1.3 - - - -Item -{ - property alias label: titleText.text - - Layout.columnSpan: parent.columns - implicitWidth: parent.width - implicitHeight: separator.height - - Rectangle - { - id: separator - border.width: 1 - height: 2 - width: parent.implicitWidth - border.color: jaspTheme.gray - } - - Rectangle - { - id: title - anchors.centerIn: separator - height: titleText.implicitWidth - width: titleText.implicitWidth + 6 - color: jaspTheme.analysisBackgroundColor - visible: label !== '' - Text - { - id: titleText - font: jaspTheme.fontLabel - anchors.centerIn: parent - } - } -} diff --git a/QMLComponents/components/JASP/Controls/DoubleField.qml b/QMLComponents/components/JASP/Controls/DoubleField.qml deleted file mode 100644 index 1e4482f3f98..00000000000 --- a/QMLComponents/components/JASP/Controls/DoubleField.qml +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP.Controls 1.0 -import JASP 1.0 - -TextField -{ - id: doubleField - defaultValue: 0 - property var _prevDefaultValue: 0 - property alias doubleValidator: doubleValidator - property bool negativeValues: false - property double min: negativeValues ? -Infinity : 0 - property double max: Infinity - property int decimals: 3 - property alias inclusive: doubleValidator.inclusive - - inputType: "number" - validator: JASPDoubleValidator { id: doubleValidator; bottom: min; top: max ; decimals: doubleField.decimals; notation: DoubleValidator.StandardNotation } - fieldWidth: jaspTheme.numericFieldWidth - - onDefaultValueChanged: - { - if (_prevDefaultValue == value) - value = defaultValue - - _prevDefaultValue = defaultValue; - } -} diff --git a/QMLComponents/components/JASP/Controls/ExpanderButton.qml b/QMLComponents/components/JASP/Controls/ExpanderButton.qml deleted file mode 100644 index 3dabb583658..00000000000 --- a/QMLComponents/components/JASP/Controls/ExpanderButton.qml +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Layouts 1.3 as L -import JASP 1.0 - -FocusScope -{ - id : expanderWrapper - implicitHeight : expanderButton.visible ? expanderButton.height : 0 - implicitWidth : expanderButton.visible ? parent.width : 0 - anchors.topMargin : expanderButton.visible ? 15 * preferencesModel.uiScale : 0 - clip : true - L.Layout.columnSpan : jaspForm ? jaspForm.columns : 1 - objectName : "Section" - - ALTNavigation.enabled: visible - ALTNavigation.showChildren: true - ALTNavigation.onTagMatch: { expanded = true; expanderButton.forceActiveFocus(); } - - default property alias content : expanderArea.children - property alias button : expanderButton - property alias childControlsArea : expanderArea - property alias spacing : expanderArea.rowSpacing - property alias text : expanderButton.title - property alias info : expanderButton.info - property alias title : expanderButton.title - property bool expanded : false - property alias debug : expanderButton.debug - readonly property string iconsFolder : jaspTheme.iconPath - readonly property string expanderButtonIcon : "expander-arrow-up.png" - property alias columns : expanderArea.columns - - states: [ - State - { - name: "expanded"; when: expanderWrapper.expanded - PropertyChanges { target: expanderWrapper; implicitHeight: expanderButton.height + expanderArea.anchors.topMargin + expanderArea.height + 2 } - PropertyChanges { target: expanderIcon; rotation: 90; } - }, - State - { - name: "imploded"; when: !expanderWrapper.expanded - PropertyChanges { target: expanderWrapper; implicitHeight: expanderButton.visible ? expanderButton.height : 0 } - PropertyChanges { target: expanderIcon; rotation: 0; } - } - ] - - transitions: Transition - { - enabled: preferencesModel.animationsOn - - NumberAnimation { property: "implicitHeight"; duration: 250; easing.type: Easing.OutQuad; easing.amplitude: 3 } - RotationAnimation { duration: 250; easing.type: Easing.OutQuad; easing.amplitude: 3 } - } - - ExpanderButtonBase - { - id : expanderButton - isBound : false - background : expanderRectangle - childControlsArea : expanderArea - width : parent.width - height : 22 * preferencesModel.uiScale - shouldStealHover : false //Because sometimes maybe something *inside* an expanderButton might want to get hovered - Keys.onSpacePressed : toggleExpander() - Keys.onReturnPressed : toggleExpander() - - function toggleExpander() { expanderWrapper.expanded = !expanderWrapper.expanded; } - - MouseArea - { - anchors.fill: parent - onClicked: - { - expanderButton.toggleExpander(); - expanderButton.forceActiveFocus(); - } - } - - Rectangle - { - id : expanderRectangle - anchors.fill : parent - border.width : 1 - border.color : jaspTheme.borderColor - radius : jaspTheme.borderRadius - color : debug ? jaspTheme.debugBackgroundColor : jaspTheme.white - - Image - { - id : expanderIcon - anchors - { - left : parent.left - leftMargin : 6 * preferencesModel.uiScale - verticalCenter : parent.verticalCenter - } - height : 15 * preferencesModel.uiScale - width : 15 * preferencesModel.uiScale - source : jaspTheme.iconPath + "/large-arrow-right.png" - sourceSize - { - width : expanderIcon.width * 2 - height : expanderIcon.height * 2 - } - } - - Text - { - id : label - text : expanderButton.title - anchors.left : expanderIcon.right - anchors.leftMargin : 5 * preferencesModel.uiScale - anchors.verticalCenter : parent.verticalCenter - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - } - } - - GridLayout - { - id : expanderArea - rowSpacing : jaspTheme.rowGridSpacing - columnSpacing : jaspTheme.columnGridSpacing - anchors.leftMargin : 5 * preferencesModel.uiScale - anchors.top : expanderButton.bottom - anchors.topMargin : 15 * preferencesModel.uiScale - width : parent.width - columns : 2 - visible : expanderWrapper.implicitHeight > expanderButton.height //set to that focus chain does not enter closed expanders -// anchors.bottomMargin : 20 * preferencesModel.uiScale - } - - Rectangle - { - z : -1 - anchors.fill : parent - color : jaspTheme.analysisBackgroundColor - } -} diff --git a/QMLComponents/components/JASP/Controls/FactorLevelList.qml b/QMLComponents/components/JASP/Controls/FactorLevelList.qml deleted file mode 100644 index 38844ed2114..00000000000 --- a/QMLComponents/components/JASP/Controls/FactorLevelList.qml +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQml.Models 2.2 -import JASP.Controls 1.0 -import JASP 1.0 - -FactorLevelListBase -{ - id: repeatedMeasuresFactorsList - implicitWidth: parent.width - implicitHeight: jaspTheme.defaultVariablesFormHeight - background: rectangle - factorName: qsTr("Factor") - levelName: qsTr("Level") - factorPlaceHolder: qsTr("New Factor") - levelPlaceHolder: qsTr("New Level") - - readonly property string deleteIcon: "cross.png" - - Text - { - id: text - anchors.top: parent.top - anchors.left: parent.left - text: repeatedMeasuresFactorsList.title - height: repeatedMeasuresFactorsList.title ? 20 * preferencesModel.uiScale : 0 - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Rectangle - { - id: rectangle - anchors.top: text.bottom - anchors.left: parent.left - height: repeatedMeasuresFactorsList.height - text.height - width: parent.width - color: debug ? jaspTheme.debugBackgroundColor : jaspTheme.controlBackgroundColor - border.width: 1 - border.color: jaspTheme.borderColor - - JASPScrollBar - { - id: scrollBar - flickable: listView - manualAnchor: true - vertical: true - z: 1337 - - anchors - { - top: parent.top - right: parent.right - bottom: parent.bottom - margins: 2 - } - } - - - GridView - { - id: listView - cellHeight: 22 * preferencesModel.uiScale - cellWidth: width - clip: true - boundsBehavior: Flickable.StopAtBounds - - - anchors.fill: parent - anchors.margins: 4 * preferencesModel.uiScale - model: repeatedMeasuresFactorsList.model - delegate: itemComponent - } - } - - Component - { - id: itemComponent - - FocusScope - { - id: itemWrapper - height: listView.cellHeight - width: scrollBar.visible ? listView.cellWidth - scrollBar.width : listView.cellWidth - - Rectangle - { - id: itemRectangle - anchors.fill: parent - focus: true - color: jaspTheme.controlBackgroundColor - - TextField - { - id: colName - isBound: false - value: model.virtual ? "" : model.name - placeholderText: model.virtual ? model.name : "" - anchors.centerIn: parent - fieldWidth: parent.width - fieldHeight: parent.height - useExternalBorder: false - showBorder: false - selectValueOnFocus: true - control.horizontalAlignment: model.type === "level" ? TextInput.AlignLeft : TextInput.AlignHCenter - onEditingFinished: itemChanged(index, displayValue) - } - - Image - { - source: jaspTheme.iconPath + deleteIcon - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - visible: model.deletable - height: 16 * preferencesModel.uiScale - width: 16 * preferencesModel.uiScale - z: 2 - - MouseArea - { - anchors.fill: parent - onClicked: itemRemoved(index) - } - } - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/FactorsForm.qml b/QMLComponents/components/JASP/Controls/FactorsForm.qml deleted file mode 100644 index 1b797ecfa8a..00000000000 --- a/QMLComponents/components/JASP/Controls/FactorsForm.qml +++ /dev/null @@ -1,121 +0,0 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 -import JASP 1.0 -import QtQuick.Layouts 1.3 - -FactorsFormBase -{ - id: factorsForm - - implicitHeight : jaspTheme.defaultVariablesFormHeight + Math.max((factorsFormRepeater.count - 3), 0) * (factorsForm.factorListHeight + factorsFormColumn.spacing) - implicitWidth : jaspForm.width - height : implicitHeight - width : implicitWidth - Layout.columnSpan : parent.columns - - property string availableVariablesListName: "allAvailableVariables" - property alias availableVariablesList: availableVariablesList - property bool allowAll: false - property int listWidth: parent.width * 2 / 5 - property int factorListHeight: (jaspTheme.defaultVariablesFormHeight - factorButtons.height) / 3 - factorsFormColumn.spacing - - AvailableVariablesList - { - id: availableVariablesList - name: availableVariablesListName - width: listWidth - preferredHeight: parent.height - anchors.top: parent.top - anchors.left: parent.left - } - - Column - { - id: factorsFormColumn - spacing: 10 - width: parent.width * 3 / 5 - anchors.top: parent.top - anchors.right: parent.right - - Repeater - { - id: factorsFormRepeater - model: factorsForm.model - RowLayout - { - property alias factorList : factorList - property alias button : button - property bool isDynamic : true - - spacing: 0 - AssignButton - { - id: button - name: "Factor form " - Layout.leftMargin: (factorsFormColumn.width / 3 - width) / 2 - Layout.rightMargin: (factorsFormColumn.width / 3 - width) / 2 - leftSource: factorsForm.availableVariablesList - rightSource: factorList - - Component.onDestruction: - { - availableVariablesList.activeFocusChanged.disconnect(button.setIconToRight); - availableVariablesList.selectedItemsChanged.disconnect(button.setState); - } - - } - FactorsList - { - id: factorList - name: factorName - editableTitle: factorTitle - dropKeys: availableVariablesListName - dropMode: JASP.DropReplace - suggestedColumns: allowAll ? [] : ["scale", "ordinal"] - allowedColumns: allowAll ? [] : ["scale", "ordinal"] - implicitHeight: factorsForm.factorListHeight // preferredHeight does not work when changing the language: the height is set to the implicitHeight - implicitWidth: listWidth - isBound: false - - onTitleIsChanged: factorsForm.titleChanged(index, editableTitle) - } - } - onItemAdded: - { - availableVariablesList.dropKeys.push(item.factorList.name); - item.factorList.activeFocusChanged.connect(item.button.setIconToLeft); - availableVariablesList.activeFocusChanged.connect(item.button.setIconToRight); - item.factorList.selectedItemsChanged.connect(item.button.setState); - availableVariablesList.selectedItemsChanged.connect(item.button.setState); - factorsForm.factorAdded(index, item.factorList); - } - } - - Row - { - id: factorButtons - anchors.right: parent.right - spacing: 10 - - Button - { - name: "add"; - text: qsTr("+") - control.width: height - width: control.width - onClicked: factorsForm.addFactor() - } - Button - { - name: "remove"; - text: qsTr("-") - control.width: height - width: control.width - onClicked: factorsForm.removeFactor() - enabled: factorsFormRepeater.count > 1 - } - } - - } -} diff --git a/QMLComponents/components/JASP/Controls/FactorsList.qml b/QMLComponents/components/JASP/Controls/FactorsList.qml deleted file mode 100644 index e5808df36a3..00000000000 --- a/QMLComponents/components/JASP/Controls/FactorsList.qml +++ /dev/null @@ -1,21 +0,0 @@ -import QtQuick 2.8 -import JASP.Controls 1.0 - -AssignedVariablesList -{ - property alias editableTitle: titleField.value - signal titleIsChanged() - title: " " //dummy - - TextField - { - id: titleField - isBound: false - anchors.top: parent.top - anchors.left: parent.left - fieldWidth: parent.width - } - - Component.onCompleted: titleField.editingFinished.connect(titleIsChanged); - -} diff --git a/QMLComponents/components/JASP/Controls/FileSelector.qml b/QMLComponents/components/JASP/Controls/FileSelector.qml deleted file mode 100644 index d01612c2278..00000000000 --- a/QMLComponents/components/JASP/Controls/FileSelector.qml +++ /dev/null @@ -1,47 +0,0 @@ -import JASP 1.0 -import JASP.Controls 1.0 -import QtQuick 2.11 as QT - -TextField -{ - id : selector - label : save ? qsTr("Save file to:") : qsTr("Load file from:") - property string caption : save ? qsTr("Select file to save") : qsTr("Select file to load") - property bool save : true - property string filter : "*" - property alias buttonText : button.text - property bool directory : false - - implicitWidth : button.x + button.width - - RoundedButton - { - id : button - text : qsTr("Browse") - z : 5 - anchors - { - leftMargin : jaspTheme.generalAnchorMargin - left : control.right - top : selector.top - bottom : selector.bottom - } - - onClicked: - { - var browsedFile; - - if (selector.directory) - browsedFile = messages.browseOpenFolderQML(selector.caption, selector.filter) - else if (selector.save) - browsedFile = messages.browseSaveFileDocumentsQML(selector.caption, selector.filter) - else - browsedFile = messages.browseOpenFileDocumentsQML(selector.caption, selector.filter) - - selector.value = browsedFile; - selector.doEditingFinished(); - } - - } - -} diff --git a/QMLComponents/components/JASP/Controls/Form.qml b/QMLComponents/components/JASP/Controls/Form.qml deleted file mode 100644 index 36cf1a3b351..00000000000 --- a/QMLComponents/components/JASP/Controls/Form.qml +++ /dev/null @@ -1,260 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 -import JASP 1.0 - -AnalysisForm -{ - id : form - implicitWidth : jaspTheme.formWidth - ( 2 * jaspTheme.formMargin ) - implicitHeight : formContent.height + (jaspTheme.formMargin * 2) - width : implicitWidth - height : implicitHeight - //errorMessagesItem : errorMessagesBox - - default property alias content : contentArea.children - property alias form : form - property alias jaspForm : form - property alias jaspAnalysis : form.analysis - property alias _contentArea : contentArea - property real minimumYMsgs : warningMessagesBox.height + warningMessagesBox.y - property int majorVersion : 1 - property int minorVersion : 0 - property int availableWidth : form.width - 2 * jaspTheme.formMargin - property var backgroundForms : undefined - property var customMenu : undefined - property alias columns : contentArea.columns - property bool runAnalysisWhenOptionChange : true - - property int plotHeight : 320 - property int plotWidth : 480 - - - Keys.onPressed: (event) => { event.accepted = true; } //dont let leftover input propagate upwards - - ALTNavigation.enabled: visible - ALTNavigation.scopeOnly: true - ALTNavigation.parent: null //default root - - MouseArea - { - z: -5 - anchors.fill: parent - onClicked: form.forceActiveFocus() - } - - IntegerField { visible: false; name: "plotWidth"; value: plotWidth } - IntegerField { visible: false; name: "plotHeight"; value: plotHeight } - - - FocusScope - { - id: formContent - width: parent.width - height: oldFileMessagesBox.height + errorMessagesBox.height + warningMessagesBox.height + rSyntaxElement.height + contentArea.implicitHeight - anchors - { - top: form.top - left: form.left - } - - Rectangle - { - id: oldFileMessagesBox - visible: needsRefresh && form.hasVolatileNotes //Ill leave the text as is for now to avoid having to go back to the po again - color: jaspTheme.controlWarningBackgroundColor - width: form.implicitWidth - height: visible ? oldAnalysisText.height : 0 - anchors.top: parent.top - radius: jaspTheme.borderRadius - - Text - { - id: oldAnalysisText - color: jaspTheme.controlWarningTextColor - anchors.centerIn: parent - padding: 5 * jaspTheme.uiScale - wrapMode: Text.Wrap - width: parent.width - 10 * jaspTheme.uiScale - verticalAlignment: Text.AlignVCenter - text: qsTr("This analysis was created with an older version of JASP (or a dynamic module)") + //I do not want to bother with formatting strings here to be honest - ( !hasVolatileNotes ? - qsTr(", refreshing could give a slightly different result.") : - qsTr(", to keep your notes where they are it is highly recommended to first refresh your analyses!")) - - } - } - - Rectangle - { - id: errorMessagesBox - visible: form.errors !== "" - color: jaspTheme.controlErrorBackgroundColor - width: form.implicitWidth - height: visible ? errorMessagesText.height : 0 - anchors.top: oldFileMessagesBox.bottom - anchors.margins: visible ? jaspTheme.generalAnchorMargin : 0 - radius: jaspTheme.borderRadius - - Text - { - id: errorMessagesText - anchors.centerIn: parent - padding: 5 * jaspTheme.uiScale - wrapMode: Text.Wrap - width: parent.width - 10 * jaspTheme.uiScale - verticalAlignment: Text.AlignVCenter - text: form.errors - textFormat: Text.StyledText - color: jaspTheme.controlErrorTextColor - linkColor: jaspTheme.controlErrorTextColor - onLinkActivated: Qt.openUrlExternally(link) - - MouseArea - { - anchors.fill: parent - z: 20 - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - - CrossButton { onCrossClicked: form.clearFormErrors() } - } - - - - Rectangle - { - id: warningMessagesBox - visible: form.warnings !== "" - color: jaspTheme.controlWarningBackgroundColor - width: form.implicitWidth - height: visible ? warningMessagesText.height : 0 - anchors.top: errorMessagesBox.bottom - anchors.margins: visible ? jaspTheme.generalAnchorMargin : 0 - radius: jaspTheme.borderRadius - - Text - { - id: warningMessagesText - anchors.centerIn: parent - padding: 5 * jaspTheme.uiScale - wrapMode: Text.Wrap - width: parent.width - 10 * jaspTheme.uiScale - verticalAlignment: Text.AlignVCenter - text: form.warnings - onLinkActivated: Qt.openUrlExternally(link) - textFormat: Text.StyledText - color: jaspTheme.controlWarningTextColor - linkColor: jaspTheme.controlWarningTextColor - - MouseArea - { - anchors.fill: parent - z: 20 - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - - CrossButton { onCrossClicked: form.clearFormWarnings(); warning: true; } - } - - Item - { - id: rSyntaxElement - anchors.top: warningMessagesBox.bottom - width: parent.width - height: visible ? rScriptArea.y + rScriptArea.height : 0 - visible: preferencesModel.showRSyntax && showRButton - - Button - { - id: generateWrapperButton - visible: DEBUG_MODE || form.developerMode - height: visible ? implicitHeight : 0 - label: qsTr("Generate Wrapper") - onClicked: popup.open() - - Popup - { - id: popup - - parent: Overlay.overlay - anchors.centerIn: parent - - width: 400 * jaspTheme.uiScale - height: 600 * jaspTheme.uiScale - - modal: true - - TextArea - { - anchors.fill: parent - isBound: false - applyScriptInfo: "" - control.readOnly: true - control.selectByKeyboard: true - onVisibleChanged: if (visible) text = form.generateWrapper() - } - } - } - - CheckBox - { - id: showAllROptionsCheckBox - anchors.top: generateWrapperButton.visible ? undefined : rSyntaxElement.top - anchors.bottom: generateWrapperButton.visible ? generateWrapperButton.bottom : undefined - anchors.right: rSyntaxElement.right - label: qsTr("Show all options") - isBound: false - checked: showAllROptions - onClicked: setShowAllROptions(!showAllROptions) - } - - TextArea - { - id: rScriptArea - name: form.rSyntaxControlName - - anchors.top: showAllROptionsCheckBox.bottom - anchors.topMargin: jaspTheme.generalAnchorMargin - width: parent.width - height: visible ? 100 * preferencesModel.uiScale : 0 - text: form.rSyntaxText - isBound: false - onApplyRequest: form.sendRSyntax(text) - - onInitializedChanged: if (preferencesModel.showRSyntax) control.forceActiveFocus() // If the textarea has already some large text, then it does not display it if it does not get temporarly the focus... - } - } - - GridLayout - { - id: contentArea - anchors.top: rSyntaxElement.bottom - anchors.margins: warningMessagesBox.visible || errorMessagesBox.visible || rSyntaxElement.visible ? jaspTheme.generalAnchorMargin : 0 - width: form.implicitWidth - } - } - - Component.onCompleted: formCompletedSignal(); -} diff --git a/QMLComponents/components/JASP/Controls/FormulaField.qml b/QMLComponents/components/JASP/Controls/FormulaField.qml deleted file mode 100644 index afb3f0dec28..00000000000 --- a/QMLComponents/components/JASP/Controls/FormulaField.qml +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP.Controls 1.0 -import JASP 1.0 - -TextField -{ - id: formulaField - defaultValue: "0" - property double realValue: 0 - property var realValues: [] - property double min: -Infinity - property double max: Infinity - property int inclusive: JASP.MinMax - property bool multiple: false - property bool parseDefaultValue: true - inputType: multiple ? "formulaArray" : "formula" - fieldWidth: jaspTheme.textFieldWidth / 2 -} diff --git a/QMLComponents/components/JASP/Controls/GridLayout.qml b/QMLComponents/components/JASP/Controls/GridLayout.qml deleted file mode 100644 index 72bd7b36d49..00000000000 --- a/QMLComponents/components/JASP/Controls/GridLayout.qml +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Layouts 1.3 - - -GridLayout -{ - id: gridLayout - rowSpacing: jaspTheme.rowGridSpacing - columnSpacing: jaspTheme.columnGridSpacing - columns: 2 - Layout.alignment: Qt.AlignTop | Qt.AlignLeft - - property int count : children.length - property bool checkFormOverflowWhenLanguageChanged : true - - property int _initialColumns : 2 - - Component.onCompleted: _initialColumns = columns; // Do not bind it! - - onCountChanged: - { - for (var i = 0; i < children.length; i++) - { - if (typeof children[i].alignment !== "undefined") - children[i].Layout.alignment = children[i].alignment; - } - } - - Connections - { - enabled: checkFormOverflowWhenLanguageChanged - target: preferencesModel - function onLanguageCodeChanged() { checkFormOverflowTimer.restart(); } - function onInterfaceFontChanged(font) { checkFormOverflowTimer.restart(); } - } - - Timer - { - id: checkFormOverflowTimer - interval: 50 - onTriggered: checkFormOverflow() - } - - - function checkFormOverflow() - { - if ((typeof jaspForm === 'undefined') || !jaspForm) return false; - - var startColumns = gridLayout.columns; - - if (gridLayout.columns !== gridLayout._initialColumns) - gridLayout.columns = gridLayout._initialColumns; - - var decrementColumns = true; - - while (decrementColumns && gridLayout.columns >= 2) - { - decrementColumns = false; - for (var i = 0; i < gridLayout.children.length; i++) - { - var child = gridLayout.children[i]; - if (child.mapToItem(jaspForm, child.width, 0).x > jaspForm.width) - decrementColumns = true; - } - - if (decrementColumns) - gridLayout.columns--; - } - - return startColumns !== gridLayout.columns; - } -} diff --git a/QMLComponents/components/JASP/Controls/GroupBox.qml b/QMLComponents/components/JASP/Controls/GroupBox.qml deleted file mode 100644 index 85464a4ea59..00000000000 --- a/QMLComponents/components/JASP/Controls/GroupBox.qml +++ /dev/null @@ -1,193 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import QtQuick.Layouts 1.3 as L -import JASP 1.0 - - -JASPControl -{ - id : groupBox - implicitWidth : Math.max(label.realWidth, jaspTheme.groupContentPadding + contentArea.implicitWidth) - implicitHeight : label.realHeight + jaspTheme.titleBottomMargin + contentArea.implicitHeight - L.Layout.leftMargin : indent ? jaspTheme.indentationLength : 0 - controlType : JASPControl.GroupBox - isBound : false - childControlsArea : contentArea - focusOnTab : false - - ALTNavigation.enabled: true - ALTNavigation.onTagMatch: { contentArea.nextItemInFocusChain().forceActiveFocus(); } - - default property alias content: contentArea.children - property int rowSpacing: jaspTheme.rowGroupSpacing - property int columnSpacing: jaspTheme.columnGroupSpacing - property int columns: 1 - property bool indent: false - property bool alignTextFields: true - property alias label: label - - property var _allTextFields: [] - property bool _childrenConnected: false - - Label - { - id: label - anchors.top: groupBox.top - anchors.left: groupBox.left - text: groupBox.title - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - font: jaspTheme.font - visible: groupBox.title ? true : false - - property int realHeight: visible ? implicitHeight : 0 - property int realWidth: visible ? implicitWidth : 0 - - } - - GridLayout - { - id: contentArea - columns: groupBox.columns - anchors.top: groupBox.title ? label.bottom : groupBox.top - anchors.topMargin: groupBox.title ? jaspTheme.titleBottomMargin : 0 - anchors.left: groupBox.left - anchors.leftMargin: groupBox.title ? jaspTheme.groupContentPadding : 0 - rowSpacing: groupBox.rowSpacing - columnSpacing: groupBox.columnSpacing - - checkFormOverflowWhenLanguageChanged: false // the checkFormOverflow is done with the alignment. - } - - Connections - { - target: preferencesModel - function onUiScaleChanged(scale) { alignTextFieldTimer.restart(); } - } - - Connections - { - target: preferencesModel - function onLanguageCodeChanged() { checkFormOverflowAndAlignTimer.restart(); } - } - - Timer - { - // The alignment should be done when the scaling of the TextField's are done - id: alignTextFieldTimer - interval: 50 - onTriggered: _alignTextFields() - } - - Timer - { - id: checkFormOverflowAndAlignTimer - interval: 50 - onTriggered: _checkFormOverflowAndAlign() - } - - Component.onCompleted: - { - for (var i = 0; i < contentArea.children.length; i++) - { - var child = contentArea.children[i]; - if (child.hasOwnProperty('controlType') && child.controlType === JASPControl.TextField) - _allTextFields.push(child) - } - - checkFormOverflowAndAlignTimer.start() - } - - function _alignTextFields() - { - if (!alignTextFields || _allTextFields.length < 1) return; - - var allTextFieldsPerColumn = {} - var columns = []; - var i, j, textField; - - for (i = 0; i < _allTextFields.length; i++) - { - textField = _allTextFields[i]; - if (!_childrenConnected) - // Do not connect visible when component is just completed: the visible value is aparently not yet set for all children. - // So do it with the first time it is aligned. - textField.visibleChanged.connect(_alignTextFields); - - if (textField.visible) - { - if (!allTextFieldsPerColumn.hasOwnProperty(textField.x)) - { - // Cannot use Layout.column to know in which column is the textField. - // Then its x value is used. - allTextFieldsPerColumn[textField.x] = [] - columns.push(textField.x) - } - allTextFieldsPerColumn[textField.x].push(textField) - } - } - - for (i = 0; i < columns.length; i++) - { - var textFields = allTextFieldsPerColumn[columns[i]] - - // To align all the textfields on one column: - // . First search for the Textfield with the longest label (its innerControl x position). - // . Then add an offset (the controlXOffset) to all other textfields so that they are aligned with the longest TextField - if (textFields.length >= 1) - { - textField = textFields[0]; - textField.controlXOffset = 0; - var xMax = textField.innerControl.x; - var longestControl = textField.innerControl; - - for (j = 1; j < textFields.length; j++) - { - textField = textFields[j]; - textField.controlXOffset = 0; - if (xMax < textField.innerControl.x) - { - longestControl = textField.innerControl; - xMax = textField.innerControl.x; - } - } - - for (j = 0; j < textFields.length; j++) - { - textField = textFields[j]; - if (textField.innerControl !== longestControl) - // Cannot use binding here, since innerControl.x depends on the controlXOffset, - // that would generate a binding loop - textField.controlXOffset = (xMax - textField.innerControl.x); - - } - } - } - - _childrenConnected = true; - } - - function _checkFormOverflowAndAlign() - { - _alignTextFields(); - if (contentArea.checkFormOverflow()) - _alignTextFields(); - } -} diff --git a/QMLComponents/components/JASP/Controls/HelpButton.qml b/QMLComponents/components/JASP/Controls/HelpButton.qml deleted file mode 100644 index 59acd29892c..00000000000 --- a/QMLComponents/components/JASP/Controls/HelpButton.qml +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.8 -import QtQuick.Layouts 1.3 -import JASP.Controls 1.0 - -///Simple help button that shows you the 'helpPage'. Only works when run from a Form. -MenuButton -{ - property string helpPage: "" - - //width: 20 * preferencesModel.uiScale - iconSource: jaspTheme.iconPath + "info-button.png" - radius: 100 * preferencesModel.uiScale - buttonPadding: 2 * preferencesModel.uiScale - _scaledDim: 22 * preferencesModel.uiScale - Layout.alignment: Qt.AlignRight - onClicked: helpModel.showOrToggleParticularPageForAnalysis(jaspAnalysis, helpPage) -} diff --git a/QMLComponents/components/JASP/Controls/InputListView.qml b/QMLComponents/components/JASP/Controls/InputListView.qml deleted file mode 100644 index 95f65152c75..00000000000 --- a/QMLComponents/components/JASP/Controls/InputListView.qml +++ /dev/null @@ -1,174 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQml.Models 2.2 -import JASP.Controls 1.0 -import JASP 1.0 - -InputListBase -{ - id : inputListView - background : itemRectangle - implicitWidth : parent.width - implicitHeight : jaspTheme.defaultVariablesFormHeight - shouldStealHover : false - innerControl : itemGridView - - property alias label : inputListView.title - property alias itemGridView : itemGridView - property alias cellHeight : itemGridView.cellHeight - property alias cellWidth : itemGridView.cellWidth - property alias itemTitle : itemTitle - property string rowComponentTitle : "" - - property var defaultValues : [] - property int minRows : 0 - property bool addVirtual : true - property string placeHolder : qsTr("New Value") - - readonly property string deleteIcon : "cross.png" - - Text - { - id : itemTitle - anchors.top : parent.top - anchors.left : parent.left - text : title - height : title ? jaspTheme.variablesListTitle : 0 - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Text - { - anchors.top : parent.top - anchors.right : parent.right - text : rowComponentTitle - height : rowComponentTitle ? jaspTheme.variablesListTitle : 0 - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Rectangle - { - id : itemRectangle - anchors.top : itemTitle.bottom - anchors.left : parent.left - height : inputListView.height - itemTitle.height - width : parent.width - color : debug ? jaspTheme.debugBackgroundColor : jaspTheme.controlBackgroundColor - border.width : 1 - border.color : jaspTheme.borderColor - radius : jaspTheme.borderRadius - - JASPScrollBar - { - id : scrollBar - flickable : itemGridView - manualAnchor : true - vertical : true - z : 1337 - - anchors - { - top : parent.top - right : parent.right - bottom : parent.bottom - margins : 2 - } - } - - GridView - { - id : itemGridView - cellHeight : 20 * preferencesModel.uiScale - cellWidth : width - clip : true - focus : true - anchors.fill : parent - anchors.margins : 4 * preferencesModel.uiScale - anchors.rightMargin : scrollBar.width + anchors.margins - model : inputListView.model - delegate : itemInputComponent - boundsBehavior : Flickable.StopAtBounds - } - } - - Component - { - id: itemInputComponent - - FocusScope - { - id: itemWrapper - height: inputListView.cellHeight - width: scrollBar.visible ? inputListView.cellWidth - scrollBar.width : inputListView.cellWidth - - property bool isDeletable: model.type.includes("deletable") - property bool isVirtual: model.type.includes("virtual") - property var rowComponentItem: model.rowComponent - - Component.onCompleted: - { - textField.fieldWidth = Qt.binding( function() { return itemWrapper.width - (rowComponentItem ? rowComponentItem.width : 0) - deleteIconID.width; }) - textField.focus = true; - - if (rowComponentItem) - { - rowComponentItem.parent = itemWrapper - rowComponentItem.anchors.verticalCenter = itemWrapper.verticalCenter - rowComponentItem.anchors.right = itemWrapper.right - rowComponentItem.anchors.rightMargin = deleteIconID.width - rowComponentItem.enabled = !itemWrapper.isVirtual - } - } - - TextField - { - id: textField - isBound: false - value: (!itemWrapper.isVirtual && model) ? model.name : "" - placeholderText: (itemWrapper.isVirtual && model) ? model.name : "" - useExternalBorder: false - showBorder: false - selectValueOnFocus: true - control.horizontalAlignment: TextInput.AlignLeft - onEditingFinished: inputListView.itemChanged(index, displayValue) - } - - Image - { - id: deleteIconID - source: jaspTheme.iconPath + deleteIcon - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - visible: itemWrapper.isDeletable - height: 16 * preferencesModel.uiScale - width: 16 * preferencesModel.uiScale - z: 2 - - MouseArea - { - anchors.fill: parent - onClicked: itemRemoved(index) - } - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/IntegerField.qml b/QMLComponents/components/JASP/Controls/IntegerField.qml deleted file mode 100644 index 6862147e8a2..00000000000 --- a/QMLComponents/components/JASP/Controls/IntegerField.qml +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP 1.0 - -TextField -{ - id: textField - defaultValue: 0 - property var _prevDefaultValue: 0 - property bool negativeValues: false - property int min: negativeValues ? -2147483647 : 0 // 2^32 - 1 - property int max: 2147483647 - property alias inclusive: intValidator.inclusive - property alias intValidator: intValidator - - inputType: "integer" - validator: JASPDoubleValidator { id: intValidator; bottom: min; top: max; decimals: 0 } - cursorShape: Qt.IBeamCursor - fieldWidth: jaspTheme.numericFieldWidth - - onDefaultValueChanged: - { - if (_prevDefaultValue == value) - value = defaultValue - - _prevDefaultValue = defaultValue; - } -} diff --git a/QMLComponents/components/JASP/Controls/JAGSTextArea.qml b/QMLComponents/components/JASP/Controls/JAGSTextArea.qml deleted file mode 100644 index 82693572feb..00000000000 --- a/QMLComponents/components/JASP/Controls/JAGSTextArea.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 -import JASP.Controls 1.0 -import JASP 1.0 - -TextArea -{ - textType: JASP.TextTypeJAGSmodel -} diff --git a/QMLComponents/components/JASP/Controls/JASPScrollBar.qml b/QMLComponents/components/JASP/Controls/JASPScrollBar.qml deleted file mode 100644 index fa479e278b7..00000000000 --- a/QMLComponents/components/JASP/Controls/JASPScrollBar.qml +++ /dev/null @@ -1,266 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// -// Code based on http://stackoverflow.com/questions/17833103/how-to-create-scrollbar-in-qtquick-2-0 - -import QtQuick 2.0; -import QtQml 2.15 - - -Item -{ - id : scrollbar - width : vertical ? breadth : undefined - height : vertical ? undefined : breadth - visible : flickable.visible && ((vertical ? heightRatio : widthRatio ) < 1.0) - - readonly property int visibleBreadth : bigBar ? jaspTheme.scrollbarBoxWidthBig : jaspTheme.scrollbarBoxWidth - property int breadth : visible ? visibleBreadth : 0 - property int extraMarginRightOrBottom : 0 - property int extraMarginLeftOrTop : 0 - property Item flickable : null - property int minimumLength : 16 * preferencesModel.uiScale - property string bkColor : jaspTheme.white - property string fgColor : jaspTheme.gray - property string pressedColor : jaspTheme.blueLighter - property bool showarrows : false - property bool vertical : true - property bool manualAnchor : false - property bool bigBar : false - property real heightRatio : flickable.height / flickable.contentHeight - property real widthRatio : flickable.width / flickable.contentWidth - - anchors - { - right: manualAnchor ? undefined : flickable.right - bottom: manualAnchor ? undefined : flickable.bottom - top: manualAnchor ? undefined : vertical ? flickable.top : undefined - left: manualAnchor ? undefined : vertical ? undefined : flickable.left - topMargin: manualAnchor ? undefined : vertical ? extraMarginLeftOrTop : undefined - leftMargin: manualAnchor ? undefined : vertical ? undefined : extraMarginLeftOrTop - rightMargin: manualAnchor ? undefined : vertical ? undefined : extraMarginRightOrBottom - bottomMargin: manualAnchor ? undefined : vertical ? extraMarginRightOrBottom : undefined - } - - //scroll to specified element. works for vertical bars only - //Will attempt to scroll element in view with margin - function scrollToElement(targetItem, margin = 0, scrollBehavior = null) - { - if(!vertical) return; - - const coordinates = targetItem.mapToItem(flickable, 0, 0); - const diffYBottom = coordinates.y + Math.min(targetItem.height, flickable.height) - flickable.height; //positive if not visible - const diffYTop = coordinates.y; //negative if not visible - - //check if the object is visible in the scrollAnalyses (with margin) and scroll to it if not - if(scrollBehavior && scrollBehavior.animation && scrollBehavior.animation.running) - return; - - if (diffYBottom > -margin) // scroll down - flickable.contentY = flickable.contentY + Math.max(0, diffYBottom + margin); - else if (diffYTop < margin) //scroll up - flickable.contentY = Math.max(0, flickable.contentY + Math.min(0, diffYTop - margin)); - } - - - function scroll(movement) - { - if(vertical) flickable.contentY = Math.max (0, Math.min (flickable.contentY + (flickable.height * movement), flickable.contentHeight - flickable.height)) ; - else flickable.contentX = Math.max (0, Math.min (flickable.contentX + (flickable.width * movement), flickable.contentWidth - flickable.width)) ; - } - - function scrollDown(smallTicks = false) { scroll( (smallTicks ? 0.05 : 0.125) ); } - function scrollUp (smallTicks = false) { scroll(-(smallTicks ? 0.05 : 0.125) ); } - - function scrollWheel(wheel, smallTicks=false) - { - var tryVertical = true; - if(wheel.pixelDelta.y == 0 && wheel.angleDelta.y == 0) - tryVertical = false; - - if(tryVertical) - { - if(wheel.pixelDelta.y !== 0) scrollbar.scroll(-wheel.pixelDelta.y / scrollbar.height) - else if(wheel.angleDelta.y < 0) scrollbar.scrollDown(smallTicks); - else if(wheel.angleDelta.y > 0) scrollbar.scrollUp( smallTicks); - else wheel.accepted = false - } else { - if(wheel.pixelDelta.x !== 0) scrollbar.scroll(-wheel.pixelDelta.x / scrollbar.width) - else if(wheel.angleDelta.x < 0) scrollbar.scrollDown(smallTicks); - else if(wheel.angleDelta.x > 0) scrollbar.scrollUp( smallTicks); - else wheel.accepted = false - } - } - - Binding - { - restoreMode: Binding.RestoreBinding - target: handle; - property: scrollbar.vertical ? "y" : "x" - when: !clicker.drag.active - value: scrollbar.vertical ? - (flickable.contentY * clicker.drag.maximumY / (flickable.contentHeight - flickable.height)) : - (flickable.contentX * clicker.drag.maximumX / (flickable.contentWidth - flickable.width)) ; - } - - Binding - { - restoreMode: Binding.RestoreBinding - target: flickable - property: scrollbar.vertical ? "contentY" : "contentX" - when: (clicker.drag.active || clicker.pressed) - value: scrollbar.vertical ? - (handle.y * (flickable.contentHeight - flickable.height) / clicker.drag.maximumY) : - (handle.x * (flickable.contentWidth - flickable.width) / clicker.drag.maximumX) ; - } - - Rectangle - { - id: backScrollbar - antialiasing: true - color: bkColor - anchors.fill: parent - border - { - width: 1 - color: jaspTheme.grayDarker - } - - MouseArea - { - id: clicker - hoverEnabled: true - anchors.fill: parent; - cursorShape: Qt.PointingHandCursor - - onWheel: (wheel)=> { scrollbar.scrollWheel(wheel); } - - drag - { - target: handle; - minimumY: !scrollbar.vertical ? 0 : 0 - maximumY: !scrollbar.vertical ? 0 : (groove.height - handle.height) - axis: Drag.XAndYAxis - minimumX: scrollbar.vertical ? 0 : 0 - maximumX: scrollbar.vertical ? 0 : (groove.width - handle.width) - - } - - onClicked: if(scrollbar.vertical) flickable.contentY = (mouse.y / groove.height * (flickable.contentHeight - flickable.height)) ; - else flickable.contentX = (mouse.x / groove.width * (flickable.contentWidth - flickable.width)) ; - - } - } - - MouseArea - { - id: btnUp - height: size - width: size - - property real size: !showarrows ? 0 : scrollbar.vertical ? scrollbar.width : scrollbar.height - - anchors - { - top: parent.top; - left: parent.left; - right: scrollbar.vertical ? parent.right : undefined; - bottom: scrollbar.vertical ? undefined : parent.bottom; - - margins: backScrollbar.border.width + 1 - } - - onClicked: scrollUp (); - - Image - { - source: scrollbar.vertical ? jaspTheme.iconPath + "arrow-up.png" : jaspTheme.iconPath + "arrow-left.png" - visible: showarrows - anchors.fill: parent - sourceSize.width: width * 2 - sourceSize.height: height * 2 - } - } - - MouseArea - { - id: btnDown - height: btnUp.size - width: btnUp.size - - anchors - { - top: scrollbar.vertical ? undefined : parent.top - left: scrollbar.vertical ? parent.left : undefined - right: parent.right - bottom: parent.bottom - margins: backScrollbar.border.width + 1 - } - - onClicked: scrollDown (); - - Image - { - source: scrollbar.vertical ? jaspTheme.iconPath + "arrow-down.png" : jaspTheme.iconPath + "arrow-right.png" - visible: showarrows - anchors.fill: parent - sourceSize.width: width * 2 - sourceSize.height: height * 2 - } - } - - Item - { - id: groove - clip: true - property real basicMargin: backScrollbar.border.width + 1 - property real extraVerticalMargin: scrollbar.vertical ? btnUp.size + 1 : 0 - property real extraHorizontalMargin: !scrollbar.vertical ? btnUp.size + 1 : 0 - - anchors - { - fill: parent - topMargin: basicMargin + extraVerticalMargin - leftMargin: basicMargin + extraHorizontalMargin - rightMargin: basicMargin + extraHorizontalMargin - bottomMargin: basicMargin + extraVerticalMargin - } - - Item - { - id: handle; - height: !scrollbar.vertical ? parent.height : Math.max (scrollbar.minimumLength, (scrollbar.heightRatio * groove.height)) - width: scrollbar.vertical ? parent.width : Math.max (scrollbar.minimumLength, (scrollbar.widthRatio * groove.width)) - anchors - { - top: scrollbar.vertical ? undefined : parent.top - left: scrollbar.vertical ? parent.left : undefined - right: scrollbar.vertical ? parent.right : undefined - bottom: scrollbar.vertical ? undefined : parent.bottom - } - - Rectangle - { - id: backHandle - color: clicker.pressed || clicker.containsMouse ? pressedColor : fgColor - anchors.fill: parent - - Behavior on opacity { enabled: preferencesModel.animationsOn; NumberAnimation { duration: 150; } } - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/JagsTableView.qml b/QMLComponents/components/JASP/Controls/JagsTableView.qml deleted file mode 100644 index 03bde0fcc63..00000000000 --- a/QMLComponents/components/JASP/Controls/JagsTableView.qml +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.0 -import QtQuick.Layouts 1.11 -import JASP.Controls 1.0 -import JASP 1.0 - -BasicThreeButtonTableView -{ - id : jagsTableView - - modelType : JASP.JAGSDataInputModel - itemType : JASP.String - initialColumnCount : 2 - initialRowCount : 0 - - property int maxDataEntries : 30 - - - buttonAddText : qsTr("Add Data") - onAddClicked : tableView.addRow() - buttonAddEnabled : tableView.columnCount > 0 && tableView.rowCount < maxDataEntries - - buttonDeleteText : qsTr("Delete Data") - onDeleteClicked : tableView.removeARow() - buttonDeleteEnabled : tableView.rowCount > 0 - - buttonResetText : qsTr("Reset") - onResetClicked : tableView.reset() - buttonResetEnabled : tableView.rowCount > 0 -} diff --git a/QMLComponents/components/JASP/Controls/Label.qml b/QMLComponents/components/JASP/Controls/Label.qml deleted file mode 100644 index 856c71a037b..00000000000 --- a/QMLComponents/components/JASP/Controls/Label.qml +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick -import QtQuick.Controls - - -Label -{ - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled -} diff --git a/QMLComponents/components/JASP/Controls/MenuButton.qml b/QMLComponents/components/JASP/Controls/MenuButton.qml deleted file mode 100644 index 38f958fbf95..00000000000 --- a/QMLComponents/components/JASP/Controls/MenuButton.qml +++ /dev/null @@ -1,54 +0,0 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import JASP.Controls 1.0 - -RoundedButton -{ - property bool hasSubMenu: false - property bool showHovered: hasSubMenu ? delayOnhoverTimer.running : hovered - property color defaultColor: "transparent" - - id: root - font: jaspTheme.fontRibbon - color: (_pressed || activeFocus) ? jaspTheme.buttonColorPressed : (showHovered || selected) ? jaspTheme.buttonColorHovered : defaultColor - border.width: 0 - centerText: false - activeFocusOnTab: true - - signal hoverClicked(); - onHoverClicked: forceActiveFocus(); - - Timer - { - id: delayOnhoverTimer - interval: jaspTheme.hoverTime - running: false - repeat: false - onTriggered: if (hovered && root.hasSubMenu) root.hoverClicked(); - } - - onClicked: delayOnhoverTimer.stop(); - onHoveredChanged: if (hasSubMenu) - { - if (hovered) delayOnhoverTimer.start() - else delayOnhoverTimer.stop() - } - - Image - { - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: jaspTheme.generalAnchorMargin - height: jaspTheme.subMenuIconHeight - width: height - source: root.hasSubMenu ? jaspTheme.iconPath + "/large-arrow-right.png" : "" - visible: hasSubMenu - opacity: enabled ? ((hovered || activeFocus) ? 1 : 0.5) : 0.3 - smooth: true - mipmap: true - sourceSize.width: width * 2 - sourceSize.height: height * 2 - } - -} diff --git a/QMLComponents/components/JASP/Controls/ModelTermsList.qml b/QMLComponents/components/JASP/Controls/ModelTermsList.qml deleted file mode 100644 index 91341f3491d..00000000000 --- a/QMLComponents/components/JASP/Controls/ModelTermsList.qml +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP 1.0 - - -VariablesList -{ - dropMode : JASP.DropInsert - name : "modelTerms" - title : qsTr("Model Terms") - listViewType : JASP.Interaction - - rowComponentTitle : qsTr("Add to null model") - interactionHighOrderCheckBox : "isNuisance" - rowComponent : CheckBox - { - name: "isNuisance" - Component.onCompleted: - { - if ((typeof(isNew) !== 'undefined') && isNew) - checked = (listView.getSourceType(rowValue) === "randomFactors") - } - } -} diff --git a/QMLComponents/components/JASP/Controls/PercentField.qml b/QMLComponents/components/JASP/Controls/PercentField.qml deleted file mode 100644 index 3f18153c7e5..00000000000 --- a/QMLComponents/components/JASP/Controls/PercentField.qml +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import JASP.Controls 1.0 - -import JASP 1.0 - -DoubleField -{ - id: percentField - property bool showPercent: true - - defaultValue: 50 - decimals: 0 - min: 0 - max: 100 - inputType: "percent" - fieldWidth: jaspTheme.font.pixelSize * (percentField.decimals + 3) - - afterLabel: showPercent ? "%" : "" - cursorShape: Qt.IBeamCursor -} diff --git a/QMLComponents/components/JASP/Controls/RadioButton.qml b/QMLComponents/components/JASP/Controls/RadioButton.qml deleted file mode 100644 index 822deff6fb1..00000000000 --- a/QMLComponents/components/JASP/Controls/RadioButton.qml +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP 1.0 - - -RadioButtonBase -{ - id: radioButton - implicitWidth: childrenOnSameRow - ? control.implicitWidth + (childControlsArea.children.length > 0 ? jaspTheme.columnGroupSpacing + childControlsArea.implicitWidth : 0) - : Math.max(control.implicitWidth, childControlsArea.childControlsPadding + childControlsArea.implicitWidth) - implicitHeight: childrenOnSameRow - ? Math.max(control.implicitHeight, childControlsArea.implicitHeight) - : control.implicitHeight + (childControlsArea.children.length > 0 ? jaspTheme.rowGroupSpacing + childControlsArea.implicitHeight : 0) - focusIndicator: focusIndicator - childControlsArea: childControlsArea - innerControl: control - title: label.text - - property alias control: control - default property alias content: childControlsArea.children - - property alias childrenArea: childControlsArea - property alias text: control.text - property alias label: control.text - property alias checked: control.checked - property alias value: radioButton.name - property bool childrenOnSameRow: false - property alias columns: childControlsArea.columns - property bool enableChildrenOnChecked: true - property bool indentChildren: true - - function click() { clicked(); } - onClicked: { radioButton.clickHandler(); } - - - RadioButton - { - id: control - padding: jaspTheme.jaspControlPadding - focus: true - - onCheckedChanged: if (checked) radioButton.clicked() - - indicator: Rectangle - { - id: radioIndicator - width: height - height: Math.floor(Math.round(label.height) / 2) * 2 - x: control.padding - y: control.padding - - radius: width - color: control.checked ? (control.enabled ? jaspTheme.buttonBackgroundColor : jaspTheme.controlDisabledBackgroundColor) : jaspTheme.controlBackgroundColor - border.color: control.enabled ? (control.checked ? jaspTheme.buttonBackgroundColor : jaspTheme.borderColor) : jaspTheme.controlDisabledBackgroundColor - border.width: 1 - - Rectangle - { - anchors.centerIn: parent - width: Math.round(parent.width / 4) * 2 - height: width - radius: width - visible: control.checked - color: jaspTheme.controlBackgroundColor - } - } - - Rectangle - { - id: focusIndicator - anchors.centerIn: radioIndicator - width: Math.floor(Math.round(radioIndicator.width + jaspTheme.jaspControlHighlightWidth) / 2) * 2 - height: Math.floor(Math.round(radioIndicator.height + jaspTheme.jaspControlHighlightWidth) / 2) * 2 - radius: width - color: "transparent" - border.width: 0 - - } - - contentItem: Label - { - id: label - text: control.text - leftPadding: radioIndicator.width + control.spacing - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - background: Rectangle { color: "transparent" } - } - - GridLayout - { - id: childControlsArea - anchors - { - top: childrenOnSameRow ? control.top : control.bottom - topMargin: childrenOnSameRow ? 0 : jaspTheme.rowGroupSpacing - left: childrenOnSameRow ? control.right : control.left - leftMargin: childrenOnSameRow ? jaspTheme.columnGroupSpacing : (indentChildren ? childControlsArea.childControlsPadding : 0) - } - - enabled: enableChildrenOnChecked ? control.checked : true - visible: children.length > 0 - columns: childrenOnSameRow ? children.length : 1 - rowSpacing: jaspTheme.rowGroupSpacing - columnSpacing: jaspTheme.columnGridSpacing - - property int childControlsPadding: childrenOnSameRow ? control.implicitWidth + jaspTheme.columnGroupSpacing : control.padding + radioIndicator.width + control.spacing - } - - Component.onCompleted: - { - if (childControlsArea.children.length > 0) - { - if (childrenOnSameRow) - { - if (childControlsArea.implicitHeight < control.implicitHeight) - childControlsArea.anchors.topMargin = control.padding - 1 // border width - } - } - registerWithParent(); - } - - Component.onDestruction: - { - unregisterRadioButton(); - } -} - diff --git a/QMLComponents/components/JASP/Controls/RadioButtonGroup.qml b/QMLComponents/components/JASP/Controls/RadioButtonGroup.qml deleted file mode 100644 index 988ad1df83c..00000000000 --- a/QMLComponents/components/JASP/Controls/RadioButtonGroup.qml +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import QtQuick.Layouts 1.3 as L -import JASP 1.0 - - -RadioButtonsGroupBase -{ - id: control - childControlsArea: contentArea - focusOnTab: false - shouldStealHover: false - - default property alias content: contentArea.children - property bool radioButtonsOnSameRow: false - property alias columns: contentArea.columns - property alias text: control.title - property int leftPadding: jaspTheme.groupContentPadding - - implicitWidth: radioButtonsOnSameRow - ? contentArea.x + contentArea.implicitWidth - : Math.max(label.implicitWidth, contentArea.x + contentArea.implicitWidth) - - implicitHeight: radioButtonsOnSameRow - ? Math.max(label.implicitHeight, contentArea.implicitHeight) - : contentArea.y + contentArea.implicitHeight - - L.Layout.leftMargin: indent ? jaspTheme.indentationLength : 0 - - Label - { - id: label - text: control.title - visible: control.title && control.visible ? true : false - anchors.top: control.top - anchors.left: control.left - anchors.bottom: radioButtonsOnSameRow ? contentArea.bottom : undefined - verticalAlignment: Text.AlignVCenter - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - - GridLayout - { - id: contentArea - rowSpacing: jaspTheme.rowGroupSpacing - columnSpacing: jaspTheme.columnGroupSpacing - columns: radioButtonsOnSameRow ? children.length : 1 - anchors.top: control.title && !radioButtonsOnSameRow ? label.bottom : control.top - anchors.topMargin: control.title && !radioButtonsOnSameRow ? jaspTheme.titleBottomMargin : 0 - anchors.left: control.title && radioButtonsOnSameRow ? label.right : control.left - anchors.leftMargin: control.title ? jaspTheme.groupContentPadding : 0 - } - - background: backgroundBox - - Rectangle - { - // This rectangle is only here to show the dependency outline for "Show Dependencies" - id: backgroundBox - color: "transparent" - border.width: 0 - anchors.fill: parent - anchors.margins: -1 * border.width - z: -1 - visible: preferencesModel.developerMode - } -} diff --git a/QMLComponents/components/JASP/Controls/RectangularButton.qml b/QMLComponents/components/JASP/Controls/RectangularButton.qml deleted file mode 100644 index f2728caa4e5..00000000000 --- a/QMLComponents/components/JASP/Controls/RectangularButton.qml +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.9 -import QtQuick.Controls 2.4 - - -Item -{ - id: filterButtonRoot - - property string text: "" - property string toolTip: "" - property string textColor: "default" - property bool selected: activeFocus - property string iconSource: "" - property real buttonPadding: 6 * preferencesModel.uiScale - property real buttonWidthPadding: buttonPadding - property alias hovered: buttonMouseArea.containsMouse - property bool showIconAndText: false - property bool centerText: true - property bool iconLeft: true - property bool isLink: false - - property real _scaledDim: Math.max(jaspTheme.defaultRectangularButtonHeight, buttonText.height + 2 * buttonPadding) - property alias _pressed: buttonMouseArea.pressed - property alias color: rect.color - property alias border: rect.border - property alias radius: rect.radius - property alias font: buttonText.font - property alias icon: buttonIcon - - //on_ScaledDimChanged: console.log("Button " + text + ": " + _scaledDim + ", text height: " + buttonText.height + ", content height: " + buttonText.contentHeight + ", padding: " + buttonPadding) - - focus: true - implicitWidth: showIconAndText ? - buttonText.implicitWidth + buttonWidthPadding + _scaledDim + buttonWidthPadding : - buttonIcon.visible ? _scaledDim : buttonText.implicitWidth + ( 2 * buttonWidthPadding) - implicitHeight: _scaledDim - width: implicitWidth - height: implicitHeight - - - ToolTip.text: toolTip - ToolTip.timeout: jaspTheme.toolTipTimeout - ToolTip.delay: jaspTheme.toolTipDelay - ToolTip.visible: toolTip !== "" && buttonMouseArea.containsMouse - - Keys.onSpacePressed: clicked(); - Keys.onEnterPressed: clicked(); - Keys.onReturnPressed: (event)=> clicked(); - - signal clicked() - - Rectangle - { - id: rect - - color: !enabled ? jaspTheme.buttonColorDisabled - : _pressed ? jaspTheme.buttonColorPressed - : (filterButtonRoot.hovered || filterButtonRoot.activeFocus) ? jaspTheme.buttonColorHovered - : jaspTheme.buttonColor - border.color: (filterButtonRoot.hovered || selected) ? jaspTheme.buttonBorderColorHovered - : jaspTheme.buttonBorderColor - border.width: 1 - width: parent.width - height: parent.height - - MouseArea - { - id: buttonMouseArea - anchors.fill: parent - acceptedButtons: Qt.LeftButton - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: filterButtonRoot.clicked(); - visible: filterButtonRoot.enabled - //propagateComposedEvents: true - } - - Image - { - id: buttonIcon - x: !filterButtonRoot.showIconAndText ? - (parent.width / 2) - (width / 2) : - filterButtonRoot.iconLeft ? - filterButtonRoot.buttonWidthPadding : - parent.width - (width + filterButtonRoot.buttonWidthPadding) - - y: (parent.height / 2) - (height / 2) - - width: Math.min(filterButtonRoot.width - (2 * buttonWidthPadding), height) - height: filterButtonRoot.height - (2 * buttonPadding) - - // sourceSize.width: Math.max(96, width * 2) - // sourceSize.height: Math.max(96, height * 2) - - visible: filterButtonRoot.iconSource != "" || filterButtonRoot.showIconAndText - source: filterButtonRoot.iconSource - mipmap: true - smooth: true - } - - Text - { - id: buttonText - x: filterButtonRoot.centerText ? - (parent.width / 2) - (contentWidth / 2) : - !buttonIcon.visible || !filterButtonRoot.iconLeft ? - filterButtonRoot.buttonWidthPadding : - buttonIcon.x + buttonIcon.width - - - y: (parent.height / 2) - (height / 2) - - text: filterButtonRoot.text - wrapMode: Text.Wrap - visible: filterButtonRoot.iconSource == "" || filterButtonRoot.showIconAndText - color: isLink - ? (enabled ? jaspTheme.blueDarker : jaspTheme.textDisabled) - : (textColor == "default" - ? (filterButtonRoot.enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled) - : textColor) - - - font: isLink ? jaspTheme.fontLink : jaspTheme.font - //font.pixelSize: jaspTheme. //Math.max(filterButtonRoot.height * 0.4, Math.min(12 * preferencesModel.uiScale, filterButtonRoot.height - 2)) - - //height: contentHeight - width: filterButtonRoot.width - 2 * buttonWidthPadding //implicitWidth //Math.min(implicitWidth, parent.width - (( buttonIcon.visible ? buttonIcon.width : 0 ) + (filterButtonRoot.buttonPadding * 2))) - - - elide: Text.ElideMiddle - } - } -} diff --git a/QMLComponents/components/JASP/Controls/RoundedButton.qml b/QMLComponents/components/JASP/Controls/RoundedButton.qml deleted file mode 100644 index 3dbde8a8bb1..00000000000 --- a/QMLComponents/components/JASP/Controls/RoundedButton.qml +++ /dev/null @@ -1,6 +0,0 @@ -import QtQuick 2.0 - -RectangularButton -{ - radius: jaspTheme.borderRadius -} diff --git a/QMLComponents/components/JASP/Controls/RowLayout.qml b/QMLComponents/components/JASP/Controls/RowLayout.qml deleted file mode 100644 index 992d70e1ef8..00000000000 --- a/QMLComponents/components/JASP/Controls/RowLayout.qml +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Layouts 1.3 - -RowLayout -{ - spacing: jaspTheme.rowGridSpacing - Layout.alignment: Qt.AlignTop | Qt.AlignLeft -} diff --git a/QMLComponents/components/JASP/Controls/SetSeed.qml b/QMLComponents/components/JASP/Controls/SetSeed.qml deleted file mode 100644 index a867c10f5f0..00000000000 --- a/QMLComponents/components/JASP/Controls/SetSeed.qml +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.8 -import JASP.Controls 1.0 - -Group -{ - title: qsTr("Repeatability") - - CheckBox { - name: "setSeed" - text: qsTr("Set seed:") - childrenOnSameRow: true - - IntegerField { - name: "seed" - defaultValue: 1 - min: -999999 - max: 999999 - fieldWidth: 60 - } - } -} diff --git a/QMLComponents/components/JASP/Controls/SimpleTableView.qml b/QMLComponents/components/JASP/Controls/SimpleTableView.qml deleted file mode 100644 index b551acd0939..00000000000 --- a/QMLComponents/components/JASP/Controls/SimpleTableView.qml +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.0 -import QtQuick.Layouts 1.11 -import JASP.Controls 1.0 -import JASP 1.0 - -BasicThreeButtonTableView -{ - modelType : JASP.Simple - - buttonAddText : qsTr("Add Column") - onAddClicked : tableView.addColumn() - buttonAddEnabled : true - - buttonDeleteText : qsTr("Delete Column") - onDeleteClicked : tableView.removeAColumn() - buttonDeleteEnabled : tableView.columnCount > initialColumnCount - - buttonResetText : qsTr("Reset") - onResetClicked : tableView.reset() - buttonResetEnabled : tableView.columnCount > initialColumnCount -} diff --git a/QMLComponents/components/JASP/Controls/Slider.qml b/QMLComponents/components/JASP/Controls/Slider.qml deleted file mode 100644 index 9b9d57bbed0..00000000000 --- a/QMLComponents/components/JASP/Controls/Slider.qml +++ /dev/null @@ -1,131 +0,0 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP.Controls 1.0 as JC //He returns! -import QtQuick.Layouts 1.3 -import JASP 1.0 - -SliderBase -{ - id: slider - implicitHeight: columnLayout.implicitHeight - implicitWidth: columnLayout.implicitWidth - innerControl: textField - title: controlLabel.text - focusOnTab: false - - property alias control: textField - property int decimals: 2 - property int power: Math.pow(10, decimals); - property alias label: controlLabel.text - property alias controlLabel: controlLabel - property alias value: control.value - property bool vertical: true - property int verticalInt: vertical ? Qt.Vertical : Qt.Horizontal - property alias orientation: control.orientation - property alias stepSize: control.stepSize - property alias from: control.from - property alias to: control.to - property alias min: control.from - property alias max: control.to - property alias textField: textField - - Component.onCompleted: control.moved.connect(moved); - - GridLayout - { - id: columnLayout; - rows: control.vertical ? 3 : 1 - columns: control.vertical ? 1 : 3 - - Label - { - id: controlLabel - visible: controlLabel.text && slider.visible ? true : false - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Slider - { - id: control - Layout.alignment: Qt.AlignCenter - Layout.leftMargin: control.orientation === Qt.Vertical ? leftPadding + jaspTheme.sliderWidth : 0 - value: 0.5 - stepSize: 1 / slider.power - orientation: slider.verticalInt - activeFocusOnTab: false - - background: Rectangle - { - id: sliderBackground - x: control.leftPadding - y: control.topPadding + (control.vertical ? 0 : control.height / 4) - implicitWidth: control.vertical ? jaspTheme.sliderWidth : jaspTheme.sliderLength - implicitHeight: control.vertical ? jaspTheme.sliderLength : jaspTheme.sliderWidth - width: control.vertical ? implicitWidth : control.availableWidth - height: control.vertical ? control.availableHeight : implicitHeight - radius: jaspTheme.sliderWidth / 2 - color: control.vertical ? jaspTheme.sliderPartOn : jaspTheme.sliderPartOff - - Rectangle - { - width: control.vertical ? parent.width : control.visualPosition * parent.width - height: control.vertical ? control.visualPosition * parent.height : parent.height - color: control.vertical ? jaspTheme.sliderPartOff : jaspTheme.sliderPartOn - radius: jaspTheme.sliderWidth / 2 - } - } - - handle: Rectangle - { - id: sliderHandle - x: control.leftPadding + (control.vertical ? sliderBackground.radius - sliderHandle.radius : control.visualPosition * (control.availableWidth - width)) - y: control.topPadding + (control.vertical ? control.visualPosition * (control.availableHeight - height) : sliderBackground.radius - sliderHandle.radius) + (control.vertical ? 0 : control.height / 4) - implicitWidth: jaspTheme.sliderHandleDiameter - implicitHeight: jaspTheme.sliderHandleDiameter - radius: jaspTheme.sliderHandleDiameter / 2 - color: control.pressed ? jaspTheme.itemSelectedColor : jaspTheme.controlBackgroundColor - border.color: jaspTheme.borderColor - } - - onMoved: - { - var intVal = Math.round(value * slider.power); - var realVal = intVal / slider.power; - - if (textField.value != realVal) textField.value = realVal; - } - - onValueChanged: - { - var intVal = Math.round(value * slider.power); - var realVal = intVal / slider.power; - value = realVal; - } - - } - - JC.DoubleField - { - id: textField - value: control.value - isBound: false - Layout.alignment: Qt.AlignCenter - validator: JASPDoubleValidator { bottom: control.from; top: control.to; decimals: slider.decimals } - - onEditingFinished: - { - if (control.value != displayValue) - { - control.value = displayValue; - control.moved(); - } - } - onTextEdited: - { - if (value && !textField.innerControl.acceptableInput) - value = control.value - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/SortMenuButton.qml b/QMLComponents/components/JASP/Controls/SortMenuButton.qml deleted file mode 100644 index 1de6d358807..00000000000 --- a/QMLComponents/components/JASP/Controls/SortMenuButton.qml +++ /dev/null @@ -1,39 +0,0 @@ -import QtQuick 2.0 - - -MenuButton -{ - id: sortButton - _scaledDim: 24 * preferencesModel.uiScale - width: height - toolTip: qsTr("Sort the items") - radius: height - iconSource: jaspTheme.iconPath + "/sort-az.png" - z: 10 - defaultColor: jaspTheme.buttonColor - opacity: enabled ? 1 : 0.5 - - property var sortMenuModel: null - property int scrollXPosition: 0 - property int scrollYPosition: 0 - property point scrollPosition: Qt.point(scrollXPosition, scrollYPosition) - - onClicked: - { - var functionCall = function (index) - { - sortMenuModel.clickSortItem(index) - customMenu.hide() - } - - var props = { - "model": sortMenuModel, - "functionCall" : functionCall - }; - - customMenu.toggle(sortButton, props, 0, sortButton.height); - customMenu.scrollOri = scrollPosition; - customMenu.menuScroll.y = Qt.binding(function() { return -1 * (scrollPosition.y - customMenu.scrollOri.y); }); - } - -} diff --git a/QMLComponents/components/JASP/Controls/SubjectivePriors.qml b/QMLComponents/components/JASP/Controls/SubjectivePriors.qml deleted file mode 100644 index 1a04d27a413..00000000000 --- a/QMLComponents/components/JASP/Controls/SubjectivePriors.qml +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.8 -import QtQuick.Layouts 1.3 -import JASP.Controls 1.0 -import JASP 1.0 - -Section -{ - title: qsTr("Prior") - property alias informedPriorsEnabled: informedPriors.enabled - property alias defaultPriorsChecked: defaultPriors.checked - - RadioButtonGroup - { - name: "effectSize" - RadioButton - { - label: qsTr("Standardized effect size") - name: "standardized" - debug: true - checked: true - id: standardized - } - - RadioButtonGroup - { - name: "effectSizeStandardized" - indent: DEBUG_MODE - enabled: standardized.checked - RadioButton - { - id: defaultPriors - label: qsTr("Default"); name: "default"; checked: true - RadioButtonGroup - { - name: "defaultStandardizedEffectSize" - RadioButton - { - label: qsTr("Cauchy"); name: "cauchy"; checked: true; childrenOnSameRow: true - DoubleField { label: qsTr("scale"); name: "priorWidth"; defaultValue: 0.707; fieldWidth: 50; max: 2; inclusive: JASP.MaxOnly } - } - } - } - - RadioButton - { - id: informedPriors - label: qsTr("Informed"); name: "informative" - RadioButtonGroup - { - name: "informativeStandardizedEffectSize" - RadioButton - { - label: qsTr("Cauchy"); name: "cauchy"; checked: true; childrenOnSameRow: true; id: cauchyInformative - DoubleField { label: qsTr("location:"); name: "informativeCauchyLocation"; visible: cauchyInformative.checked; defaultValue: 0; min: -3; max: 3 } - DoubleField { label: qsTr("scale:"); name: "informativeCauchyScale"; visible: cauchyInformative.checked; defaultValue: 0.707; fieldWidth: 50; max: 2; inclusive: JASP.MaxOnly } - } - RadioButton - { - label: qsTr("Normal"); name: "normal"; childrenOnSameRow: true; id: normalInformative - DoubleField { label: qsTr("mean:"); name: "informativeNormalMean"; visible: normalInformative.checked; defaultValue: 0; min: -3; max: 3 } - DoubleField { label: qsTr("std:"); name: "informativeNormalStd"; visible: normalInformative.checked; defaultValue: 0.707; fieldWidth: 50; max: 2 } - } - RadioButton - { - label: qsTr("t"); name: "t"; childrenOnSameRow: true; id: tInformative - DoubleField { label: qsTr("location:"); name: "informativeTLocation"; visible: tInformative.checked; defaultValue: 0; min: -3; max: 3 } - DoubleField { label: qsTr("scale:"); name: "informativeTScale"; visible: tInformative.checked; defaultValue: 0.707; fieldWidth: 50; max: 2; inclusive: JASP.MaxOnly } - DoubleField { label: qsTr("df:"); name: "informativeTDf"; visible: tInformative.checked; defaultValue: 1; min: 1; max: 100 } - } - } - } - } - - RadioButton - { - label: qsTr("Raw effect size (Dienes)"); name: "dienes"; debug: true - RadioButtonGroup - { - debug: true - name: "dienesEffectSize" - RadioButton - { - label: qsTr("Uniform"); name: "uniform"; checked: true; childrenOnSameRow: true; id: uniformDienes - DoubleField { label: qsTr("lower bound:"); name: "uniformDienesLowerBound"; visible: uniformDienes.checked; defaultValue: 0.707; fieldWidth: 50; min: 0; max: 2 } - DoubleField { label: qsTr("upper bound:"); name: "uniformDienesUpperBound"; visible: uniformDienes.checked; defaultValue: 0.707; fieldWidth: 50; min: 0; max: 2 } - } - RadioButton - { - label: qsTr("Half-normal"); name: "half_normal"; childrenOnSameRow: true; id: halfNormalDienes - DoubleField { label: qsTr("std:"); name: "halfNormalDienesStd"; visible: halfNormalDienes.checked; defaultValue: 0.707; fieldWidth: 50; min: 0; max: 2 } - } - RadioButton - { - label: qsTr("Normal"); name: "normal"; childrenOnSameRow: true; id: normalDienes - DoubleField { label: qsTr("mean:"); name: "normalDienesMean"; visible: normalDienes.checked; defaultValue: 0.707; fieldWidth: 50; min: 0; max: 2 } - DoubleField { label: qsTr("std:"); name: "normalDienesStd"; visible: normalDienes.checked; defaultValue: 0.707; fieldWidth: 50; min: 0; max: 2 } - } - } - } - } - -} diff --git a/QMLComponents/components/JASP/Controls/Switch.qml b/QMLComponents/components/JASP/Controls/Switch.qml deleted file mode 100644 index dc3597159ff..00000000000 --- a/QMLComponents/components/JASP/Controls/Switch.qml +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import JASP 1.0 - -CheckBoxBase -{ - implicitWidth: control.indicator.height + (4 * preferencesModel.uiScale) - implicitHeight: control.indicator.width + controlLabel.implicitWidth + control.spacing + (6 * preferencesModel.uiScale) - innerControl: control - title: label - - property alias control: control - property alias label: control.text - property alias checked: control.checked - signal clicked(); - - Component.onCompleted: control.clicked.connect(clicked); - - Switch - { - id: control - anchors.fill: parent - - indicator: Rectangle - { - id: switchHandle - width: jaspTheme.switchHeight * 2.2 - height: jaspTheme.switchHeight - radius: jaspTheme.switchHeight / 2 - color: jaspTheme.light - border.color: jaspTheme.borderColor - anchors - { - left: control.left - leftMargin: 2 * preferencesModel.uiScale - top: control.top - topMargin: 2 * preferencesModel.uiScale - } - - Rectangle - { - id: rectangle - width: jaspTheme.switchHeight - height: jaspTheme.switchHeight - radius: jaspTheme.switchHeight / 2 - color: jaspTheme.light - border.color: jaspTheme.borderColor - } - } - - contentItem: Label - { - id: controlLabel - text: control.text - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - anchors - { - left: control.indicator.right - leftMargin: control.spacing - top: control.top - topMargin: 2 * preferencesModel.uiScale - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/TabView.qml b/QMLComponents/components/JASP/Controls/TabView.qml deleted file mode 100644 index 701d6eee55b..00000000000 --- a/QMLComponents/components/JASP/Controls/TabView.qml +++ /dev/null @@ -1,243 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.11 -import QtQuick.Controls 2.5 as QtControls -import QtQuick.Layouts 1.3 -import JASP 1.0 - -ComponentsListBase -{ - id : tabView - background : rectangleItem - implicitWidth : parent.width - implicitHeight : itemStack.y + itemStack.height - shouldStealHover : false - innerControl : itemTabBar - addItemManually : !source - minimumItems : 1 - newItemName : qsTr("New tab") - controlType : JASPControl.TabView - - property alias label : tabView.title - property bool showAddIcon : addItemManually - property bool showRemoveIcon : addItemManually - property bool tabNameEditable : addItemManually - property string removeIcon : "cross.png" - property string addIcon : "duplicate.png" - property string addTooltip : qsTr("Add a tab") - property string removeTooltip : qsTr("Remove this tab") - property alias newTabName : tabView.newItemName - property alias itemTabBar : itemTabBar - property alias itemTitle : itemTitle - property alias content : tabView.rowComponent - property alias currentIndex : itemTabBar.currentIndex - property var buttonComponent : defaultButtonButton - - Text - { - id : itemTitle - anchors.top : parent.top - anchors.left : parent.left - text : title - height : title ? jaspTheme.variablesListTitle : 0 - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Component - { - id: defaultButtonButton - - QtControls.TabButton - { - id : tabButton - width : Math.min(100, (rectangleItem.width - itemRepeater.count - (showAddIcon ? addIconItem.width : 0)) / itemRepeater.count) - contentItem: Text - { - color : jaspTheme.black - text : model.name - horizontalAlignment : Text.AlignLeft - verticalAlignment : Text.AlignVCenter - elide : Text.ElideRight - width : parent.width - (removeIconItem.visible ? (removeIconItem.width + 2 * jaspTheme.labelSpacing) : 0) - } - - background: Rectangle - { - color : itemTabBar.currentIndex === index ? jaspTheme.analysisBackgroundColor : jaspTheme.grayLighter - - Rectangle - { - anchors - { - right : parent.right - bottom : parent.bottom - top : parent.top - bottomMargin : 4 * preferencesModel.uiScale - topMargin : 4 * preferencesModel.uiScale - } - - visible: index == tabView.count - 1 || (itemTabBar.currentIndex != index && itemTabBar.currentIndex != index + 1) - - width : 1 - color : jaspTheme.gray - } - } - - onDoubleClicked: - { - if (tabNameEditable) - { - textFieldItem.visible = true - textFieldItem.forceActiveFocus(); - } - } - - TextField - { - id : textFieldItem - z : 3 - isBound : false - visible : false - useExternalBorder : false - value : model.name - fieldWidth : parent.width - fieldHeight : parent.height - onEditingFinished : tabView.nameChanged(index, displayValue) - - onActiveFocusChanged: if (!activeFocus) visible = false - } - - Image - { - id : removeIconItem - source : jaspTheme.iconPath + tabView.removeIcon - anchors.right : parent.right - anchors.rightMargin : 4 * preferencesModel.uiScale - anchors.verticalCenter : parent.verticalCenter - visible : tabView.showRemoveIcon && tabView.minimumItems < tabView.count - height : jaspTheme.iconSize * preferencesModel.uiScale - width : jaspTheme.iconSize * preferencesModel.uiScale - z : 2 - - QtControls.ToolTip.text : removeTooltip - QtControls.ToolTip.timeout : jaspTheme.toolTipTimeout - QtControls.ToolTip.delay : jaspTheme.toolTipDelay - QtControls.ToolTip.visible : removeTooltip !== "" && deleteMouseArea.containsMouse - - MouseArea - { - id : deleteMouseArea - anchors.fill : parent - onClicked : tabView.removeItem(index) - } - } - } - } - - Rectangle - { - id : rectangleItem - - anchors.top : itemTitle.bottom - anchors.left : parent.left - height : itemTabBar.height + itemStack.height + 2 * preferencesModel.uiScale - width : parent.width - - color : "transparent" - radius : jaspTheme.borderRadius - border.color : jaspTheme.borderColor - border.width : 1 - z : 2 - } - - QtControls.TabBar - { - id : itemTabBar - anchors - { - top : itemTitle.bottom - left : parent.left - } - - background: Rectangle - { - color: jaspTheme.grayLighter - } - - Repeater - { - id : itemRepeater - model : tabView.model - delegate : tabView.buttonComponent - } - } - - MenuButton - { - id : addIconItem - height : 28 * preferencesModel.uiScale //jaspTheme.defaultRectangularButtonHeight - width : height - radius : height - visible : tabView.showAddIcon && (tabView.maximumItems <= 0 || tabView.maximumItems > tabView.count) - iconSource : jaspTheme.iconPath + tabView.addIcon - onClicked : addItem() - toolTip : tabView.addTooltip - anchors - { - left : itemTabBar.right - verticalCenter : itemTabBar.verticalCenter - } - } - - StackLayout - { - id : itemStack - anchors - { - top : itemTabBar.bottom - topMargin : 2 * preferencesModel.uiScale - left : parent.left - right : parent.right - } - - currentIndex : itemTabBar.currentIndex - - Repeater - { - model : tabView.model - FocusScope - { - id: tabViewWrapper - property var rowComponentItem: model.rowComponent - - width : rowComponentItem ? rowComponentItem.width : 0 - height : rowComponentItem ? rowComponentItem.height : 0 - - Component.onCompleted: - { - rowComponentItem.parent = tabViewWrapper - rowComponentItem.z = 10 - itemStack.height = Qt.binding( function() { return rowComponentItem.height; }); - } - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/TableView.qml b/QMLComponents/components/JASP/Controls/TableView.qml deleted file mode 100644 index 9a0e29e6a7d..00000000000 --- a/QMLComponents/components/JASP/Controls/TableView.qml +++ /dev/null @@ -1,394 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.15 -import QtQuick.Controls 2.12 as QTC -import QtQuick.Layouts 1.3 -import JASP.Controls 1.0 -import QtQuick.Window 2.3 -import JASP 1.0 - -TableViewBase -{ - id: tableView - focusOnTab: false - implicitWidth: 400 - implicitHeight: 400 - shouldStealHover: false - defaultValue: modelType === JASP.JAGSDataInputModel ? "..." : (modelType === JASP.CustomContrasts ? "0" : "1") - initialColumnCount: modelType === JASP.MultinomialChi2Model ? 1 : 0 - - property string factorsSource : "" - property string filter : "rep(TRUE, rowcount)" //Used by ListModelFilteredDataEntry - property string colName : modelType === JASP.CustomContrasts ? "" : "data" //Used by ListModelFilteredDataEntry - property string extraCol : "" //Used by ListModelFilteredDataEntry - property alias rowNumberWidth : theView.rowNumberWidth - property var validator : (itemType === JASP.Integer) ? intValidator : (itemType === JASP.Double ? doubleValidator : stringValidator) - property double minimum : 0 - property int decimals : 1 - property int colSelected : -1 - property int rowSelected : -1 - property real scaleFactor : 1 // Only used by marginalMeansContrast - property string cornerText : qsTr("Row #") - property bool parseDefaultValue : true - property bool isFirstColEditable : true - property bool showAddRemoveButtons: modelType === JASP.GridInput - - property alias view : theView - property alias itemDelegate : theView.itemDelegate - property alias rowNumberDelegate : theView.rowNumberDelegate - property alias columnHeaderDelegate : theView.columnHeaderDelegate - property alias leftTopCornerItem : theView.leftTopCornerItem - - property alias addLeftButton : addLeftButton - property alias addRightButton : addRightButton - property alias deleteButton : deleteButton - - //The size of the table *inside* the Flickable. + 2 for margins of flickable and scrollbars - readonly property int tableWidth: theView.width + 2 + (vertiScroller.visible ? jaspTheme.scrollbarBoxWidth : 0) - readonly property int tableHeight: theView.height + 2 + (horiScroller.visible ? jaspTheme.scrollbarBoxWidth : 0) - - // These 4 functions can be overloaded to set a custom column or row header, or a default value, or a default validator. - function getColHeaderText(headerText, columnIndex) { return (columnNames.length > columnIndex) ? columnNames[columnIndex] : headerText; } - function getRowHeaderText(headerText, rowIndex) { return (rowNames.length > rowIndex) ? rowNames[rowIndex] : headerText; } - function getDefaultValue(columnIndex, rowIndex) { return defaultValue; } - function getValidator(columnIndex, rowIndex) { return validator; } - function getEditable(columnIndex, rowIndex) { return true; } - - //These signals are added because I had some trouble connecting the filterChanged from C++ (in constructor of ListModelFilteredDataEntry) - signal filterSignal(string filter) - signal colNameSignal(string filter) - signal extraColSignal(string extraCol) - - onFilterChanged: filterSignal(tableView.filter) - onColNameChanged: colNameSignal(tableView.colName) - onExtraColChanged: extraColSignal(tableView.extraCol) - - property real iconSize: 12 * preferencesModel.uiScale - property real iconSizeHovered: 14 * preferencesModel.uiScale - - onColSelectedChanged: setButtons() - - function setButtons() - { - if (!showAddRemoveButtons) return - - var item - if (colSelected >= 0) item = theView.getColumnHeader(colSelected); - - if (item) - { - if (maxColumn < 0 || maxColumn > model.columnCount()) - { - var maxNumberWidth = theView.rowNumberWidth; - addLeftButton.x = Qt.binding(function() { return 1 + item.x - iconSize/2 - myFlickable.contentX } ) - addLeftButton.y = Qt.binding(function() { return item.y + item.height/2 - iconSize/2 } ) - addLeftButton.visible = Qt.binding(function() { return (addLeftButton.x + iconSize/2 > theView.rowNumberWidth) && (addLeftButton.x + iconSize/2 < tableView.width + 1) } ) - addRightButton.x = Qt.binding(function() { return 1 + item.x + item.width - iconSize/2 - myFlickable.contentX } ) - addRightButton.y = Qt.binding(function() { return item.y + item.height/2 - iconSize/2 } ) - addRightButton.visible = Qt.binding(function() { return (addRightButton.x + iconSize/2 > theView.rowNumberWidth) && (addRightButton.x + iconSize/2 < tableView.width + 1) } ) - } - else - { - addLeftButton.visible = false - addRightButton.visible = false; - } - if (minColumn < model.columnCount()) - { - deleteButton.x = Qt.binding(function() { return item.x + item.width/2 - iconSize/2 - myFlickable.contentX } ) - deleteButton.visible = Qt.binding(function() { return (deleteButton.x + iconSize/2 > theView.rowNumberWidth ) && (deleteButton.x + iconSize/2 < tableView.width + 1) } ) - } - else - deleteButton.visible = false - } - else - { - addLeftButton.visible = false - addRightButton.visible = false - deleteButton.visible = false - } - } - - function removeAColumn() - { - if (colSelected >= 0) - removeColumn(colSelected); - } - - function removeARow() - { - if (rowSelected >= 0) removeRow(rowSelected); - else removeRow(rowCount - 1); - } - - Rectangle - { - id: rectangleBorder - anchors.centerIn: parent - width: parent.width - height: parent.height - border.width: 1 - border.color: jaspTheme.uiBorder - color: jaspTheme.white - - MenuButton - { - id: addLeftButton - z: 100 - anchors.top: parent.top - anchors.topMargin: -height/2 - height: hovered ? iconSizeHovered : iconSize - width: height - buttonPadding: 0 - color: "transparent" - iconSource: jaspTheme.iconPath + "/addition-sign-small-green.svg" - toolTip: qsTr("Add to the left") - radius: height - visible: false - onClicked: - { - if (maxColumn < 0 || maxColumn > model.columnCount()) - { - addColumn(colSelected, true); - colSelected++; - } - } - } - - MenuButton - { - id: addRightButton - z: 100 - anchors.top: parent.top - anchors.topMargin: -height/2 - height: hovered ? iconSizeHovered : iconSize - width: height - buttonPadding: 0 - color: "transparent" - iconSource: jaspTheme.iconPath + "/addition-sign-small-green.svg" - toolTip: qsTr("Add to the right") - radius: height - visible: false - onClicked: - { - if (maxColumn < 0 || maxColumn > model.columnCount()) - { - addColumn(colSelected, false) - setButtons() - } - } - } - - MenuButton - { - id: deleteButton - z: 100 - anchors.top: parent.top - anchors.topMargin: -height/2 - height: (hovered ? iconSizeHovered : iconSize) - 1 - width: height - buttonPadding: 0 - color: "transparent" - iconSource: jaspTheme.iconPath + "/cross-sign-small-red.svg" - toolTip: qsTr("Delete") - radius: height - visible: false - onClicked: - { - if (minColumn < model.columnCount()) - { - removeColumn(colSelected); - if (colSelected > 0) colSelected-- - else setButtons() - } - } - } - - - Flickable - { - id: myFlickable - anchors - { - topMargin: 1 - leftMargin: 1 - top: parent.top - left: parent.left - right: vertiScroller.left - bottom: horiScroller.top - } - - contentWidth: theView.width - contentHeight: theView.height - - boundsBehavior : Flickable.StopAtBounds - boundsMovement : Flickable.StopAtBounds - clip: true - - DataSetView - { - z: -1 - id: theView - model: tableView.model - itemHorizontalPadding: 0 - itemVerticalPadding: 8 * preferencesModel.uiScale - cacheItems: false - tableViewItem: tableView - - viewportX: myFlickable.visibleArea.xPosition * width - viewportY: myFlickable.visibleArea.yPosition * height - viewportW: myFlickable.visibleArea.widthRatio * width - viewportH: myFlickable.visibleArea.heightRatio * height - - columnHeaderDelegate: Rectangle - { - color: columnIndex === tableView.colSelected ? jaspTheme.grayLighter : jaspTheme.analysisBackgroundColor - Text { text: tableView.getColHeaderText(headerText, columnIndex); anchors.centerIn: parent; font: jaspTheme.font; color: jaspTheme.textEnabled } - MouseArea - { - anchors.fill: parent - onClicked: - { - if (tableView.colSelected === columnIndex) - columnIndex = -1 - tableView.colSelected = columnIndex; - } - } - } - - rowNumberDelegate: Rectangle - { - color: rowIndex === tableView.rowSelected ? jaspTheme.grayLighter : jaspTheme.analysisBackgroundColor - Text - { - text: tableView.getRowHeaderText(headerText, rowIndex); - color: jaspTheme.textEnabled - anchors.centerIn: parent; - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - leftPadding: 3 * preferencesModel.uiScale - elide: Text.ElideRight; - width: parent.width - height: parent.width - font: jaspTheme.font - } - - MouseArea - { - anchors.fill: parent - onClicked: - { - if (tableView.rowSelected === rowIndex) - rowIndex = -1 - tableView.rowSelected = rowIndex; - } - } - } - - JASPDoubleValidator { id: intValidator; bottom: tableView.minimum; decimals: 0 } - JASPDoubleValidator { id: doubleValidator; bottom: tableView.minimum; decimals: tableView.decimals } - RegularExpressionValidator { id: stringValidator } - - itemDelegate: Item - { - FormulaField - { - id: formlaInput - inputType: itemInputType === undefined ? "string" : itemInputType - isBound: false - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: - 8 * preferencesModel.uiScale - fieldHeight: parent.height + 16 * preferencesModel.uiScale - fieldWidth: parent.width - useExternalBorder: false - showBorder: false - value: itemText - useLastValidValue: false - parseDefaultValue: tableView.parseDefaultValue - defaultValue: tableView.getDefaultValue(columnIndex, rowIndex) - selectValueOnFocus: true - validator: tableView.getValidator(columnIndex, rowIndex) - onPressed: tableView.colSelected = columnIndex - onEditingFinished: - { - tableView.itemChanged(columnIndex, rowIndex, displayValue, inputType) - tableView.setButtons() - } - editable: itemEditable && tableView.getEditable(columnIndex, rowIndex) - multiple: itemInputType === "formulaArray" - } - } - - leftTopCornerItem: Rectangle - { - color: jaspTheme.analysisBackgroundColor - - Text - { - text: cornerText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: jaspTheme.textEnabled - height: parent.height - font: jaspTheme.font - anchors.centerIn: parent - } - } - - } - } - - JASPScrollBar - { - id: vertiScroller; - flickable: myFlickable - manualAnchor: true - visible: myFlickable.visible && tableView.height < theView.height - anchors - { - top: parent.top - right: parent.right - bottom: horiScroller.top - topMargin: 1 - rightMargin: 1 - } - bigBar: false - } - - JASPScrollBar - { - id: horiScroller; - flickable: myFlickable - vertical: false - manualAnchor: true - visible: myFlickable.visible && tableView.width < theView.width - anchors - { - left: parent.left - right: vertiScroller.left - bottom: parent.bottom - leftMargin: 1 - bottomMargin: 1 - } - bigBar: false - } - } -} diff --git a/QMLComponents/components/JASP/Controls/Text.qml b/QMLComponents/components/JASP/Controls/Text.qml deleted file mode 100644 index 69ed97faf73..00000000000 --- a/QMLComponents/components/JASP/Controls/Text.qml +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.11 -import QtQuick.Controls 2.4 - -Text -{ - font: jaspTheme.font - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled -} diff --git a/QMLComponents/components/JASP/Controls/TextArea.qml b/QMLComponents/components/JASP/Controls/TextArea.qml deleted file mode 100644 index cc17d2a8878..00000000000 --- a/QMLComponents/components/JASP/Controls/TextArea.qml +++ /dev/null @@ -1,178 +0,0 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 as QTC -import QtQuick.Layouts 1.3 -import JASP 1.0 - -TextAreaBase -{ - id: textArea - height: jaspTheme.defaultTextAreaHeight - implicitHeight: height - width: parent.width - implicitWidth: width - focusIndicator: flickableRectangle - innerControl: control - - property alias control : control - property alias text : control.text - property string applyScriptInfo : Qt.platform.os == "osx" ? qsTr("\u2318 + Enter to apply") : qsTr("Ctrl + Enter to apply") - property alias infoText : infoText.text - property alias font : control.font - property alias textDocument : control.textDocument - property bool trim : false - property var modelParameterView : null - property string separator : "\n" - property var separators : [] - property alias radius : flickableRectangle.radius - property alias placeholderText : control.placeholderText - property var undoModel - property bool useTabAsSpaces : true - property var nextTabItem - - Component.onCompleted: control.editingFinished.connect(editingFinished) - - function userEnteredInput() { - if (textArea.trim) - textArea.text = textArea.text.trim(); - - applyRequest(); - } - - function undo() { - if (undoModel) { - undoModel.undo() - return true - } - else - return false - } - - function redo() - { - if (undoModel) { - undoModel.redo() - return true - } - else - return false - } - - Text - { - id: textAreaTitle - visible: text !== "" - font: jaspTheme.font - color: !enabled ? jaspTheme.textDisabled : jaspTheme.textEnabled - text: textArea.title - } - - Rectangle - { - id: flickableRectangle - anchors.top: title !== "" ? textAreaTitle.bottom : parent.top - anchors.topMargin: title !== "" ? jaspTheme.titleBottomMargin : 0 - width: parent.implicitWidth - height: parent.implicitHeight - (title !== "" ? (textAreaTitle.height + jaspTheme.titleBottomMargin) : 0) - color: textArea.enabled ? jaspTheme.white : jaspTheme.whiteBroken - border.width: 1 - border.color: jaspTheme.borderColor - radius: jaspTheme.borderRadius - - Flickable - { - id: flickable - clip: true - boundsBehavior: Flickable.StopAtBounds - anchors.fill: parent - - QTC.TextArea.flickable: QTC.TextArea - { - id: control - selectByMouse: true - selectedTextColor: jaspTheme.white - selectionColor: jaspTheme.itemSelectedColor - - font: textArea.textType === JASP.TextTypeDefault || textArea.textType === JASP.TextTypeSource ? jaspTheme.font : jaspTheme.fontCode - color: textArea.enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - - Component.onCompleted: - { - if (textArea.nextTabItem) - { - control.KeyNavigation.priority = KeyNavigation.BeforeItem - control.KeyNavigation.tab = textArea.nextTabItem - } - } - - Keys.onPressed: (event) => - { - var controlPressed = Boolean(event.modifiers & Qt.ControlModifier) - var shiftPressed = Boolean(event.modifiers & Qt.ShiftModifier ) - - switch (event.key) - { - case Qt.Key_Return: - case Qt.Key_Enter: - if (controlPressed) - { - userEnteredInput(); - event.accepted = true; - } - break; - case Qt.Key_Tab: - if (useTabAsSpaces) - { - control.insert(control.cursorPosition, " ") - event.accepted = true; - } - break; - case Qt.Key_Z: - if (controlPressed) - { - if (shiftPressed) - { - if (textArea.redo()) - event.accepted = true; - } - else if (textArea.undo()) - event.accepted = true; - } - break; - default: - infoText.text = textArea.applyScriptInfo; - textArea.hasScriptError = false; - } - } - } - - QTC.ScrollBar.vertical: QTC.ScrollBar { } - } - } - - Text - { - id: infoText - z: 2 - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: 4 * preferencesModel.uiScale - leftPadding: 5 * preferencesModel.uiScale - rightPadding: leftPadding - bottomPadding: 3 * preferencesModel.uiScale - topPadding: bottomPadding - text: textArea.applyScriptInfo - font: jaspTheme.font - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: !enabled ? jaspTheme.textDisabled : textArea.hasScriptError ? jaspTheme.textEnabled : jaspTheme.grayDarker - wrapMode: Text.Wrap - width: implicitWidth > textArea.width - 2 * anchors.margins ? textArea.width - 2 * anchors.margins : implicitWidth - - Rectangle - { - z: -1 - anchors.fill: infoText - color: textArea.hasScriptError ? jaspTheme.errorMessagesBackgroundColor : "transparent" - } - } -} diff --git a/QMLComponents/components/JASP/Controls/TextField.qml b/QMLComponents/components/JASP/Controls/TextField.qml deleted file mode 100644 index 5ac82a856e9..00000000000 --- a/QMLComponents/components/JASP/Controls/TextField.qml +++ /dev/null @@ -1,282 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick -import QtQuick.Controls 2.4 as QTC -import QtQuick.Layouts 1.3 -import JASP 1.0 - -TextInputBase -{ - id: textField - implicitHeight: control.height - implicitWidth: afterLabel.text ? (afterLabelRect.x + afterLabelRect.width) : (control.x + control.width) - background: useExternalBorder ? externalControlBackground : control.background - cursorShape: Qt.IBeamCursor - innerControl: control - title: text - - property alias control: control - property alias text: textField.label - property alias displayValue: control.text ///< In onEditingFinished this contains the "value" entered by the user - property var lastValidValue: defaultValue - property int fieldWidth: jaspTheme.textFieldWidth - property int fieldHeight: 0 - property bool useExternalBorder: !parentListView - property bool showBorder: true - property alias placeholderText: control.placeholderText - property bool selectValueOnFocus: false - property alias startValue: textField.defaultValue - - property alias validator: control.validator - property alias controlLabel: beforeLabel - property string inputType: "string" - property bool useLastValidValue: true - property bool editable: true - property var undoModel - - property double controlXOffset: 0 - - signal editingFinished() ///< To get the entered value use `displayValue` in the slot instead of `value` - signal textEdited() - signal pressed(var event) - signal released(var event) - - function doEditingFinished() - { - if (displayValue === "" && defaultValue !== undefined && String(defaultValue) !== "") - displayValue = defaultValue; - lastValidValue = displayValue - editingFinished(); - } - - function undo() { - if (undoModel) { - undoModel.undo() - return true - } - else - return false - } - function redo() - { - if (undoModel) { - undoModel.redo() - return true - } - else - return false - } - - Component.onCompleted: - { - if (!beforeLabel.text && textField.text) - beforeLabel.text = textField.text; - - control.editingFinished.connect(doEditingFinished); - control.textEdited.connect(textEdited); - control.pressed.connect(pressed); - control.released.connect(released); - if (control.text) - lastValidValue = control.text; - } - - // The value should be checked only when the control is initialized. - // But even if initialized, the constraints (e.g min or max) might change afterwards, if these constraints depend on other controls. - // In this case the error must be removed: this is done via the onAcceptableInputChanged which calls the checkValue. - onInitializedChanged: if (initialized) checkValue(false, false) - - function checkValue(resetLastValidValue, addErrorIfNotFocussed) - { - if (!initialized && isBound) return false - - if (control.acceptableInput) - { - if (!hasScriptError) - clearControlError(); - return true; - } - - if (addErrorIfNotFocussed && activeFocus) return false - if (!control.validator || (typeof control.validator.validationMessage !== "function")) return false; - - var msg = control.validator.validationMessage(beforeLabel.text) - - if (resetLastValidValue) - { - if (textField.useLastValidValue) - value = textField.lastValidValue - msg += "

    " - msg += qsTr("Restoring last correct value: %1").arg(value); - addControlErrorTemporary(msg) - } - else - addControlError(msg) - - return false - } - - - - Rectangle - { - id: beforeLabelRect - width: beforeLabel.width - height: control.height - color: debug ? jaspTheme.debugBackgroundColor : "transparent" - visible: beforeLabel.text && textField.visible - - Label - { - id: beforeLabel - font: jaspTheme.font - anchors.verticalCenter: parent.verticalCenter - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - text: textField.label - width: implicitWidth - } - } - - QTC.TextField - { - id: control - anchors.left: beforeLabelRect.visible ? beforeLabelRect.right : parent.left - anchors.leftMargin: controlXOffset + (beforeLabelRect.visible ? jaspTheme.labelSpacing : 0) - width: textField.fieldWidth //+ (textField.useExternalBorder ? 2 * jaspTheme.jaspControlHighlightWidth : 0) - font: jaspTheme.font - activeFocusOnPress: textField.editable - color: enabled && textField.editable ? jaspTheme.textEnabled : jaspTheme.textDisabled - - padding: jaspTheme.jaspControlPadding - leftPadding: jaspTheme.labelSpacing - selectByMouse: true - focus: textField.editable - selectedTextColor: jaspTheme.white - selectionColor: jaspTheme.itemSelectedColor - enabled: textField.editable - // text property is set by TextInpoutBase - - QTC.ToolTip.text : control.text - QTC.ToolTip.timeout : jaspTheme.toolTipTimeout - QTC.ToolTip.delay : !hovered ? 0 : jaspTheme.toolTipDelay - QTC.ToolTip.visible : contentWidth > width - leftPadding - rightPadding && (hovered || control.activeFocus) - - // The acceptableInput is checked even if the user is still typing in the TextField. - // In this case, the error should not appear immediately (only when the user is pressing the return key, or going out of focus), - // so the checkValue is called with addErrorIfNotFocussed set to true: it should not display an error if in focus. - // In not in focus, the acceptableInput can be changed because another control has changed the constraint of this control: in this case, the error should be displayed. - onAcceptableInputChanged: checkValue(false, true) - - background: Rectangle - { - id: controlBackground - color: jaspTheme.controlBackgroundColor - border.width: textField.showBorder && !control.activeFocus ? 1 : 0 - border.color: jaspTheme.borderColor //If the border width is zero the color is inconsequential - radius: jaspTheme.borderRadius - width: parent.width - 2 // (parent+self) border width - height: parent.height - 2 - anchors.centerIn: parent - } - - Rectangle - { - id: externalControlBackground - height: parent.height + jaspTheme.jaspControlHighlightWidth - width: parent.width + jaspTheme.jaspControlHighlightWidth - color: "transparent" - border.width: 0 //Changed from JASPControl::_setFocusBorder() (like border.color) - anchors.centerIn: parent - opacity: debug ? .3 : 1 - visible: textField.useExternalBorder - radius: jaspTheme.jaspControlHighlightWidth - } - - onActiveFocusChanged: - { - if (activeFocus) - { - if (textField.selectValueOnFocus) - control.selectAll() - } - else - // When going out of focus, the value must be checked. If the value is wrong, the last valid value should replace the wrong value. - checkValue(true, false) - } - - Keys.onReturnPressed: (event)=> - { - // When pressing the return key, the value should be checked: if the value is wrong, an error should appear and the focus should stay on this control. - if (checkValue(false, false)) - { - var nextItem = nextItemInFocusChain(); - if (nextItem) - nextItem.forceActiveFocus(); - - event.accepted = false; - } - } - - Keys.onPressed: (event) => - { - var controlPressed = Boolean(event.modifiers & Qt.ControlModifier); - var shiftPressed = Boolean(event.modifiers & Qt.ShiftModifier ); - - if (event.key === Qt.Key_Z && controlPressed) - { - if (shiftPressed) - { - if (textField.redo()) - event.accepted = true; - } - else if (textField.undo()) - event.accepted = true; - } - } - } - - Binding - { - // This is a way to set the property height only if fieldHeight is set - // If not, height should keep its implicit binding. - target: control - property: "height" - value: textField.fieldHeight - when: textField.fieldHeight != 0 - } - - Rectangle - { - id: afterLabelRect - width: afterLabel.implicitWidth - height: control.height - color: debug ? jaspTheme.debugBackgroundColor : "transparent" - visible: afterLabel.text && textField.visible - anchors.left: control.right - anchors.leftMargin: jaspTheme.labelSpacing - - Label - { - id: afterLabel - font: jaspTheme.font - anchors.verticalCenter: parent.verticalCenter - color: enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - text: textField.afterLabel - } - } -} diff --git a/QMLComponents/components/JASP/Controls/VariablesForm.qml b/QMLComponents/components/JASP/Controls/VariablesForm.qml deleted file mode 100644 index 2767702924f..00000000000 --- a/QMLComponents/components/JASP/Controls/VariablesForm.qml +++ /dev/null @@ -1,222 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import JASP 1.0 - -VariablesFormBase -{ - id : variablesForm - implicitHeight : jaspTheme.defaultVariablesFormHeight - implicitWidth : jaspForm.width - Layout.columnSpan : (parent && parent.hasOwnProperty('columns')) ? parent.columns : 1 - isBound : false - shouldStealHover : false - marginBetweenVariablesLists : 8 * preferencesModel.uiScale - minimumHeightVariablesLists : 25 * preferencesModel.uiScale - preferredHeight : implicitHeight - preferredWidth : implicitWidth - Layout.preferredHeight : preferredHeight // Cannot set Layout attached property in c++ - - onActiveFocusChanged : - { - if (activeFocus) - { - availableVariablesList.forceActiveFocus(); - availableVariablesList.KeyNavigation.backtab = variablesForm.nextItemInFocusChain(false); - } - } - - default property alias content : items.children - property int listWidth : width * 2 / 5 - property alias contentItems : items - property bool removeInvisibles : false - - property double _lastListWidth : 0 - - Item { id: items } - - Connections - { - target: preferencesModel - function onLanguageCodeChanged() - { - // Apparently a Qt bug: the height is not always recalculated by the GridLayout when the language is changed. - // Force this by changing temporarily the Layout.preferredHeight - // This fixes jasp-stats/jasp-test-release#731, but with Qt5.14.2, if preferredHeight is temporarly set to 0, it does not set it back to the original value afterwards. - // So set it to slightly higher value, and then it works.... - variablesForm.Layout.preferredHeight = variablesForm.preferredHeight + .1 - variablesForm.Layout.preferredHeight = Qt.binding(function() { return variablesForm.preferredHeight; }) - } - } - - onListWidthChanged: if (initialized && listWidth > 0 && listWidth != _lastListWidth) _lastListWidth = listWidth; - - onHeightChanged: if (initialized) setControlsSize() - onRemoveInvisiblesChanged: if (initialized) setControlsSize() - - Repeater - { - id: assignButtonRepeater - model: 0 - - AssignButton - { - x: (allAssignedVariablesList[index].x + availableVariablesList.width - 40 * preferencesModel.uiScale) / 2 - y: allAssignedVariablesList[index].y + allAssignedVariablesList[index].rectangleY - z: 10 - leftSource: availableVariablesList - rightSource: allAssignedVariablesList[index] - - Component.onCompleted: - { - allAssignedVariablesList[index] .activeFocusChanged .connect(setIconToLeft ); - availableVariablesList .activeFocusChanged .connect(setIconToRight ); - allAssignedVariablesList[index] .selectedItemsChanged .connect(setState ); - availableVariablesList .selectedItemsChanged .connect(setState ); - } - } - } - - function init() - { - for (var i in allJASPControls) - { - var control = allJASPControls[i] - control.anchors.right = variablesForm.right; - control.visibleChanged.connect(setControlsSize) - - var isControlList = ((control instanceof VariablesList) || (control instanceof FactorLevelList) || (control instanceof InputListView)) - var isControlComboBox = (control instanceof ComboBox) - - if (isControlList && widthSetByForm(control)) - // Change the width of the VariablesList only if was not set explicitely - control.width = Qt.binding(function() {return variablesForm.listWidth; }) - else if (isControlComboBox && widthSetByForm(control)) - { - control.setLabelAbove = true - control.controlMinWidth = Qt.binding(function() {return variablesForm.listWidth; }) - } - } - - var countAssignedList = 0 - var availableDropKeys = [] - for (var key in allAssignedVariablesList) - { - countAssignedList++; - var assignedList = allAssignedVariablesList[key] - var assignedDropKeys = []; - availableDropKeys.push(assignedList.name); - availableVariablesList.draggingChanged.connect(assignedList.setEnabledState); - assignedDropKeys.push(availableVariablesList.name); - - for (var key2 in allAssignedVariablesList) - { - assignedDropKeys.push(allAssignedVariablesList[key2].name); - if (assignedList !== allAssignedVariablesList[key2]) - assignedList.draggingChanged.connect(allAssignedVariablesList[key2].setEnabledState); - } - - assignedList.dropKeys = assignedDropKeys; - } - - availableVariablesList.dropKeys = availableDropKeys - setControlsSize() - assignButtonRepeater.model = countAssignedList; - setTabOrder(); - - availableVariablesList.height = Qt.binding(function() { return variablesForm.height; }) - // Set the width of the VariablesList to listWidth only if it is not set explicitely - // Implicitely, the width is set to the parent width. - if (widthSetByForm(availableVariablesList)) - availableVariablesList.width = Qt.binding(function() { return variablesForm.listWidth; }) - - } - - function setControlsSize() - { - var firstControl = true; - var minHeightOfAssignedControls = 0; - var changeableHeightControls = []; - var anchorTop = variablesForm.top - - for (var key in allJASPControls) - { - var control = allJASPControls[key] - var isControlList = ((control instanceof VariablesList) || (control instanceof FactorLevelList) || (control instanceof InputListView)) - - if (removeInvisibles && !control.visible) - control.height = 0 - else - { - control.anchors.top = anchorTop; - control.anchors.topMargin = firstControl ? 0 : marginBetweenVariablesLists; - anchorTop = control.bottom; - - if (removeInvisibles && control.visible && control.height == 0) // Reset the height of the control when it bocomes visible again - control.height = control.maxRows === 1 ? jaspTheme.defaultSingleItemListHeight : jaspTheme.defaultVariablesFormHeight - - if (!firstControl) - minHeightOfAssignedControls += marginBetweenVariablesLists; - - firstControl = false; - - if (!isControlList) - minHeightOfAssignedControls += control.height; - else if (control.maxRows === 1 || !heightSetByForm(control)) - { - // console.log("Control " + control.name + " has height " + control.height) - minHeightOfAssignedControls += control.height; - } - else - { - changeableHeightControls.push(control); - if (control.title) - minHeightOfAssignedControls += jaspTheme.variablesListTitle; - } - } - } - - // Set the height of controls (that have not singleVariable set or where the height is already specifically set) - // so that the AssignedVariablesList column is as long as the AvailableVariablesList column. - if (changeableHeightControls.length > 0) - { - var controlHeight = (availableVariablesList.height - minHeightOfAssignedControls) / changeableHeightControls.length; - - if (controlHeight < minimumHeightVariablesLists) - controlHeight = minimumHeightVariablesLists; // Set a minimum height - - for (var i = 0; i < changeableHeightControls.length; i++) - changeableHeightControls[i].height = changeableHeightControls[i].title ? (jaspTheme.variablesListTitle + controlHeight) : controlHeight; - } - } - - function setTabOrder() - { - availableVariablesList.KeyNavigation.tab = assignButtonRepeater.itemAt(0); - for (var i = 0; i < allAssignedVariablesList.length - 1; i++) - assignButtonRepeater.itemAt(i).KeyNavigation.tab = assignButtonRepeater.itemAt(i + 1); - - if(allAssignedVariablesList.length > 0) - assignButtonRepeater.itemAt(allAssignedVariablesList.length - 1).KeyNavigation.tab = allAssignedVariablesList[0] - - for (var j = 0; j < allAssignedVariablesList.length - 1; j++) - allAssignedVariablesList[j].KeyNavigation.tab = allAssignedVariablesList[j + 1]; - } -} diff --git a/QMLComponents/components/JASP/Controls/VariablesList.qml b/QMLComponents/components/JASP/Controls/VariablesList.qml deleted file mode 100644 index 26a9ad62a52..00000000000 --- a/QMLComponents/components/JASP/Controls/VariablesList.qml +++ /dev/null @@ -1,666 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -import QtQuick 2.11 -import QtQuick.Controls 2.4 as QTCONTROLS -import QtQml.Models 2.2 -import JASP 1.0 - -VariablesListBase -{ - id : variablesList - implicitHeight : maxRows === 1 ? jaspTheme.defaultSingleItemListHeight : jaspTheme.defaultVariablesFormHeight - background : itemRectangle - implicitWidth : parent.width - shouldStealHover : false - innerControl : itemGridView - optionKey : listViewType === JASP.Interaction ? "components" : "variable" - maxRows : singleVariable ? 1 : -1 - addAvailableVariablesToAssigned : listViewType === JASP.Interaction - allowAnalysisOwnComputedColumns : true - - property alias label : variablesList.title - property alias itemGridView : itemGridView - property alias cellHeight : itemGridView.cellHeight - property alias cellWidth : itemGridView.cellWidth - property alias itemRectangle : itemRectangle - property alias scrollBar : scrollBar - property alias itemTitle : itemTitle - property string rowComponentTitle : "" - property string itemType : "variables" - property int dropMode : JASP.DropNone - property bool draggable : true - property var sortMenuModel : null - property bool showSortMenu : true - property bool singleVariable : false - property bool dropModeInsert : dropMode === JASP.DropInsert - property bool dropModeReplace : dropMode === JASP.DropReplace - property bool showElementBorder : false - property bool showVariableTypeIcon : containsVariables - property bool addInteractionsByDefault : true - property bool interactionContainLowerTerms : true - property bool allowDuplicatesInMultipleColumns: false // This property is used in the constructor and is not updatable afterwards. - - property int indexInDroppedListViewOfDraggedItem: -1 - - readonly property int rectangleY : itemRectangle.y - - property int startShiftSelected : 0 - property int endShiftSelected : -1 - property bool mousePressed : false - property bool shiftPressed : false - property var draggingItems : [] - property var itemContainingDrag - property string searchKeys : "" - - signal itemDoubleClicked(int index); - signal itemsDropped(var indexes, var dropList, int dropItemIndex); - signal draggingChanged(var context, bool dragging); - signal selectedItemsChanged(); - - onModelChanged: if (model) model.selectedItemsChanged.connect(selectedItemsChanged); - - function setEnabledState(source, dragging) - { - var result = !dragging || areTypesAllowed(source.model.selectedItemsTypes()); - - // Do not use variablesList.enabled: this may break the binding if the developer used it in his QML form. - itemRectangle.enabled = result - itemTitle.enabled = result - } - - - function moveSelectedItems(target) - { - var selectedItems = variablesList.model.selectedItems() - if (selectedItems.length === 0) return; - - itemsDropped(selectedItems, target, -1); - variablesList.clearSelectedItems(); - } - - - - function getExistingItems() - { - var items = []; - for (var i = 0; i < itemGridView.contentItem.children.length; i++) - { - var item = itemGridView.contentItem.children[i]; - if (item.children.length === 0) - continue; - item = item.children[0]; - if (item.objectName === "itemRectangle") - items.push(item); - } - - return items; - } - - function addSelectedItem(itemRank) - { - variablesList.model.selectItem(itemRank, true); - } - - function removeSelectedItem(itemRank) - { - variablesList.model.selectItem(itemRank, false); - } - - function clearSelectedItems() - { - variablesList.model.clearSelectedItems(); - } - - function setSelectedItem(itemRank) - { - variablesList.model.setSelectedItem(itemRank); - } - - function selectShiftItems(selected) - { - var startIndex = variablesList.startShiftSelected; - var endIndex = variablesList.endShiftSelected; - if (startIndex > endIndex) - { - var temp = startIndex; - startIndex = endIndex; - endIndex = temp; - } - - for (var i = startIndex; i <= endIndex; i++) - variablesList.model.selectItem(i, selected) - } - - Text - { - id : itemTitle - anchors.top : parent.top - anchors.left : parent.left - text : title - height : title ? jaspTheme.variablesListTitle : 0 - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Text - { - anchors.top : parent.top - anchors.right : parent.right - text : rowComponentTitle - height : rowComponentTitle ? jaspTheme.variablesListTitle : 0 - font : jaspTheme.font - color : enabled ? jaspTheme.textEnabled : jaspTheme.textDisabled - } - - Rectangle - { - id : itemRectangle - anchors.top : itemTitle.bottom - anchors.left : parent.left - height : variablesList.height - itemTitle.height - width : parent.width - color : debug ? jaspTheme.debugBackgroundColor : jaspTheme.controlBackgroundColor - border.width : 1 - border.color : jaspTheme.borderColor - radius : jaspTheme.borderRadius - - JASPScrollBar - { - id : scrollBar - flickable : itemGridView - manualAnchor : true - vertical : true - z : 1337 - - anchors - { - top : parent.top - right : parent.right - bottom : parent.bottom - margins : 2 - } - } - - GridView - { - id : itemGridView - cellHeight : 20 * preferencesModel.uiScale - cellWidth : width / variablesList.columns - clip : true - focus : true - anchors.fill : parent - anchors.margins : 4 * preferencesModel.uiScale - anchors.rightMargin : scrollBar.width + anchors.margins - model : variablesList.model - delegate : itemVariableComponent - boundsBehavior : Flickable.StopAtBounds - - onCurrentItemChanged: - { - if (variablesList.shiftPressed) - { - if (variablesList.endShiftSelected >= 0) - variablesList.selectShiftItems(false); - variablesList.endShiftSelected = itemGridView.currentIndex; - variablesList.selectShiftItems(true); - } - else if (!variablesList.mousePressed) - { - var itemWrapper = currentItem; - if (itemWrapper) - { - var itemRectangle = itemWrapper.children[0]; - variablesList.setSelectedItem(itemRectangle.rank); - variablesList.startShiftSelected = currentIndex; - variablesList.endShiftSelected = -1; - } - } - } - } - } - - Repeater - { - model: suggestedColumnsIcons - - Image - { - source: modelData - height: 16 * preferencesModel.uiScale - width: 16 * preferencesModel.uiScale - z: 2 - mipmap: true - smooth: true - anchors - { - bottom: itemRectangle.bottom; - bottomMargin: 4 * preferencesModel.uiScale - right: itemRectangle.right; - rightMargin: (index * 20 + 4) * preferencesModel.uiScale + (scrollBar.visible ? scrollBar.width : 0) - } - } - } - - DropArea - { - id: dropArea - anchors.fill: itemRectangle - keys: variablesList.dropKeys - - onPositionChanged: (drag)=> - { - if (!itemRectangle.enabled || variablesList.maxRows === 1 || (!variablesList.dropModeInsert && !variablesList.dropModeReplace)) return; - - var onTop = true; - var item = itemGridView.itemAt(drag.x, drag.y + itemGridView.contentY) - if (item && item.children.length > 0) - item = item.children[0]; - if (!item || item.objectName !== "itemRectangle") - { - if (itemGridView.count > 0) - { - var items = variablesList.getExistingItems(); - if (items.length > 0) - { - var lastItem = items[items.length - 1]; - if (lastItem.rank === (itemGridView.count - 1) && drag.y > (lastItem.height * itemGridView.count)) - { - item = lastItem - onTop = false; - } - } - } - } - if (item && item.objectName === "itemRectangle") - { - dropLine.parent = item - dropLine.visible = true - dropLine.onTop = onTop - variablesList.itemContainingDrag = item - variablesList.indexInDroppedListViewOfDraggedItem = onTop ? item.rank : -1 - } - else - { - dropLine.visible = false - variablesList.itemContainingDrag = null - variablesList.indexInDroppedListViewOfDraggedItem = -1 - } - } - onExited: - { - dropLine.visible = false - variablesList.itemContainingDrag = null - variablesList.indexInDroppedListViewOfDraggedItem = -1 - } - } - - Rectangle - { - id: dropLine - height: 1 - width: parent ? parent.width : 0 - anchors.top: parent ? (onTop ? parent.top : parent.bottom) : undefined - anchors.left: parent ? parent.left : undefined - color: jaspTheme.blueLighter - visible: false - - property bool onTop: true - } - - SortMenuButton - { - visible: variablesList.showSortMenu && variablesList.sortMenuModel && itemGridView.count > 1 - anchors - { - top: itemRectangle.top - right: itemRectangle.right - rightMargin: 5 * preferencesModel.uiScale + (scrollBar.visible ? scrollBar.width : 0) - topMargin: 5 * preferencesModel.uiScale - } - - sortMenuModel: variablesList.sortMenuModel - scrollYPosition: backgroundForms ? backgroundForms.contentY : 0 - } - - Timer - { - id: searchKeysTimer - interval: 500 - onTriggered: variablesList.searchKeys = "" - } - - Keys.onPressed: (event)=> - { - if (event.key === Qt.Key_Shift) - variablesList.shiftPressed = true; - else if (event.key === Qt.Key_A && event.modifiers & Qt.ControlModifier) - variablesList.model.selectAllItems(); - else if (event.key >= Qt.Key_Exclam && event.key <= Qt.Key_ydiaeresis) - { - var currentSearchKeys = variablesList.searchKeys - var stringToSearch = (currentSearchKeys.length === 1 && currentSearchKeys === event.text) ? event.text : currentSearchKeys + event.text - var nextIndex = variablesList.model.searchTermWith(stringToSearch) - - if (nextIndex >= 0) - { - itemGridView.positionViewAtIndex(nextIndex, GridView.Contain) - if (itemGridView.currentIndex !== nextIndex) - { - variablesList.clearSelectedItems(); - itemGridView.currentIndex = nextIndex; - } - searchKeysTimer.restart() - variablesList.searchKeys = stringToSearch - } - } - } - - Keys.onReleased: (event)=> - { - if (event.key === Qt.Key_Shift) - variablesList.shiftPressed = false; - } - - Keys.onSpacePressed: (event)=> - { - moveSelectedItems() - } - Keys.onReturnPressed: (event)=> - { - moveSelectedItems() - } - - Component - { - id: itemVariableComponent - - FocusScope - { - id: itemWrapper - height: itemGridView.cellHeight - width: itemGridView.cellWidth - - Rectangle - { - id: itemRectangle - objectName: "itemRectangle" - - // the height & width of itemWrapper & itemRectangle must be set independently of each other: - // when the rectangle is dragged, it gets another parent but it must keep the same size, - height: itemGridView.cellHeight - width: itemGridView.cellWidth - focus: true - border.width: containsDragItem && variablesList.dropModeReplace ? 2 : (variablesList.showElementBorder ? 1 : 0) - border.color: containsDragItem && variablesList.dropModeReplace ? jaspTheme.containsDragBorderColor : jaspTheme.grayLighter - radius: jaspTheme.borderRadius - - property bool clearOtherSelectedItemsWhenClicked: false - property bool selected: model.selected - property bool isDependency: variablesList.dependencyMustContain.indexOf(colName.text) >= 0 - property bool dragging: false - property int offsetX: 0 - property int offsetY: 0 - property int rank: index - property bool containsDragItem: variablesList.itemContainingDrag === itemRectangle - property bool isVirtual: (typeof model.type !== "undefined") && model.type.includes("virtual") - property bool isVariable: (typeof model.type !== "undefined") && model.type.includes("variable") - property bool isLayer: (typeof model.type !== "undefined") && model.type.includes("layer") - property bool draggable: variablesList.draggable && model.selectable - property string columnType: isVariable && (typeof model.columnType !== "undefined") ? model.columnType : "" - property var extraItem: model.rowComponent - - enabled: variablesList.listViewType != JASP.AvailableVariables || !columnType || variablesList.areTypesAllowed([columnType]) - - function setRelative(draggedRect) - { - x = Qt.binding(function (){ return draggedRect.x + offsetX; }) - y = Qt.binding(function (){ return draggedRect.y + offsetY; }) - } - - color: - { - if (itemRectangle.isDependency) return itemRectangle.selected ? jaspTheme.dependencySelectedColor : jaspTheme.dependencyBorderColor; - if (itemRectangle.draggable) - { - if (itemRectangle.selected) return variablesList.activeFocus ? jaspTheme.itemSelectedColor: jaspTheme.itemSelectedNoFocusColor; - if (itemRectangle.containsDragItem && variablesList.dropModeReplace) return jaspTheme.itemSelectedColor; - if (mouseArea.containsMouse) return jaspTheme.itemHoverColor; - } - return jaspTheme.controlBackgroundColor; - } - - Drag.keys: [variablesList.name] - Drag.active: mouseArea.drag.active - Drag.hotSpot.x: itemRectangle.width / 2 - Drag.hotSpot.y: itemRectangle.height / 2 - - // Use the ToolTip Attached property to avoid creating ToolTip object for each item - QTCONTROLS.ToolTip.visible: mouseArea.containsMouse && model.name && !itemRectangle.containsDragItem && colName.truncated - QTCONTROLS.ToolTip.delay: 300 - QTCONTROLS.ToolTip.text: model.name - - Component.onCompleted: - { - if (extraItem) - { - extraItem.parent = itemRectangle; - extraItem.anchors.verticalCenter = itemRectangle.verticalCenter; - extraItem.anchors.right = itemRectangle.right; - extraItem.anchors.rightMargin = 3 * preferencesModel.uiScale; - } - } - - Image - { - id: icon - height: 16 * preferencesModel.uiScale - width: source === "" ? 0 : 16 * preferencesModel.uiScale - x: jaspTheme.borderRadius - anchors.verticalCenter: parent.verticalCenter - source: sourceVar !== undefined ? sourceVar : "" - visible: source - mipmap: true - smooth: true - - //So Im pushing this through a property because it seems to results in "undefined" during loading and this adds a ton of warnings to the output which is not helpful. I tried less heavyhanded approaches first but this works perfectly fine. - property var sourceVar: variablesList.showVariableTypeIcon && itemRectangle.isVariable ? (enabled ? model.columnTypeIcon : model.columnTypeDisabledIcon) : "" - } - - Text - { - id: colName - anchors.left: variablesList.showVariableTypeIcon ? icon.right : itemRectangle.left - anchors.leftMargin: jaspTheme.generalAnchorMargin - text: model.name - width: itemRectangle.width - x - (itemRectangle.extraItem ? itemRectangle.extraItem.width : 0) - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: itemRectangle.isLayer ? Text.AlignHCenter : undefined - color: !enabled ? jaspTheme.textDisabled : itemRectangle.isVirtual ? jaspTheme.grayLighter : (itemRectangle.color === jaspTheme.itemSelectedColor ? jaspTheme.white : jaspTheme.black) - font: jaspTheme.font - } - - states: [ - State - { - when: itemRectangle.dragging - - ParentChange - { - target: itemRectangle - parent: jaspForm - } - AnchorChanges - { - target: itemRectangle - anchors.horizontalCenter: undefined - anchors.verticalCenter: undefined - } - PropertyChanges - { - target: itemRectangle - opacity: 0.4 - } - }, - - State - { - when: !itemRectangle.dragging - - ParentChange - { - target: itemRectangle - parent: itemWrapper - } - AnchorChanges - { - target: itemRectangle - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - } - PropertyChanges - { - target: itemRectangle - opacity: 1.0 - } - } - ] - - MouseArea - { - id: mouseArea - anchors.fill: parent - drag.target: itemRectangle.draggable ? parent : null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onDoubleClicked: (mouse)=> - { - if (itemRectangle.draggable) - { - variablesList.clearSelectedItems(); // Must be before itemDoubleClicked: listView does not exist anymore afterwards - itemDoubleClicked(index); - } - } - - onClicked: (mouse)=> - { - if (itemRectangle.clearOtherSelectedItemsWhenClicked) - variablesList.setSelectedItem(itemRectangle.rank) - } - - onPressed: (mouse)=> - { - variablesList.mousePressed = true - itemGridView.currentIndex = index; - itemRectangle.clearOtherSelectedItemsWhenClicked = false - if (mouse.modifiers & Qt.ControlModifier) - { - if (itemRectangle.selected) - variablesList.removeSelectedItem(itemRectangle.rank) - else - variablesList.addSelectedItem(itemRectangle.rank) - variablesList.startShiftSelected = index - variablesList.endShiftSelected = -1 - } - else if (mouse.modifiers & Qt.ShiftModifier) - { - if (variablesList.endShiftSelected >= 0) - variablesList.selectShiftItems(false) - variablesList.endShiftSelected = index - variablesList.selectShiftItems(true) - } - else - { - itemWrapper.forceActiveFocus() - if (!itemRectangle.selected) - variablesList.setSelectedItem(itemRectangle.rank); - else - itemRectangle.clearOtherSelectedItemsWhenClicked = true; - - variablesList.startShiftSelected = index; - variablesList.endShiftSelected = -1; - } - } - onReleased: (mouse)=> - { - variablesList.mousePressed = false; - } - - drag.onActiveChanged: - { - variablesList.draggingChanged(variablesList, drag.active) - if (drag.active) - { - if (itemRectangle.selected) - { - variablesList.draggingItems = [] - variablesList.draggingItems.push(itemRectangle) - itemRectangle.dragging = true; - - var items = variablesList.getExistingItems(); - for (var i = 0; i < items.length; i++) - { - var item = items[i]; - if (!variablesList.model.selectedItems().includes(item.rank)) - continue; - - if (item.rank !== index) - { - variablesList.draggingItems.push(item) - item.dragging = true; - item.offsetX = item.x - itemRectangle.x; - item.offsetY = item.y - itemRectangle.y; - item.setRelative(itemRectangle); - } - } - } - - } - else - { - for (var i = 0; i < variablesList.draggingItems.length; i++) - { - var draggingItem = variablesList.draggingItems[i]; - if (!draggingItem.dragging) - continue; - - draggingItem.dragging = false; - draggingItem.x = draggingItem.x; // break bindings - draggingItem.y = draggingItem.y; - } - if (itemRectangle.Drag.target) - { - var dropTarget = itemRectangle.Drag.target.parent - var selectedItems = variablesList.model.selectedItems() - if (dropTarget.maxRows > 0 && selectedItems.length > dropTarget.maxRows) - return; - - var variablesListName = variablesList.name - itemsDropped(selectedItems, dropTarget, dropTarget.indexInDroppedListViewOfDraggedItem); - variablesList.clearSelectedItems(); - } - } - } - } - } - } - } -} diff --git a/QMLComponents/components/JASP/Controls/qmldir b/QMLComponents/components/JASP/Controls/qmldir deleted file mode 100644 index d5a546432b0..00000000000 --- a/QMLComponents/components/JASP/Controls/qmldir +++ /dev/null @@ -1,68 +0,0 @@ -module -AddColumnField 1.0 AddColumnField.qml -AssignButton 1.0 AssignButton.qml -AssignedRepeatedMeasuresCells 1.0 AssignedRepeatedMeasuresCells.qml -AssignedPairsVariablesList 1.0 AssignedPairsVariablesList.qml -AssignedVariablesList 1.0 AssignedVariablesList.qml -AvailableVariablesList 1.0 AvailableVariablesList.qml -BasicThreeButtonTableView 1.0 BasicThreeButtonTableView.qml -BayesFactorType 1.0 BayesFactorType.qml -Button 1.0 Button.qml -CheckBox 1.0 CheckBox.qml -Chi2TestTableView 1.0 Chi2TestTableView.qml -CIField 1.0 CIField.qml -ColumnLayout 1.0 ColumnLayout.qml -ColorPalette 1.0 ColorPalette.qml -ComboBox 1.0 ComboBox.qml -ComponentsList 1.0 ComponentsList.qml -ComputedColumnField 1.0 ComputedColumnField.qml -ContrastsList 1.0 ContrastsList.qml -ControlErrorMessage 1.0 ControlErrorMessage.qml -CrossButton 1.0 CrossButton.qml -CustomContrastsTableView 1.0 CustomContrastsTableView.qml -Divider 1.0 Divider.qml -DoubleField 1.0 DoubleField.qml -DropDown 1.0 ComboBox.qml -ExpanderButton 1.0 ExpanderButton.qml -FactorLevelList 1.0 FactorLevelList.qml -FactorsForm 1.0 FactorsForm.qml -FactorsList 1.0 FactorsList.qml -FileSelector 1.0 FileSelector.qml -Form 1.0 Form.qml -FormulaField 1.0 FormulaField.qml -GridLayout 1.0 GridLayout.qml -Group 1.0 GroupBox.qml -GroupBox 1.0 GroupBox.qml -HelpButton 1.0 HelpButton.qml -InputListView 1.0 InputListView.qml -IntegerField 1.0 IntegerField.qml -JagsTableView 1.0 JagsTableView.qml -JAGSTextArea 1.0 JAGSTextArea.qml -JASPControl 1.0 JASPControl.qml -JASPGridControl 1.0 JASPGridControl.qml -JASPGridViewControl 1.0 JASPGridViewControl.qml -JASPScrollBar 1.0 JASPScrollBar.qml -Label 1.0 Label.qml -MenuButton 1.0 MenuButton.qml -ModelTermsList 1.0 ModelTermsList.qml -PercentField 1.0 PercentField.qml -RowLayout 1.0 RowLayout.qml -SubjectivePriors 1.0 SubjectivePriors.qml -SortMenuButton 1.0 SortMenuButton.qml -RoundedButton 1.0 RoundedButton.qml -RectangularButton 1.0 RectangularButton.qml -Section 1.0 ExpanderButton.qml -TabView 1.0 TabView.qml -Text 1.0 Text.qml -RadioButton 1.0 RadioButton.qml -RadioButtonGroup 1.0 RadioButtonGroup.qml -RowComponents 1.0 RowComponents.qml -SetSeed 1.0 SetSeed.qml -SimpleTableView 1.0 SimpleTableView.qml -Slider 1.0 Slider.qml -Switch 1.0 Switch.qml -TableView 1.0 TableView.qml -TextField 1.0 TextField.qml -TextArea 1.0 TextArea.qml -VariablesForm 1.0 VariablesForm.qml -VariablesList 1.0 VariablesList.qml diff --git a/QMLComponents/components/JASP/Controls/tableviewcolumn.qmodel b/QMLComponents/components/JASP/Controls/tableviewcolumn.qmodel deleted file mode 100644 index 4da1cd2a65f..00000000000 --- a/QMLComponents/components/JASP/Controls/tableviewcolumn.qmodel +++ /dev/null @@ -1,55 +0,0 @@ - - - - {d0f8e5ce-737c-4774-90d2-89468dd55a71} - - - - - - - - {7ef386b4-3579-4a69-8d9c-8ab857ce1a05} - - - TableViewColumn - - - - - - - {bea79fb9-c356-4c76-ae02-7d88f4d87b36} - - - - - - - - - - {bea79fb9-c356-4c76-ae02-7d88f4d87b36} - - - TableViewColumn - - - - - - - - - - - - - - - - - - - - diff --git a/QMLComponents/controls/checkboxbase.cpp b/QMLComponents/controls/checkboxbase.cpp deleted file mode 100644 index 676e1dbfab5..00000000000 --- a/QMLComponents/controls/checkboxbase.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "checkboxbase.h" -#include "log.h" -#include "analysisform.h" - -CheckBoxBase::CheckBoxBase(QQuickItem* parent) - : JASPControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::CheckBox; -} - -bool CheckBoxBase::isJsonValid(const Json::Value &value) const -{ - return value.type() == Json::booleanValue; -} - -Json::Value CheckBoxBase::createJson() const -{ - return checked(); -} - -void CheckBoxBase::bindTo(const Json::Value &value) -{ - BoundControlBase::bindTo(value); - setChecked(value.asBool()); -} - -void CheckBoxBase::setUp() -{ - JASPControl::setUp(); - connect(this, &CheckBoxBase::clicked, this, &CheckBoxBase::clickedSlot); -} - -void CheckBoxBase::setChecked(bool checked) -{ - setProperty("checked", checked); -} - -bool CheckBoxBase::checked() const -{ - return property("checked").toBool(); -} - -void CheckBoxBase::clickedSlot() -{ - setBoundValue(checked()); -} diff --git a/QMLComponents/controls/checkboxbase.h b/QMLComponents/controls/checkboxbase.h deleted file mode 100644 index e9e5f03be85..00000000000 --- a/QMLComponents/controls/checkboxbase.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef CHECKBOXBASE_H -#define CHECKBOXBASE_H - -#include "jaspcontrol.h" -#include "boundcontrols/boundcontrolbase.h" - -class CheckBoxBase : public JASPControl, public BoundControlBase -{ - Q_OBJECT - -public: - CheckBoxBase(QQuickItem* parent = nullptr); - - bool isJsonValid(const Json::Value& value) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - void setUp() override; - - void setChecked(bool checked); - bool checked() const; - -signals: - void clicked(); - -protected slots: - void clickedSlot(); - -}; - -#endif // CHECKBOXBASE_H diff --git a/QMLComponents/controls/comboboxbase.cpp b/QMLComponents/controls/comboboxbase.cpp deleted file mode 100644 index 1dca7fa4680..00000000000 --- a/QMLComponents/controls/comboboxbase.cpp +++ /dev/null @@ -1,281 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "comboboxbase.h" -#include "analysisform.h" -#include "log.h" - - -ComboBoxBase::ComboBoxBase(QQuickItem* parent) - : JASPListControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::ComboBox; - _hasUserInteractiveValue = true; -} - -void ComboBoxBase::bindTo(const Json::Value& value) -{ - _model->resetTermsFromSources(); - - std::vector values = _model->getValues(); - std::string selectedValue = value.asString(); - int index = -1; - - if (values.size() > 0) - { - if (selectedValue.empty()) index = 0; - else - { - auto itr = std::find(values.begin(), values.end(), selectedValue); - - if (itr == values.end()) - { - // Buggy situation: the value is not one of the available values of the DropDown. - // This might happen with a corrupted JASP file, or an old bug like https://github.com/jasp-stats/jasp-test-release/issues/1836 - // Before throwing an error message, let's be a bit flexible: if we can find a value which is case-insensitive equal to the selectedValue, - // then we can be confident that it is the right one. - auto caseInsensitiveEquals = [&](const std::string& s) - { - return std::equal(s.begin(), s.end(), - selectedValue.begin(), selectedValue.end(), - [](char a, char b) { return tolower(a) == tolower(b); }); - }; - itr = std::find_if(values.begin(), values.end(), caseInsensitiveEquals); - if (itr != values.end()) - Log::log() << "Option " << selectedValue << " in DropDown " << name() << " found but not with the same case: " << *itr << std::endl; - } - - if (itr == values.end()) - { - // Try also to find a label equals to the selectedValue. - auto labelEqualts = [&](const std::string& s) - { - return fq(_model->getLabel(tq(s))) == selectedValue; - }; - itr = std::find_if(values.begin(), values.end(), labelEqualts); - if (itr != values.end()) - Log::log() << "Option " << selectedValue << " in DropDown " << name() << " found but as label." << std::endl; - } - - if (itr == values.end()) - { - addControlError(tr("Unknown option %1 in DropDown %2").arg(tq(selectedValue)).arg(name())); - index = 0; - } - index = int(std::distance(values.begin(), itr)); - } - } - - _setCurrentProperties(index); // This will call the BoundControlBase::bindTo method - - _resetItemWidth(); - - BoundControlBase::bindTo(value); -} - -int ComboBoxBase::_getStartIndex() const -{ - if (!startValue().isEmpty()) return _model->getIndexOfValue(startValue()); - if (currentIndex() != -1) return currentIndex(); - if (!currentValue().isEmpty()) return _model->getIndexOfValue(currentValue()); - if (!currentText().isEmpty()) return _model->getIndexOfLabel(currentText()); - return -1; -} - -Json::Value ComboBoxBase::createJson() const -{ - std::vector options = _model->getValues(); - - int index = _getStartIndex(); - - if (options.size() == 0) index = -1; - else if (index == -1 || (index >= int(options.size()))) index = 0; - - std::string selected = index >= 0 ? options[size_t(index)] : ""; - - return selected; -} - -bool ComboBoxBase::isJsonValid(const Json::Value &optionValue) const -{ - return optionValue.type() == Json::stringValue; -} - -void ComboBoxBase::setUp() -{ - JASPListControl::setUp(); - - _model->resetTermsFromSources(); - - connect(this, &ComboBoxBase::activated, this, &ComboBoxBase::activatedSlot); - connect(this, &JASPListControl::addEmptyValueChanged, [this] () { _model->resetTermsFromSources(); } ); - connect(this, &ComboBoxBase::currentIndexChanged, [this] () { _setCurrentProperties(currentIndex()); } ); // Case when currentIndex is changed in QML - - if (form()) - connect(form(), &AnalysisForm::languageChanged, [this] () { _model->resetTermsFromSources(); } ); - -} - -void ComboBoxBase::setUpModel() -{ - _model = new ListModelLabelValueTerms(this); - JASPListControl::setUpModel(); -} - -std::vector ComboBoxBase::usedVariables() const -{ - if (containsVariables()) return { fq(_currentValue) }; - else return {}; -} - -void ComboBoxBase::termsChangedHandler() -{ - std::vector values = _model->getValues(); - int index = -1; - - if (values.size() > 0) - { - if (initialized()) - { - auto itr = std::find(values.begin(), values.end(), fq(_currentValue)); - - if (itr == values.end()) index = _getStartIndex(); - else index = int(std::distance(values.begin(), itr)); - } - else index = _getStartIndex(); - - if (index < 0 || index > int(values.size())) index = 0; - } - - _setCurrentProperties(index); - - _resetItemWidth(); -} - -void ComboBoxBase::activatedSlot(int index) -{ - _setCurrentProperties(index); -} - -void ComboBoxBase::_resetItemWidth() -{ - const Terms& terms = _model->terms(); - QMetaObject::invokeMethod(this, "resetWidth", Q_ARG(QVariant, QVariant(terms.asQList()))); -} - -void ComboBoxBase::setCurrentText(QString text) -{ - if (initialized()) - _setCurrentProperties(_model->getIndexOfLabel(text)); - else - _currentText = text; -} - -void ComboBoxBase::setCurrentValue(QString value) -{ - if (initialized()) - _setCurrentProperties(_model->getIndexOfValue(value)); - else - _currentValue = value; -} -void ComboBoxBase::setCurrentIndex(int index) -{ - if (initialized()) - _setCurrentProperties(index); - else - _currentIndex = index; // In this case it is used as start index -} - -void ComboBoxBase::_setCurrentProperties(int index, bool bindValue) -{ - QString currentColumnType, currentValue, currentText, currentColumnTypeIcon; - - if (index >= _model->rowCount()) - index = 0; - - if (index >= 0) - { - QModelIndex modelIndex(_model->index(index, 0)); - - currentColumnType = _model->data(modelIndex, ListModel::ColumnTypeRole ).toString(); - currentColumnTypeIcon = _model->data(modelIndex, ListModel::ColumnTypeIconRole).toString(); - currentText = _model->data(modelIndex, ListModel::NameRole ).toString(); - currentValue = _model->data(modelIndex, ListModel::ValueRole ).toString(); - } - - // emit signals when all values are set, so that when 1 of the signals is caught, - // all values are coherent - bool emitCurrentTextSignal = _currentText != currentText, - emitCurrentValueSignal = _currentValue != currentValue, - emitCurrentIndexSignal = _currentIndex != index, - emitCurrentColumnTypeSignal = _currentColumnType != currentColumnType, - emitCurrentColumnTypeIconSignal = _currentColumnTypeIcon != currentColumnTypeIcon; - - _currentText = currentText; - _currentValue = currentValue; - _currentColumnType = currentColumnType; - _currentColumnTypeIcon = currentColumnTypeIcon; - _currentIndex = index; - - if (emitCurrentTextSignal) emit currentTextChanged(); - if (emitCurrentValueSignal) emit currentValueChanged(); - if (emitCurrentColumnTypeSignal) emit currentColumnTypeChanged(); - if (emitCurrentColumnTypeIconSignal) emit currentColumnTypeIconChanged(); - if (emitCurrentIndexSignal) emit currentIndexChanged(); - - if (bindValue && initialized()) - setBoundValue(fq(_currentValue)); - - if(emitCurrentValueSignal && containsVariables()) - emit usedVariablesChanged(); -} - - -QString ComboBoxBase::helpMD(SetConst & markdowned, int howDeep, bool) const -{ - QStringList md = { JASPControl::helpMD(markdowned, howDeep, false) }; - howDeep++; - - if (values().isValid() && !values().isNull()) - { - bool isInteger = false; - values().toInt(&isInteger); - - if (!isInteger) - { - QList list = values().toList(); - if (!list.isEmpty()) - { - for (const QVariant& itemVariant : list) - { - QMap labelValueInfoTriplet = itemVariant.toMap(); - if (labelValueInfoTriplet.contains(labelRole()) && labelValueInfoTriplet.contains("info")) - { - QString label = labelValueInfoTriplet[labelRole()].toString(), - info = labelValueInfoTriplet["info"].toString(); - - md << ( QString{howDeep, ' '} + "- *" + label + "*: " + info); - } - } - } - } - } - - - return md.join("\n"); -} diff --git a/QMLComponents/controls/comboboxbase.h b/QMLComponents/controls/comboboxbase.h deleted file mode 100644 index 96daf6a2d32..00000000000 --- a/QMLComponents/controls/comboboxbase.h +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef COMBOBOXBASE_H -#define COMBOBOXBASE_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include "models/listmodel.h" -#include "models/listmodellabelvalueterms.h" -#include - -class ComboBoxBase : public JASPListControl, public BoundControlBase -{ - Q_OBJECT - - Q_PROPERTY( int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged ) - Q_PROPERTY( QString currentText READ currentText WRITE setCurrentText NOTIFY currentTextChanged ) - Q_PROPERTY( QString currentValue READ currentValue WRITE setCurrentValue NOTIFY currentValueChanged ) - Q_PROPERTY( QString startValue READ startValue WRITE setStartValue NOTIFY startValueChanged ) - Q_PROPERTY( QString currentColumnType READ currentColumnType NOTIFY currentColumnTypeChanged ) - Q_PROPERTY( QString currentColumnTypeIcon READ currentColumnTypeIcon NOTIFY currentColumnTypeIconChanged ) -public: - ComboBoxBase(QQuickItem* parent = nullptr); - - void bindTo(const Json::Value& value) override; - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void setUp() override; - ListModel* model() const override { return _model; } - void setUpModel() override; - QString helpMD(SetConst & markdowned, - int howDeep = 2, bool asList=true) const override; - - const QString& currentText() const { return _currentText; } - const QString& currentValue() const { return _currentValue; } - const QString& startValue() const { return _startValue; } - const QString& currentColumnType() const { return _currentColumnType; } - const QString& currentColumnTypeIcon() const { return _currentColumnTypeIcon;} - int currentIndex() const { return _currentIndex; } - - std::vector usedVariables() const override; - - -signals: - void currentTextChanged(); - void currentValueChanged(); - void startValueChanged(); - void currentColumnTypeChanged(); - void currentColumnTypeIconChanged(); - void currentIndexChanged(); - void activated(int index); - -protected slots: - void termsChangedHandler() override; - void setCurrentIndex(int index); - void setCurrentValue(QString value); - void setCurrentText(QString text); - void activatedSlot(int index); - - GENERIC_SET_FUNCTION(StartValue, _startValue, startValueChanged, QString ) - -protected: - ListModelLabelValueTerms* _model = nullptr; - QString _currentText, - _currentValue, - _startValue, - _currentColumnType, - _currentColumnTypeIcon; - int _currentIndex = -1; - - int _getStartIndex() const; - void _resetItemWidth(); - void _setCurrentProperties(int index, bool bindValue = true); - -}; - -#endif // COMBOBOXBASE_H diff --git a/QMLComponents/controls/componentslistbase.cpp b/QMLComponents/controls/componentslistbase.cpp deleted file mode 100644 index b800e469bc9..00000000000 --- a/QMLComponents/controls/componentslistbase.cpp +++ /dev/null @@ -1,376 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "componentslistbase.h" -#include "rowcontrols.h" -#include "log.h" - -ComponentsListBase::ComponentsListBase(QQuickItem *parent) - : JASPListControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::ComponentsList; - _useControlMouseArea = false; -} - -void ComponentsListBase::setUpModel() -{ - _termsModel = new ListModelTermsAssigned(this); - JASPListControl::setUpModel(); - - connect(this, &ComponentsListBase::nameChanged, this, &ComponentsListBase::nameChangedHandler); - connect(this, &ComponentsListBase::addItem, this, &ComponentsListBase::addItemHandler); - connect(this, &ComponentsListBase::removeItem, this, &ComponentsListBase::removeItemHandler); - connect(this, &ComponentsListBase::initializedChanged, this, &ComponentsListBase::resetDefaultValue); -} - -void ComponentsListBase::bindTo(const Json::Value& value) -{ - BoundControlBase::bindTo(value); - - std::string keyName = fq(_optionKey); - Terms terms; - ListModel::RowControlsValues allControlValues; - - _readTableValue(value, keyName, containsInteractions(), terms, allControlValues); - - _termsModel->initTerms(terms, allControlValues); -} - -void ComponentsListBase::setUp() -{ - JASPListControl::setUp(); - - QQuickItem* ancestor = parentItem(); - while (ancestor) - { - JASPControl* control = qobject_cast(ancestor); - if (control && control->dependsOnDynamicComponents()) - { - control->addDependency(this); - return; - } - - ancestor = ancestor->parentItem(); - } -} - -Json::Value ComponentsListBase::createJson() const -{ - std::string keyName = fq(_optionKey); - Json::Value result(Json::arrayValue); - - if (hasSource()) - { - Terms initTerms = _termsModel->getSourceTerms(); - for (const Term& term : initTerms) - { - Json::Value row(Json::objectValue); - if (containsInteractions()) - { - Json::Value keyTerm(Json::arrayValue); - for (const std::string& term: term.scomponents()) - keyTerm.append(term); - row[keyName] = keyTerm; - } - else - row[keyName] = term.asString(); - result.append(row); - } - } - else - { - QString defaultName = property("newItemName").toString(); - QList defaultValues = property("defaultValues").toList(); - int minimumItems = property("minimumItems").toInt(); - - while (defaultValues.length() < minimumItems) - defaultValues.push_back(defaultName); - - QList keyValues; - - int nbOfRows = _defaultValues.length(); - if (_minimumItems > nbOfRows) nbOfRows = _minimumItems; - for (int rowNb = 0; rowNb < nbOfRows; rowNb++) - { - QVariantMap defaultValuesMap; - if (rowNb < _defaultValues.length()) defaultValuesMap = _defaultValues[rowNb].toMap(); - Json::Value row(Json::objectValue); - - QString keyValue = _newItemName; - if (defaultValuesMap.contains(_optionKey)) - keyValue = defaultValuesMap[_optionKey].toString(); - - keyValue = _makeUnique(keyValue, keyValues); - keyValues.push_back(keyValue); - - row[keyName] = fq(keyValue); - - QMapIterator it(defaultValuesMap); - while (it.hasNext()) - { - it.next(); - QString name = it.key(); - - if (name != _optionKey) - { - QVariant valueVar = it.value(); - switch (valueVar.typeId()) - { - case QMetaType::Int: row[fq(name)] = valueVar.toInt(); break; - case QMetaType::Double: row[fq(name)] = valueVar.toDouble(); break; - case QMetaType::Bool: row[fq(name)] = valueVar.toBool(); break; - case QMetaType::QString: row[fq(name)] = fq(valueVar.toString()); break; - default: - { - if (valueVar.canConvert()) row[fq(name)] = fq(valueVar.toString()); - else Log::log() << "Cannot convert default values with key " << name << " in ComponentList " << this->name() << std::endl; - } - } - } - } - result.append(row); - } - } - - return result; -} - -void ComponentsListBase::resetDefaultValue() -{ - if (hasSource()) return; - - // This slot is called when the component is initialized - // If the default values are not given by the defaultValues property, then it must be set by the default values of - // the components self. When the ComponentsList is initialized, the components are created and we can ask them their default values - Json::Value defaultJson = createJson(); - uint defaultValuesRows = property("defaultValues").toList().size(); - - if (defaultJson.size() > defaultValuesRows) - { - const Terms& terms = _termsModel->terms(); - const QMap& allRowControls = _termsModel->getAllRowControls(); - - for (uint i = defaultValuesRows; i < defaultJson.size(); i++) - { - if (terms.size() > i) - { - const QString& key = terms.at(i).asQString(); - RowControls* rowControls = allRowControls[key]; - if (!rowControls) - { - Log::log() << "Cannot find " << key << " in row controls!" << std::endl; - continue; - } - const QMap& controlMap = rowControls->getJASPControlsMap(); - Json::Value row(Json::objectValue); - - row[fq(_optionKey)] = fq(key); - for (const QString& controlName : controlMap.keys()) - { - JASPControl* control = controlMap[controlName]; - BoundControl* boundControl = control->boundControl(); - if (boundControl) - row[fq(controlName)] = boundControl->defaultBoundValue(); - } - defaultJson[i] = row; - } - } - } - setDefaultBoundValue(defaultJson); -} - - - -bool ComponentsListBase::isJsonValid(const Json::Value &value) const -{ - return value.isArray(); -} - -void ComponentsListBase::termsChangedHandler() -{ - _setTableValue(_termsModel->terms(), _termsModel->getTermsWithComponentValues(), fq(_optionKey), containsInteractions()); - bindOffsets(); - emit offsetsChanged(); -} - -void ComponentsListBase::bindOffsets() -{ - if (_termsModel && _termsModel->rowCount() > 0) - { - RowControls* row = _termsModel->getRowControls(_termsModel->terms().at(0).asQString()); - if (row) - for (JASPControl* control : row->getJASPControlsMap().values()) - connect(control, &JASPControl::xChanged, this, &ComponentsListBase::offsetsChanged, Qt::UniqueConnection); - } -} - -QList ComponentsListBase::offsets() -{ - QList result; - if (_termsModel && _termsModel->rowCount() > 0) - { - RowControls* row = _termsModel->getRowControls(_termsModel->terms().at(0).asQString()); - if (row) - for (JASPControl* control : row->getJASPControlsMap().values()) - result.append(control->x()); - - std::sort(result.begin(), result.end()); - } - - return result; -} - -Json::Value ComponentsListBase::getJsonFromComponentValues(const ListModel::RowControlsValues &termsWithComponentValues) -{ - Terms terms; - for (const QString& term : termsWithComponentValues.keys()) - terms.add(Term::readTerm(term)); - - return _getTableValueOption(terms, termsWithComponentValues, fq(_optionKey), containsInteractions()); -} - -void ComponentsListBase::addItemHandler() -{ - Terms newTerms; - QString newTerm = _makeUnique(_newItemName); - newTerms.add(newTerm); - ListModel::RowControlsValues rowValues; - - if (_duplicateWhenAdding) - { - QMap jsonValues; - - const Json::Value & boundVal = boundValue(); - int currentIndex = property("currentIndex").toInt(); - const Terms & terms = _termsModel->terms(); - - if (boundVal.isArray() && int(terms.size()) >= currentIndex) - { - std::string keyString = terms.at(size_t(currentIndex)).asString(); - - for (const Json::Value& jsonVal : boundVal) - { - const Json::Value& keyVal = jsonVal.get(fq(_optionKey), Json::nullValue); - - if (keyVal.asString() == keyString) - { - for (const std::string& member : jsonVal.getMemberNames()) - jsonValues[tq(member)] = jsonVal.get(member, Json::nullValue); - } - - jsonValues[_optionKey] = fq(newTerm); - } - } - rowValues[newTerm] = jsonValues; - } - _termsModel->addTerms(newTerms, -1, rowValues); - setProperty("currentIndex", _termsModel->rowCount() - 1); -} - -void ComponentsListBase::removeItemHandler(int index) -{ - _termsModel->removeTerm(index); - setProperty("currentIndex", index >= _termsModel->rowCount() ? index - 1 : index); -} - -void ComponentsListBase::nameChangedHandler(int index, QString name) -{ - if (index < 0) - return; - if (index >= _termsModel->rowCount()) - { - Log::log() << "Index " << index << " in ListModelTabView is greater than the maximum " << _termsModel->rowCount() << std::endl; - return; - } - - if (name.isEmpty()) - name = property("newItemName").toString(); - - name = _makeUnique(name, index); - - if (isBound()) - { - // The name is the key value that allows to distinguish the elements of the components list. - // So this must be also updated in the bound value. - Json::Value val = boundValue(); - if (val.isArray() && val.size() > index) - { - val[index][fq(_optionKey)] = fq(name); - setBoundValue(val, false); - } - } - - _termsModel->changeTerm(index, name); -} - -QString ComponentsListBase::_changeLastNumber(const QString &val) const -{ - QString result = val; - - int index; - for (index = val.length() - 1; index >= 0 ; index--) - { - if (!val.at(index).isDigit()) - break; - } - index++; - - int num = -1; - if (index >= 0 && index < val.length()) - { - bool ok = false; - num = val.right(val.length() - index).toInt(&ok); - if (!ok) - num = -1; - } - - if (num >= 0) - return result.left(index).append(QString::number(num + 1)); - else - return result.append(QString::number(2)); -} - -QString ComponentsListBase::_makeUnique(const QString &val, int index) const -{ - QList values = _termsModel->terms().asQList(); - - return _makeUnique(val, values, index); -} - -QString ComponentsListBase::_makeUnique(const QString &val, const QList &values, int index) const -{ - QString result = val; - - bool isUnique = true; - do - { - int i = 0; - isUnique = true; - for (const QString& value : values) - { - if (i != index && value == result) - { - isUnique = false; - result = _changeLastNumber(result); - } - i++; - } - } while (!isUnique); - - return result; -} diff --git a/QMLComponents/controls/componentslistbase.h b/QMLComponents/controls/componentslistbase.h deleted file mode 100644 index 40553dfb8ef..00000000000 --- a/QMLComponents/controls/componentslistbase.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef COMPONENTSLIST_H -#define COMPONENTSLIST_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include "models/listmodeltermsassigned.h" - -class ComponentsListBase : public JASPListControl, public BoundControlBase -{ - Q_OBJECT - - Q_PROPERTY( bool addItemManually READ addItemManually WRITE setAddItemManually NOTIFY addItemManuallyChanged ) - Q_PROPERTY( int minimumItems READ minimumItems WRITE setMinimumItems NOTIFY minimumItemsChanged ) - Q_PROPERTY( int maximumItems READ maximumItems WRITE setMaximumItems NOTIFY maximumItemsChanged ) - Q_PROPERTY( QString newItemName READ newItemName WRITE setNewItemName NOTIFY newItemNameChanged ) - Q_PROPERTY( QList defaultValues READ defaultValues WRITE setDefaultValues NOTIFY defaultValuesChanged ) - Q_PROPERTY( bool duplicateWhenAdding READ duplicateWhenAdding WRITE setDuplicateWhenAdding NOTIFY duplicateWhenAddingChanged ) - Q_PROPERTY( QList offsets READ offsets NOTIFY offsetsChanged ) - -public: - ComponentsListBase(QQuickItem* item = nullptr); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - ListModel* model() const override { return _termsModel; } - void setUp() override; - void setUpModel() override; - - QString newItemName() const { return _newItemName; } - bool addItemManually() const { return _addItemManually; } - int minimumItems() const { return _minimumItems; } - int maximumItems() const { return _maximumItems; } - QList defaultValues() const { return _defaultValues; } - bool duplicateWhenAdding() const { return _duplicateWhenAdding; } - void bindOffsets(); - QList offsets(); - - Json::Value getJsonFromComponentValues(const ListModel::RowControlsValues& termsWithComponentValues); - -signals: - void addItem(); - void removeItem(int index); - void nameChanged(int index, QString name); - void newItemNameChanged(); - void addItemManuallyChanged(); - void minimumItemsChanged(); - void maximumItemsChanged(); - void defaultValuesChanged(); - void duplicateWhenAddingChanged(); - void offsetsChanged(); - -public slots: - GENERIC_SET_FUNCTION(NewItemName, _newItemName, newItemNameChanged, QString ) - GENERIC_SET_FUNCTION(AddItemManually, _addItemManually, addItemManuallyChanged, bool ) - GENERIC_SET_FUNCTION(MinimumItems, _minimumItems, minimumItemsChanged, int ) - GENERIC_SET_FUNCTION(MaximumItems, _maximumItems, maximumItemsChanged, int ) - GENERIC_SET_FUNCTION(DefaultValues, _defaultValues, defaultValuesChanged, QList ) - GENERIC_SET_FUNCTION(DuplicateWhenAdding, _duplicateWhenAdding, duplicateWhenAddingChanged, bool ) - -protected slots: - void termsChangedHandler() override; - void addItemHandler(); - void removeItemHandler(int index); - void nameChangedHandler(int index, QString name); - void resetDefaultValue(); - -protected: - QString _makeUnique(const QString& val, int index = -1) const; - QString _makeUnique(const QString& val, const QList& values, int index = -1) const; - QString _changeLastNumber(const QString& val) const; - -private: - ListModelTermsAssigned* _termsModel = nullptr; - QString _newItemName = "#"; - bool _addItemManually = false, - _duplicateWhenAdding = false; - int _minimumItems = 0, - _maximumItems = -1; - QList _defaultValues; -}; - -#endif // COMPONENTSLIST_H diff --git a/QMLComponents/controls/expanderbuttonbase.cpp b/QMLComponents/controls/expanderbuttonbase.cpp deleted file mode 100644 index 3da59063f4e..00000000000 --- a/QMLComponents/controls/expanderbuttonbase.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "expanderbuttonbase.h" -#include "analysisform.h" - -ExpanderButtonBase::ExpanderButtonBase(QQuickItem *parent) - : JASPControl(parent) -{ - _controlType = ControlType::Expander; -} - -void ExpanderButtonBase::setUp() -{ - if (!form()) - return; - - setInitialized(); -} diff --git a/QMLComponents/controls/expanderbuttonbase.h b/QMLComponents/controls/expanderbuttonbase.h deleted file mode 100644 index 4bad82dcb00..00000000000 --- a/QMLComponents/controls/expanderbuttonbase.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef EXPANDERBUTTONBASE_H -#define EXPANDERBUTTONBASE_H - -#include "jaspcontrol.h" - -#include - -class ExpanderButtonBase : public JASPControl -{ - Q_OBJECT -public: - explicit ExpanderButtonBase(QQuickItem *parent = nullptr); - - void setUp() override; -}; - -#endif // EXPANDERBUTTONBASE_H diff --git a/QMLComponents/controls/factorlevellistbase.cpp b/QMLComponents/controls/factorlevellistbase.cpp deleted file mode 100644 index c9590fa86d5..00000000000 --- a/QMLComponents/controls/factorlevellistbase.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "factorlevellistbase.h" - -using namespace std; - -FactorLevelListBase::FactorLevelListBase(QQuickItem *parent) - : JASPListControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::FactorLevelList; -} - -void FactorLevelListBase::setUpModel() -{ - _factorLevelsModel = new ListModelFactorLevels(this); - JASPListControl::setUpModel(); -} - -void FactorLevelListBase::setUp() -{ - JASPListControl::setUp(); - - connect(this, &FactorLevelListBase::itemChanged, _factorLevelsModel, &ListModelFactorLevels::itemChanged); - connect(this, &FactorLevelListBase::itemRemoved, _factorLevelsModel, &ListModelFactorLevels::itemRemoved); -} - -void FactorLevelListBase::bindTo(const Json::Value& value) -{ - vector > > factors; - - for (const Json::Value& row : value) - { - vector factorLevels; - for (const Json::Value& level : row["levels"]) - factorLevels.push_back(level.asString()); - - factors.push_back(make_pair(row["name"].asString(), factorLevels)); - } - - _factorLevelsModel->initFactors(factors); - - BoundControlBase::bindTo(value); -} - -Json::Value FactorLevelListBase::createJson() const -{ - Json::Value result(Json::arrayValue); - - for (int i = 0; i < minFactors(); i++) - { - Json::Value factor(Json::objectValue); - factor["name"] = fq(getFactorName(i + 1)); - - Json::Value levels(Json::arrayValue); - for (int j = 0; j < minLevels(); j++) - levels.append(fq(getLevelName(j + 1))); - - factor["levels"] = levels; - result.append(factor); - } - - return result; -} - -Json::Value FactorLevelListBase::createMeta() const -{ - Json::Value meta(BoundControlBase::createMeta()); //Work from parent to get everything it defines - - auto factors = _factorLevelsModel->getFactors(); - - if(factors.size() == 0) - return meta; - - meta["encodeThis"] = Json::arrayValue; - for (const auto & factor : factors) - { - meta["encodeThis"].append(factor.first); - - for(const auto & level : factor.second) - meta["encodeThis"].append(level); - } - - return meta; -} - -bool FactorLevelListBase::isJsonValid(const Json::Value &value) const -{ - bool valid = value.isArray(); - - if (valid) - { - for (const Json::Value& row : value) - { - valid = row.isObject() && row["name"].isString() && row["levels"].isArray(); - if (!valid) break; - } - } - - return valid; -} - -void FactorLevelListBase::termsChangedHandler() -{ - Json::Value boundValue(Json::arrayValue); - const vector > > &factors = _factorLevelsModel->getFactors(); - - for (const auto &factor : factors) - { - Json::Value row(Json::objectValue); - row["name"] = factor.first; - - Json::Value levels(Json::arrayValue); - for (const string &level : factor.second) - levels.append(level); - - row["levels"] = levels; - boundValue.append(row); - } - - setNbFactors(factors.size()); - setBoundValue(boundValue); -} diff --git a/QMLComponents/controls/factorlevellistbase.h b/QMLComponents/controls/factorlevellistbase.h deleted file mode 100644 index 9bdbb0d9bd2..00000000000 --- a/QMLComponents/controls/factorlevellistbase.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef FACTORLEVELLISTBASE_H -#define FACTORLEVELLISTBASE_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include "models/listmodelfactorlevels.h" - -class FactorLevelListBase : public JASPListControl, public BoundControlBase -{ - Q_OBJECT - - Q_PROPERTY( QString factorName READ factorName WRITE setFactorName NOTIFY factorNameChanged ) - Q_PROPERTY( QString levelName READ levelName WRITE setLevelName NOTIFY levelNameChanged ) - Q_PROPERTY( QString factorPlaceHolder READ factorPlaceHolder WRITE setFactorPlaceHolder NOTIFY factorPlaceHolderChanged ) - Q_PROPERTY( QString levelPlaceHolder READ levelPlaceHolder WRITE setLevelPlaceHolder NOTIFY levelPlaceHolderChanged ) - Q_PROPERTY( int minFactors READ minFactors WRITE setMinFactors NOTIFY minFactorsChanged ) - Q_PROPERTY( int minLevels READ minLevels WRITE setMinLevels NOTIFY minLevelsChanged ) - Q_PROPERTY( int nbFactors READ nbFactors NOTIFY nbFactorsChanged ) - -public: - FactorLevelListBase(QQuickItem* parent = nullptr); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - Json::Value createMeta() const override; - void bindTo(const Json::Value& value) override; - bool encodeValue() const override { return true; } - ListModel* model() const override { return _factorLevelsModel; } - void setUpModel() override; - void setUp() override; - - QString factorName() const { return _factorName; } - QString levelName() const { return _levelName; } - QString factorPlaceHolder() const { return _factorPlaceHolder; } - QString levelPlaceHolder() const { return _levelPlaceHolder; } - int minFactors() const { return _minFactors; } - int minLevels() const { return _minLevels; } - int nbFactors() const { return _nbFactors; } - - QString getFactorName(int i) const { return QStringLiteral("%1 %2").arg(_factorName).arg(i); } - QString getLevelName(int i) const { return QStringLiteral("%1 %2").arg(_levelName).arg(i); } - -signals: - void itemChanged(int index, QString name); - void itemRemoved(int index); - - void factorNameChanged(); - void levelNameChanged(); - void factorPlaceHolderChanged(); - void levelPlaceHolderChanged(); - void minFactorsChanged(); - void minLevelsChanged(); - void nbFactorsChanged(); - -protected slots: - void termsChangedHandler() override; - -protected: - GENERIC_SET_FUNCTION(FactorName, _factorName, factorNameChanged, QString ) - GENERIC_SET_FUNCTION(LevelName, _levelName, levelNameChanged, QString ) - GENERIC_SET_FUNCTION(FactorPlaceHolder, _factorPlaceHolder, factorPlaceHolderChanged, QString ) - GENERIC_SET_FUNCTION(LevelPlaceHolder, _levelPlaceHolder, levelPlaceHolderChanged, QString ) - GENERIC_SET_FUNCTION(MinFactors, _minFactors, minFactorsChanged, int ) - GENERIC_SET_FUNCTION(MinLevels, _minLevels, minLevelsChanged, int ) - GENERIC_SET_FUNCTION(NbFactors, _nbFactors, nbFactorsChanged, int ) - -private: - ListModelFactorLevels* _factorLevelsModel = nullptr; - - QString _factorName; - QString _levelName; - QString _factorPlaceHolder; - QString _levelPlaceHolder; - int _minFactors = 1, - _minLevels = 2, - _nbFactors = 1; - -}; - -#endif // FACTORLEVELLISTBASE_H diff --git a/QMLComponents/controls/factorsformbase.cpp b/QMLComponents/controls/factorsformbase.cpp deleted file mode 100644 index b47acd0c1d9..00000000000 --- a/QMLComponents/controls/factorsformbase.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "factorsformbase.h" -#include "boundcontrols/boundcontrolterms.h" -#include "analysisform.h" -#include "qutils.h" -#include "variableslistbase.h" -#include "log.h" - -using namespace std; - -FactorsFormBase::FactorsFormBase(QQuickItem *parent) - : JASPListControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::FactorsForm; - _useControlMouseArea = false; - _containsVariables = true; -} - -void FactorsFormBase::setUpModel() -{ - _factorsModel = new ListModelFactorsForm(this); - - JASPListControl::setUpModel(); - - _availableVariablesListName = property("availableVariablesListName").toString(); - QVariant availableListVariant = property("availableVariablesList"); - _availableVariablesListItem = qobject_cast(availableListVariant.value()); - - connect(this, &FactorsFormBase::initializedChanged, this, &FactorsFormBase::countVariablesChanged); -} - -void FactorsFormBase::bindTo(const Json::Value& value) -{ - BoundControlBase::bindTo(value); - - ListModelFactorsForm::FactorVec factors; - - for (const Json::Value& factor : value) - { - vector indicators; - for (const Json::Value& indicator : factor["indicators"]) - indicators.push_back(indicator.asString()); - - factors.push_back(make_tuple(factor["name"].asString(), factor["title"].asString(), indicators)); - } - - _factorsModel->initFactors(factors); -} - -Json::Value FactorsFormBase::createJson() const -{ - Json::Value result(Json::arrayValue); - - for (int i = 0; i < _initNumberFactors; i++) - { - Json::Value row(Json::objectValue); - QString name("Factor"); - name += QString::number(i+1); - QString title("Factor "); - title += QString::number(i+1); - row["name"] = fq(name); - row["title"] = fq(title); - row["indicators"] = Json::Value(Json::arrayValue); - - result.append(row); - } - - return result; -} - -bool FactorsFormBase::isJsonValid(const Json::Value &value) const -{ - bool valid = value.isArray(); - if (valid) - { - for (const Json::Value& factor : value) - { - valid = factor.isObject() && factor["name"].isString() && factor["title"].isString() && factor["indicators"].isArray(); - if (!valid) break; - } - } - - return valid; -} - -void FactorsFormBase::termsChangedHandler() -{ - // This slot is called to set the boundValues if the factors are changed. - // This does not have to be called during the initialization of the FactorsForm: the _factorsModel might give the wrong information - // and during the initialization, the boundValues has to be set by the bindTo method anyway. - if (!initialized()) return; - - const ListModelFactorsForm::FactorVec &factors = _factorsModel->getFactors(); - Json::Value boundValue(Json::arrayValue); - - for (const auto &factor : factors) - { - Json::Value factorJson(Json::objectValue); - factorJson["name"] = get<0>(factor); - factorJson["title"] = get<1>(factor); - Json::Value indicators(Json::arrayValue); - for (const string &level : get<2>(factor)) - indicators.append(level); - factorJson["indicators"] = indicators; - boundValue.append(factorJson); - } - - setBoundValue(boundValue); -} - -void FactorsFormBase::factorAdded(int index, QVariant item) -{ - VariablesListBase* listView = item.value(); - if (!listView) - { - JASPControl* control = item.value(); - Log::log() << "JASP Control " << (control ? control->name() : "") << " is not a VariablesListBase in factorAdded" << std::endl; - return; - } - - _factorsModel->factorAdded(index, listView); - - connect(listView->model(), &ListModel::termsChanged, _factorsModel, &ListModelFactorsForm::resetModelTerms); - connect(listView->model(), &ListModel::termsChanged, this, &FactorsFormBase::countVariablesChanged); -} diff --git a/QMLComponents/controls/factorsformbase.h b/QMLComponents/controls/factorsformbase.h deleted file mode 100644 index 8429b366277..00000000000 --- a/QMLComponents/controls/factorsformbase.h +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef FACTORSFORMBASE_H -#define FACTORSFORMBASE_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include "models/listmodelfactorsform.h" - - -class FactorsFormBase : public JASPListControl, public BoundControlBase -{ - Q_OBJECT - - Q_PROPERTY( int initNumberFactors READ initNumberFactors WRITE setInitNumberFactors NOTIFY initNumberFactorsChanged ) - Q_PROPERTY( int countVariables READ countVariables NOTIFY countVariablesChanged ) - - -public: - FactorsFormBase(QQuickItem* parent = nullptr); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - ListModel* model() const override { return _factorsModel; } - void setUpModel() override; - - Q_INVOKABLE void addFactor() { _factorsModel->addFactor(); } - Q_INVOKABLE void removeFactor() { _factorsModel->removeFactor(); } - Q_INVOKABLE void titleChanged(int index, QString title) { _factorsModel->titleChangedSlot(index, title); } - Q_INVOKABLE void factorAdded(int index, QVariant item); - - int initNumberFactors() const { return _initNumberFactors; } - int countVariables() const { return _initialized ? _factorsModel->countVariables() : 0; } - JASPListControl* availableVariablesList() const { return _availableVariablesListItem; } - -signals: - void initNumberFactorsChanged(); - void countVariablesChanged(); - -protected slots: - void termsChangedHandler() override; - -protected: - GENERIC_SET_FUNCTION(InitNumberFactors, _initNumberFactors, initNumberFactorsChanged, int ) - -private: - ListModelFactorsForm* _factorsModel = nullptr; - QString _availableVariablesListName; - JASPListControl* _availableVariablesListItem = nullptr; - int _initNumberFactors = 1; -}; - -#endif // FACTORSFORMBASE_H diff --git a/QMLComponents/controls/inputlistbase.cpp b/QMLComponents/controls/inputlistbase.cpp deleted file mode 100644 index 416f659b8e6..00000000000 --- a/QMLComponents/controls/inputlistbase.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "inputlistbase.h" -#include "log.h" -#include "jaspcontrol.h" -#include "rowcontrols.h" - - -InputListBase::InputListBase(QQuickItem *parent) - : JASPListControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::InputListView; - _useControlMouseArea = false; -} - -void InputListBase::setUpModel() -{ - int minRows = property("minRows").toInt(); - QString placeHolder = property("placeHolder").toString(); - bool addVirtual = property("addVirtual").toBool(); - _inputModel = new ListModelInputValue(this, minRows); - _inputModel->setAddVirtual(addVirtual, placeHolder); - - QList defaultValues = property("defaultValues").toList(); - for (QVariant defaultValue : defaultValues) - _defaultValues.push_back(defaultValue.toString().toStdString()); - - connect(this, &InputListBase::itemChanged, _inputModel, &ListModelInputValue::itemChanged); - connect(this, &InputListBase::itemRemoved, _inputModel, &ListModelInputValue::itemRemoved); - - JASPListControl::setUpModel(); -} - -void InputListBase::bindTo(const Json::Value& value) -{ - BoundControlBase::bindTo(value); - - std::string keyName = fq(_optionKey); - Terms terms; - ListModel::RowControlsValues allControlValues; - - if (hasRowComponent()) - _readTableValue(value, keyName, containsInteractions(), terms, allControlValues); - else - { - for (const Json::Value& variable : value) - terms.add(Term(variable.asString())); - } - - _inputModel->initTerms(terms, allControlValues); -} - -Json::Value InputListBase::createJson() const -{ - Json::Value result(Json::arrayValue); - std::string keyName = fq(_optionKey); - - if (_defaultValues.size() > 0) - { - std::vector allOptions; - - for (const std::string& defaultValue : _defaultValues) - { - if (hasRowComponent()) - { - Json::Value row(Json::objectValue); - row[keyName] = defaultValue; - result.append(row); - } - else - result.append(defaultValue); - } - } - - return result; -} - -bool InputListBase::isJsonValid(const Json::Value &value) const -{ - bool valid = value.isArray(); - - if (valid) - { - for (const Json::Value& row : value) - { - if (hasRowComponent()) valid = row.isObject(); - else valid = row.isString(); - - if (!valid) break; - } - } - - return valid; -} - -void InputListBase::termsChangedHandler() -{ - if (hasRowComponent()) - _setTableValue(_inputModel->terms(), _inputModel->getTermsWithComponentValues(), fq(_optionKey), containsInteractions()); - else - { - const Terms& terms = _inputModel->terms(); - Json::Value boundValue(Json::arrayValue); - for (const Term& term : terms) - boundValue.append(term.asString()); - setBoundValue(boundValue); - } -} diff --git a/QMLComponents/controls/inputlistbase.h b/QMLComponents/controls/inputlistbase.h deleted file mode 100644 index cc104ab1421..00000000000 --- a/QMLComponents/controls/inputlistbase.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef INPUTLISTBASE_H -#define INPUTLISTBASE_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include "models/listmodelinputvalue.h" - -class InputListBase : public JASPListControl, public BoundControlBase -{ - Q_OBJECT - -public: - InputListBase(QQuickItem* parent = nullptr); - - bool isJsonValid(const Json::Value& optionValue) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - ListModel* model() const override { return _inputModel; } - void setUpModel() override; - -signals: - void itemChanged(int index, QString name); - void itemRemoved(int index); - -protected slots: - void termsChangedHandler() override; - -private: - ListModelInputValue* _inputModel = nullptr; - std::vector _defaultValues; - -}; - -#endif // INPUTLISTBASE_H diff --git a/QMLComponents/controls/jaspcontrol.cpp b/QMLComponents/controls/jaspcontrol.cpp deleted file mode 100644 index ae8a167baa0..00000000000 --- a/QMLComponents/controls/jaspcontrol.cpp +++ /dev/null @@ -1,851 +0,0 @@ -#include "jaspcontrol.h" -#include "jasplistcontrol.h" -#include "log.h" -#include "analysisform.h" -#include "jasptheme.h" -#include -#include -#include -#include - -const QStringList JASPControl::_optionReservedNames = {"data", "version"}; - -QMap JASPControl::_mouseAreaComponentMap; -QByteArray JASPControl::_mouseAreaDef = "\ - import QtQuick 2.9\n\ - MouseArea {\n\ - z: 5\n\ - anchors.fill: parent\n\ - acceptedButtons: Qt.NoButton\n\ -}"; - -QQmlComponent* JASPControl::getMouseAreaComponent(QQmlEngine* engine) -{ - QQmlComponent* result = _mouseAreaComponentMap[engine]; - if (result == nullptr) - { - result = new QQmlComponent(engine); - result->setData(_mouseAreaDef, QUrl()); - _mouseAreaComponentMap[engine] = result; - } - - return result; -} - -JASPControl::JASPControl(QQuickItem *parent) : QQuickItem(parent) -{ - setFlag(ItemIsFocusScope); - setActiveFocusOnTab(true); - /*if (JaspTheme::currentTheme()) // THis does not work... - { - // TODO: Add currentTheme changed font changed - QQmlProperty(this, "ToolTip.timeout", qmlContext(this)).write(JaspTheme::currentTheme()->toolTipTimeout()); - setProperty("ToolTip.delay", JaspTheme::currentTheme()->toolTipDelay()); - setProperty("ToolTip.tooltip.font", JaspTheme::currentTheme()->font()); - }*/ - - connect(this, &JASPControl::titleChanged, this, &JASPControl::helpMDChanged); - connect(this, &JASPControl::infoChanged, this, &JASPControl::helpMDChanged); - connect(this, &JASPControl::visibleChanged, this, &JASPControl::helpMDChanged); - connect(this, &JASPControl::visibleChildrenChanged, this, &JASPControl::helpMDChanged); - connect(this, &JASPControl::backgroundChanged, [this] () { if (!_focusIndicator) setFocusIndicator(_background); }); - connect(this, &JASPControl::infoChanged, [this] () { if (_toolTip.isEmpty()) setToolTip(_info); }); - connect(this, &JASPControl::toolTipChanged, [this] () { setShouldStealHover(!_toolTip.isEmpty()); }); - connect(this, &JASPControl::hasErrorChanged, this, &JASPControl::_setFocusBorder); - connect(this, &JASPControl::hasWarningChanged, this, &JASPControl::_setFocusBorder); - connect(this, &JASPControl::isDependencyChanged, this, &JASPControl::_setFocusBorder); - connect(this, &JASPControl::shouldShowFocusChanged, this, &JASPControl::_setFocusBorder); - connect(this, &JASPControl::activeFocusChanged, this, &JASPControl::_setShouldShowFocus); - connect(this, &JASPControl::focusOnTabChanged, this, &JASPControl::_setShouldShowFocus); - connect(this, &JASPControl::innerControlChanged, this, &JASPControl::_setShouldShowFocus); - //connect(this, &JASPControl::implicitWidthChanged, [this] () { setWidth(implicitWidth()); if (_preferredWidthBinding) setPreferredWidth(int(implicitWidth()), true); }); - //connect(this, &JASPControl::implicitHeightChanged, [this] () { setHeight(implicitHeight()); if (_preferredHeightBinding) setPreferredHeight(int(implicitHeight()), true); }); - connect(this, &JASPControl::indentChanged, [this] () { QQmlProperty(this, "Layout.leftMargin", qmlContext(this)).write( (indent() && JaspTheme::currentTheme()) ? JaspTheme::currentTheme()->indentationLength() : 0); }); - connect(this, &JASPControl::debugChanged, [this] () { _setBackgroundColor(); _setVisible(); } ); - connect(this, &JASPControl::parentDebugChanged, [this] () { _setBackgroundColor(); _setVisible(); } ); - connect(this, &JASPControl::toolTipChanged, [this] () { QQmlProperty(this, "ToolTip.text", qmlContext(this)).write(toolTip()); } ); - connect(this, &JASPControl::boundValueChanged, this, &JASPControl::_resetBindingValue); - connect(this, &JASPControl::activeFocusChanged, this, &JASPControl::_setFocus); - connect(this, &JASPControl::activeFocusChanged, this, &JASPControl::_notifyFormOfActiveFocus); -} - -JASPControl::~JASPControl() -{ - //first we disconnect the children because reconnectWithYourChildren connected them to the parent - //These might get triggered during the destructor of QQuickItem and then crash jasp... - for (JASPControl* child : getChildJASPControls(_childControlsArea)) - child->disconnect(); - - disconnect(); -} - -void JASPControl::setFocusOnTab(bool focus) -{ - if (focus != activeFocusOnTab()) - { - setActiveFocusOnTab(focus); - emit focusOnTabChanged(); - } -} - -void JASPControl::setInnerControl(QQuickItem* control) -{ - if (control != _innerControl) - { - _innerControl = control; - if (_innerControl && !qobject_cast(_innerControl)) - { - connect(_innerControl, &QQuickItem::activeFocusChanged, this, &JASPControl::_setShouldShowFocus); - //capture focus reason - control->installEventFilter(this); - } - - emit innerControlChanged(); - } -} - -void JASPControl::setPreferredHeight(int preferredHeight, bool isBinding) -{ - if (!isBinding) _preferredHeightBinding = false; // unbind with implicitHeight - - if (preferredHeight != _preferredHeight) - { - _preferredHeight = preferredHeight; - //setProperty("Layout.preferredHeight", preferredHeight); // This does not work... - bool success = QQmlProperty(this, "Layout.preferredHeight", qmlContext(this)).write(preferredHeight); - - emit preferredHeightChanged(); - } -} - -void JASPControl::setPreferredWidth(int preferredWidth, bool isBinding) -{ - if (!isBinding) _preferredWidthBinding = false; // unbind with implicitWidth - - if (preferredWidth != _preferredWidth) - { - _preferredWidth = preferredWidth; - QQmlProperty(this, "Layout.preferredWidth", qmlContext(this)).write(preferredWidth); - - emit preferredWidthChanged(); - } -} - -void JASPControl::_setShouldShowFocus() -{ - setShouldShowFocus(hasActiveFocus() && focusOnTab() && (!_innerControl || _innerControl->hasActiveFocus()) && !hasError()); -} - -void JASPControl::_setBackgroundColor() -{ - if (background() && JaspTheme::currentTheme() && (debug() || parentDebug())) - background()->setProperty("color", JaspTheme::currentTheme()->debugBackgroundColor()); -} - -void JASPControl::_setVisible() -{ - bool isDebug = false; -#ifdef JASP_DEBUG - isDebug = true; -#endif - if (!isDebug && (debug() || parentDebug())) - setVisible(false); -} - -void JASPControl::_resetBindingValue() -{ - // If a control gets a value from a JASP file, this value may differ from its default value sets by a QML binding: - // this QML binding may then change the value during the initialization of the form. - // In this case, restore the original value. - if (isBound() && hasUserInteractiveValue() && initializedWithValue() && form() && !form()->initialized()) - boundControl()->resetBoundValue(); -} - -void JASPControl::setHasError(bool hasError) -{ - if (hasError != _hasError) - { - _hasError = hasError; - emit hasErrorChanged(); - } -} - -void JASPControl::setHasWarning(bool hasWarning) -{ - if (hasWarning != _hasWarning) - { - _hasWarning = hasWarning; - emit hasWarningChanged(); - } -} - -void JASPControl::componentComplete() -{ - QQuickItem::componentComplete(); - _setBackgroundColor(); - _setVisible(); - - connect(this, &JASPControl::initializedChanged, this, &JASPControl::_checkControlName); - - if (_useControlMouseArea) - { - QQmlComponent* comp = getMouseAreaComponent(qmlEngine(this)); - QVariantMap props = { {"hoverEnabled", shouldStealHover()}, {"cursorShape", cursorShape()} }; - - _mouseAreaObj = qobject_cast(comp->createWithInitialProperties(props, qmlContext(this))); - if (_mouseAreaObj) - { - _mouseAreaObj->setParentItem(this); - QQuickItem::connect(_mouseAreaObj, SIGNAL(hoveredChanged()), this, SLOT(_hoveredChangedSlot()) ); - } - else - Log::log() << "Cannot create a Mouse Area!!!" << std::endl; - } - - QQmlContext* context = qmlContext(this); - bool isDynamic = context->contextProperty("isDynamic").toBool(); - _form = context->contextProperty("form").value(); - - if (!_form) - { - // The control is used outside of a form, typically this is used by the Desktop application direclty - // Just call its setup function, and it is then already initialized. - setUp(); - setInitialized(); - } - else if (!isDynamic) - // For statically build controls in a form, the form self will setup the controls when the form is completely loaded - // (by calling the AnalysisForm::setAnalysisUp function). - _form->addControl(this); - else - { - // The control is created dynamically, this is the case for row components. - // They are created either from a ListView (or a TableView): when all terms of the ListView are set, the row components are created, and then initialized (via rhe ListModel::setUpRowControls function). - // Here the parent ListView and the key for this control is stored. - setUp(); - - JASPListControl* listView = nullptr; - - QVariant listViewVar = context->contextProperty("listView"); - if (!listViewVar.isNull()) - listView = listViewVar.value(); - else - { - QVariant tableViewVar = context->contextProperty("tableView"); - if (!tableViewVar.isNull()) - listView = tableViewVar.value(); - } - - if (listView && listView != this) - { - _parentListView = listView; - - if (!listViewVar.isNull()) - { - _parentListViewKey = context->contextProperty("rowValue").toString(); - connect(listView->model(), &ListModel::oneTermChanged, this, &JASPControl::parentListViewKeyChanged); - } - else - _parentListViewKey = context->contextProperty("rowIndex").toString(); - - listView->addRowControl(_parentListViewKey, this); - - emit parentListViewChanged(); - } - } - - if (_background == nullptr && _innerControl != nullptr) - { - QVariant innerControlBackround = _innerControl->property("background"); - if (!innerControlBackround.isNull()) - _background = innerControlBackround.value(); - } - - // Set the parentDebug property to children items when the item is completed (and the children are already created) - if (_debug) - setParentDebugToChildren(_debug); - - if (_form) - connect(this, &JASPControl::boundValueChanged, _form, &AnalysisForm::boundValueChangedHandler); -} - -void JASPControl::setCursorShape(int shape) -{ - _cursorShape = shape; - - if (_mouseAreaObj) - _mouseAreaObj->setProperty("cursorShape", shape); -} - -void JASPControl::addControlError(QString message) -{ - if (_form && message.size()) - _form->addControlError(this, message, false); -} - -void JASPControl::addControlErrorTemporary(QString message) -{ - if (_form && message.size()) - _form->addControlError(this, message, true); -} - -void JASPControl::addControlWarning(QString message) -{ - if (_form && message.size()) - _form->addControlError(this, message, false, true); -} - -void JASPControl::addControlWarningTemporary(QString message) -{ - if (_form && message.size()) - _form->addControlError(this, message, true, true); -} - -void JASPControl::clearControlError() -{ - if (_form) - _form->clearControlError(this); -} - -QList JASPControl::getChildJASPControls(const QQuickItem * item) -{ - QList result; - - if (!item) - return result; - - QList childItems = item->childItems(); - - for (QQuickItem* childItem : childItems) - { - JASPControl* childControl = qobject_cast(childItem); - - if (childControl) result.push_back(childControl); - else result.append(getChildJASPControls(childItem)); - } - - return result; -} - -BoundControl *JASPControl::boundControl() -{ - if (isBound()) return dynamic_cast(this); - return nullptr; -} - -bool JASPControl::addDependency(JASPControl *item) -{ - if (_depends.count(item) > 0 || this == item || !item) - return false; - - _depends.insert(item); - return true; -} - -void JASPControl::removeDependency(JASPControl *item) -{ - _depends.erase(item); -} - -QString JASPControl::friendlyName() const -{ - return ControlTypeToFriendlyString(controlType()); -} - -void JASPControl::setParentDebug(bool parentDebug) -{ - if (_parentDebug != parentDebug) - { - _parentDebug = parentDebug; - setParentDebugToChildren(_parentDebug || _debug); - emit parentDebugChanged(); - } -} - -void JASPControl::setFocusIndicator(QQuickItem *focusIndicator) -{ - if (focusIndicator != _focusIndicator) - { - if (focusIndicator) - { - QObject* border = focusIndicator->property("border").value(); - if (border) - { - _defaultBorderColor = border->property("color").value(); - _defaultBorderWidth = border->property("width").toFloat(); - } - } - - _focusIndicator = focusIndicator; - - emit focusIndicatorChanged(); - } -} - -void JASPControl::_setFocusBorder() -{ - JaspTheme* theme = JaspTheme::currentTheme(); - - if (!_focusIndicator || !theme) return; - - QColor borderColor = _defaultBorderColor; - - if (hasError()) borderColor = theme->controlErrorTextColor(); - else if (shouldShowFocus()) borderColor = theme->focusBorderColor(); - else if (hasWarning()) borderColor = theme->controlWarningTextColor(); - else if (isDependency()) borderColor = theme->dependencyBorderColor(); - - float borderWidth = (borderColor == _defaultBorderColor) ? _defaultBorderWidth : theme->jaspControlHighlightWidth(); - - QObject* border = _focusIndicator->property("border").value(); - if (border) - { - if (border->property("color").value() != borderColor) - border->setProperty("color", borderColor); - - if (!qFuzzyCompare(border->property("width").toFloat(), borderWidth)) - { - if (!_form || !_form->initialized() || qFuzzyCompare(borderWidth, _defaultBorderWidth)) - { - _borderAnimation.stop(); - border->setProperty("width", borderWidth); // No animation when coming back to normal. - } - else - { - _borderAnimation.setTargetObject(border); - _borderAnimation.setPropertyName("width"); - _borderAnimation.setDuration(800); - _borderAnimation.setEasingCurve(QEasingCurve::OutElastic); - _borderAnimation.setEndValue(borderWidth); - _borderAnimation.start(); - } - } - else - { - _borderAnimation.stop(); - border->setProperty("width", borderWidth); // just to be sure.. - } - } -} - -void JASPControl::setDebug(bool debug) -{ - if (_debug != debug) - { - _debug = debug; - setParentDebugToChildren(_parentDebug || _debug); - emit debugChanged(); - } -} - -void JASPControl::setParentDebugToChildren(bool debug) -{ - if (_childControlsArea) - for (JASPControl* childControl : getChildJASPControls(_childControlsArea)) - childControl->setParentDebug(debug); -} - -void JASPControl::focusInEvent(QFocusEvent *event) -{ - QQuickItem::focusInEvent(event); - _focusReason = event->reason(); - _hasActiveFocus = true; -} - -//Installed of innercontrol and non JASPControl children to capture focus reason -bool JASPControl::eventFilter(QObject *watched, QEvent *event) -{ - if (event->type() == QEvent::FocusIn) - { - QFocusEvent* focusEvent = static_cast(event); - _focusReason = focusEvent->reason(); - _hasActiveFocus = true; - } - #ifdef __APPLE__ - if (event->type() == QEvent::MouseButtonPress) - { - QQuickItem* item = qobject_cast(watched); - if(item) - item->forceActiveFocus(Qt::FocusReason::MouseFocusReason); - } - #endif - return false; -} - -void JASPControl::_checkControlName() -{ - checkOptionName(_name); -} - -bool JASPControl::checkOptionName(const QString &name) -{ - // Do not check the option name if the control is not yet initialized: the isBound property is maybe not yet set - // A RadioButton uses the name as value of a RadioButtonGroup option, so it's not an option self, so don't check it - // (the RadioButtonGroup will take care that the Radio Button names are consistent. - if (!form() || !initialized() || nameIsOptionValue()) return true; - - // Some controls without bound value, have a name (like Available Variables List). This name must also be checked - if (!isBound() && name.isEmpty()) return true; - - // If a control is bound, it must have a name. - if (isBound() && name.isEmpty()) - { - QString label = humanFriendlyLabel(); - - if (!label.isEmpty()) addControlError(tr("Control with label '%1' has no name").arg(label)); - else addControlError(tr("A control has no name")); - - return false; - } - - if (_optionReservedNames.contains(name)) - { - addControlError(tr("Option name '%1' is a reserved word").arg(name)); - return false; - } - - JASPControl* anotherControl = form()->getControl(name); - if (anotherControl && anotherControl != this) - { - addControlError(tr("2 controls have the same name: %1").arg(name)); - anotherControl->addControlError(tr("2 controls have the same name: %1").arg(name)); - return false; - } - - if (form()->isFormulaName(name)) - { - addControlError(tr("A control and a formula have the same name '%1'").arg(name)); - return false; - } - - return true; -} - -QString JASPControl::ControlTypeToFriendlyString(ControlType controlType) -{ - switch(controlType) - { - default: - case ControlType::DefaultControl: return tr("Option"); break; - case ControlType::Expander: return tr("Section"); break; - case ControlType::CheckBox: return tr("CheckBox"); break; - case ControlType::Switch: return tr("Switch"); break; - case ControlType::TextField: return tr("Entry Field"); break; - case ControlType::RadioButton: return tr("Radio Button"); break; - case ControlType::RadioButtonGroup: return tr("Radio Buttons"); break; - case ControlType::VariablesListView: return tr("Variables List"); break; - case ControlType::ComboBox: return tr("DropDown"); break; - case ControlType::FactorLevelList: return tr("Factor Level List"); break; - case ControlType::InputListView: return tr("Input ListView"); break; - case ControlType::TableView: return tr("TableView"); break; - case ControlType::Slider: return tr("Slider"); break; - case ControlType::TextArea: return tr("TextArea"); break; - case ControlType::Button: return tr("Button"); break; - case ControlType::FactorsForm: return tr("Factors Form"); break; - case ControlType::ComponentsList: return tr("List of Components"); break; - case ControlType::GroupBox: return tr("Group Box"); break; - case ControlType::TabView: return tr("Tab View"); break; - case ControlType::VariablesForm: return tr("Variables Form"); break; - } -} - -QString JASPControl::helpMD(SetConst & markdowned, int howDeep, bool asList) const -{ - if(!isEnabled()) - return ""; - - markdowned.insert(this); - - Log::log() << "Generating markdown for control by name '" << name() << "', title '" << title() << "' and type: '" << JASPControl::ControlTypeToFriendlyString(controlType()) << "'.\n"; - - bool shouldChildrenBeAList; - - switch(controlType()) - { - case ControlType::GroupBox: - case ControlType::ComboBox: - case ControlType::RadioButtonGroup: - case ControlType::VariablesForm: - shouldChildrenBeAList = true; - break; - - default: - shouldChildrenBeAList = false; - break; - } - - if(controlType() == ControlType::Expander) - howDeep = 1; //When within a section we can go back to bigger titles. Together with howDeep++ right below here this ends up as default 2 - - howDeep++; - QStringList markdown, childMDs; - - //First we determine if we have children, and if so if they contain anything. - QList children = getChildJASPControls(_childControlsArea ? _childControlsArea : this); - - bool aControlThatEncloses = children.size() > 0; - - Log::log() << "Control encloses #" << children.size() << " children." << std::endl; - - bool childrenList = asList || shouldChildrenBeAList || howDeep > 6; //Headers in html only got 6 sizes so below that I guess we just turn it into bulletpoints? - int newDeep = howDeep; - - if(childrenList && !asList) - newDeep = 0; - - for (JASPControl* childControl : children) - if(!markdowned.count(childControl)) - childMDs << childControl->helpMD(markdowned, newDeep, childrenList); - - QString childMD = childMDs.join(""); - - //If we have no info and none of our children have info then we shouldn't be part of the help md - if(info() == "" && (!aControlThatEncloses || childMD == "")) - return ""; - - //If on the other hand we are a simply radiobutton we can just turn it into a list entry - if(controlType() == ControlType::RadioButton && !aControlThatEncloses) - return "- *" + title() + "*: " + info() + "\n"; - - //And otherwise we go the full mile, header + title + info and all followed by whatever children we have - if(aControlThatEncloses) - markdown << "\n\n"; - - if(controlType() == ControlType::Expander) - markdown << "\n---\n"; - - if(asList) markdown << QString{howDeep, ' '} + "- "; - else markdown << QString{howDeep, '#' } + " "; // ;) - - markdown << friendlyName(); - - if(title() != "") markdown << " - *" + title() + "*:\n"; - else markdown << "\n"; - - - markdown << info() + "\n"; - - markdown << childMD; - - if(controlType() == ControlType::Expander) - markdown << "\n---\n"; - - - QString md = markdown.join("") + "\n\n"; - - Log::log() << "Generated: '" << md << "'\n"; - - return md; -} - -void JASPControl::setChildControlsArea(QQuickItem * childControlsArea) -{ - _childControlsArea = childControlsArea; - - //If there is a child control we would like to be kept informed of it - if(_childControlsArea) - connect(_childControlsArea, &QQuickItem::childrenChanged, this, &JASPControl::reconnectWithYourChildren, Qt::UniqueConnection); - - //Just in case the children are there already: - reconnectWithYourChildren(); -} - -void JASPControl::reconnectWithYourChildren() -{ - for (JASPControl* child : getChildJASPControls(_childControlsArea)) - { - //Unique so that it doesn't matter how many times we connect - connect(child, &JASPControl::helpMDChanged, this, &JASPControl::helpMDChanged, Qt::UniqueConnection); - connect(child, &JASPControl::hasErrorChanged, this, &JASPControl::hasErrorChanged, Qt::UniqueConnection); - connect(child, &JASPControl::hasWarningChanged, this, &JASPControl::hasWarningChanged, Qt::UniqueConnection); - } - - //Just in case: - emit helpMDChanged(); - emit hasErrorChanged(); - emit hasWarningChanged(); -} - -void JASPControl::parentListViewKeyChanged(const QString &oldName, const QString &newName) -{ - if (oldName == _parentListViewKey) - _parentListViewKey = newName; -} - -void JASPControl::setName(const QString &name) -{ - if (name != _name && checkOptionName(name)) - { - _name = name; - emit nameChanged(); - } -} - -bool JASPControl::hasError() const -{ - if(_controlType != ControlType::Expander) return _hasError; - else return childHasError(); -} - -bool JASPControl::hasWarning() const -{ - if(_controlType != ControlType::Expander) return _hasWarning; - else return childHasWarning(); -} - -bool JASPControl::childHasError() const -{ - for (JASPControl* child : getChildJASPControls(_childControlsArea)) - if(child->childHasError()) - return true; - - return _hasError; -} - -bool JASPControl::childHasWarning() const -{ - for (JASPControl* child : getChildJASPControls(_childControlsArea)) - if(child->childHasWarning()) - return true; - - return _hasWarning; -} - -// This method is just for the parentListView property that needs a JASPControl (JASPListControl is unknown in QML). -JASPControl *JASPControl::parentListViewEx() const -{ - return _parentListView; -} - -bool JASPControl::hovered() const -{ - if (_mouseAreaObj) - return _mouseAreaObj->property("hovered").toBool(); - else - return false; -} - -QString JASPControl::humanFriendlyLabel() const -{ - - QString label = property("label").toString(); - - if (label.isEmpty()) - label = property("title").toString(); - - if (label.isEmpty()) - label = name(); - - label = label.simplified(); - if (label.right(1) == ":") - label = label.chopped(1); - - return label; - -} - -QVector JASPControl::getParentKeys() -{ - QVector parentKeys; - JASPListControl* parentControl = parentListView(); - QString parentKeyValue = parentListViewKey(); - - while (parentControl) - { - parentKeys.prepend({parentControl->name().toStdString(), parentControl->optionKey().toStdString(), Term::readTerm(parentKeyValue).scomponents()}); - parentKeyValue = parentControl->parentListViewKey(); - parentControl = parentControl->parentListView(); - } - - return parentKeys; -} - -void JASPControl::runRScript(const QString &script, bool whiteListedVersion) -{ - QString id = parentListView() ? (parentListView()->name() + "." + parentListViewKey() + "." + name()) : name(); - - form()->runRScript(script, id, whiteListedVersion); -} - -void JASPControl::rScriptDoneHandler(const QString &) -{ - throw std::runtime_error("runRScript done but handler not implemented!\nImplement an override for RScriptDoneHandler\n"); -} - -void JASPControl::_setFocus() -{ - if (!hasActiveFocus()) - setFocus(false); -} - -void JASPControl::_notifyFormOfActiveFocus() -{ - if (!hasActiveFocus()) - _hasActiveFocus = false; - - //All JASP controls are focusscopes when they receive focus due to a child being clicked the reason is 8 for some reason (undocumented as of 3-1-2023) - //Objects like jasp groupboxes could unrightfully be marked as the active jasp control when a child jasp control gets focus - //For this reason we check if the focus reason is the result of user input or the focus scope system. - if (_form && _focusReason >= Qt::MouseFocusReason && _focusReason <= Qt::OtherFocusReason) - _form->setActiveJASPControl(this, hasActiveFocus()); -} - -void JASPControl::_addExplicitDependency(const QVariant& depends) -{ - if (!depends.isValid() || depends.isNull()) return; - - JASPControl* control = depends.value(); - if (control) - _depends.insert(control); - else if (depends.canConvert()) - _depends.insert(form()->getControl(depends.toString())); - else if (depends.canConvert()) - { - QVariantList varDeps = depends.toList(); - for (const QVariant& varDep : varDeps) - _addExplicitDependency(varDep); - } -} - -void JASPControl::addExplicitDependency() -{ - _addExplicitDependency(_explicitDepends); -} - -bool JASPControl::dependingControlsAreInitialized() -{ - bool dependenciesAreInitialized = true; - - for (JASPControl* c : _depends) - { - if (!c->initialized()) - dependenciesAreInitialized = false; - } - return dependenciesAreInitialized; -} - -void JASPControl::setInitialized(const Json::Value &value) -{ - if (dependingControlsAreInitialized()) - _setInitialized(value); - else - { - for (JASPControl* c : _depends) - if (!c->initialized()) - connect(c, &JASPControl::initializedChanged, this, [this, value]() { if (dependingControlsAreInitialized()) _setInitialized(value); }); - } -} - -void JASPControl::_setInitialized(const Json::Value &value) -{ - BoundControl* bControl = boundControl(); - if (bControl) - { - bControl->setDefaultBoundValue(bControl->createJson()); - bControl->bindTo(value == Json::nullValue ? bControl->createJson() : value); - } - - _initialized = true; - _initializedWithValue = (value != Json::nullValue); - emit initializedChanged(); -} diff --git a/QMLComponents/controls/jaspcontrol.h b/QMLComponents/controls/jaspcontrol.h deleted file mode 100644 index 53d8e3a0038..00000000000 --- a/QMLComponents/controls/jaspcontrol.h +++ /dev/null @@ -1,322 +0,0 @@ -#ifndef JASPCONTROL_H -#define JASPCONTROL_H - -#include -#include - -#include "qutils.h" -#include "columntype.h" - -class AnalysisForm; -class JASPListControl; -class BoundControl; - -/// -/// Basic class for all our qml controls -/// Contains all the properties that *must* be there for the QML components defined under Desktop/components/Controls and their bases in Desktop/widgets to function -/// Also defined here are qml-enums for use in qml and of course a whole lot of functionality. -class JASPControl : public QQuickItem -{ - Q_OBJECT - - Q_PROPERTY( ControlType controlType READ controlType WRITE setControlType NOTIFY controlTypeChanged ) - Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged ) - Q_PROPERTY( QString title READ title WRITE setTitle NOTIFY titleChanged ) //Basically whatever a human sees on their screen when they look at this specific item. - Q_PROPERTY( QString info READ info WRITE setInfo NOTIFY infoChanged ) - Q_PROPERTY( QString toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged ) - Q_PROPERTY( QString helpMD READ helpMDControl NOTIFY helpMDChanged ) - Q_PROPERTY( bool isBound READ isBound WRITE setIsBound NOTIFY isBoundChanged ) - Q_PROPERTY( bool indent READ indent WRITE setIndent NOTIFY indentChanged ) - Q_PROPERTY( bool isDependency READ isDependency WRITE setIsDependency NOTIFY isDependencyChanged ) - Q_PROPERTY( bool debug READ debug WRITE setDebug NOTIFY debugChanged ) - Q_PROPERTY( bool parentDebug READ parentDebug NOTIFY parentDebugChanged ) - Q_PROPERTY( bool focusOnTab READ focusOnTab WRITE setFocusOnTab NOTIFY focusOnTabChanged ) - Q_PROPERTY( bool hasError READ hasError WRITE setHasError NOTIFY hasErrorChanged ) - Q_PROPERTY( bool hasWarning READ hasWarning WRITE setHasWarning NOTIFY hasWarningChanged ) - Q_PROPERTY( bool initialized READ initialized NOTIFY initializedChanged ) - Q_PROPERTY( bool shouldShowFocus READ shouldShowFocus WRITE setShouldShowFocus NOTIFY shouldShowFocusChanged ) - Q_PROPERTY( bool shouldStealHover READ shouldStealHover WRITE setShouldStealHover NOTIFY shouldStealHoverChanged ) - Q_PROPERTY( QQuickItem * childControlsArea READ childControlsArea WRITE setChildControlsArea ) - Q_PROPERTY( JASPControl * parentListView READ parentListViewEx NOTIFY parentListViewChanged ) - Q_PROPERTY( QQuickItem * innerControl READ innerControl WRITE setInnerControl NOTIFY innerControlChanged ) - Q_PROPERTY( QQuickItem * background READ background WRITE setBackground NOTIFY backgroundChanged ) - Q_PROPERTY( QQuickItem * focusIndicator READ focusIndicator WRITE setFocusIndicator NOTIFY focusIndicatorChanged ) - Q_PROPERTY( QStringList dependencyMustContain READ dependencyMustContain WRITE setDependencyMustContain NOTIFY dependencyMustContainChanged ) - Q_PROPERTY( int preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged ) - Q_PROPERTY( int preferredWidth READ preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged ) - Q_PROPERTY( int cursorShape READ cursorShape WRITE setCursorShape ) - Q_PROPERTY( bool hovered READ hovered NOTIFY hoveredChanged ) - Q_PROPERTY( int alignment READ alignment WRITE setAlignment ) - Q_PROPERTY( Qt::FocusReason focusReason READ getFocusReason ) - Q_PROPERTY( QVariant depends READ explicitDepends WRITE setExplicitDepends NOTIFY explicitDependsChanged ) - -protected: - typedef std::set Set; - typedef std::set SetConst; - -public: - struct ParentKey - { - std::string name, key; - std::vector value; - ParentKey(const std::string & _name, const std::string & _key, const std::vector& _value) - : name(_name), key(_key), value(_value) {} - }; - - // Any addition here should also be added manually to ControlTypeToFriendlyString... I couldnt get this to work with DECLARE_ENUM... - enum class ControlType { - DefaultControl - , Expander - , CheckBox - , Switch - , TextField - , RadioButton - , RadioButtonGroup - , VariablesListView - , ComboBox - , FactorLevelList - , InputListView - , TableView - , Slider - , TextArea - , Button - , FactorsForm - , ComponentsList - , GroupBox - , TabView - , VariablesForm - }; - - // Be careful not to reuse a name in a enum type: in QML, they are mixed up with a 'JASP' prefix: JASP.DropNone or JASP.None - enum class Inclusive { None = 0, MinMax, MinOnly, MaxOnly }; - enum class DropMode { DropNone = static_cast(Inclusive::MaxOnly) + 1, DropInsert, DropReplace }; - enum class ListViewType { AssignedVariables = static_cast(DropMode::DropReplace) + 1, Interaction, AvailableVariables, RepeatedMeasures, Layers, AvailableInteraction }; - enum class CombinationType { NoCombination = static_cast(ListViewType::AvailableInteraction) + 1, CombinationCross, CombinationInteraction, Combination2Way, Combination3Way, Combination4Way, Combination5Way }; - enum class TextType { TextTypeDefault = static_cast(CombinationType::Combination5Way) + 1, TextTypeModel, TextTypeRcode, TextTypeJAGSmodel, TextTypeSource, TextTypeLavaan, TextTypeCSem }; - enum class ModelType { Simple = static_cast(TextType::TextTypeLavaan) + 1, GridInput, CustomContrasts, MultinomialChi2Model, JAGSDataInputModel, FilteredDataEntryModel }; - enum class ItemType { String = static_cast(ModelType::FilteredDataEntryModel) + 1, Integer, Double }; - - Q_ENUM(ControlType) - Q_ENUM(Inclusive) - Q_ENUM(DropMode) - Q_ENUM(ListViewType) - Q_ENUM(CombinationType) - Q_ENUM(TextType) - Q_ENUM(ModelType) - Q_ENUM(ItemType) - - JASPControl(QQuickItem *parent = nullptr); - ~JASPControl(); //Disconnecting signals right before destroying the object avoids some crashes with qt >= 6.3 on macos m1 - - ControlType controlType() const { return _controlType; } - const QString & name() const { return _name; } - QString title() const { return _title; } - QString info() const { return _info; } - QString toolTip() const { return _toolTip; } - QString helpMDControl() const { SetConst tmp; return helpMD(tmp); } ///< If someone want to get it from qml they can this way. - virtual QString helpMD(SetConst & markdowned, int howDeep = 2, bool asList = false) const; - bool isBound() const { return _isBound; } - bool nameIsOptionValue() const { return _nameIsOptionValue; } - bool indent() const { return _indent; } - bool isDependency() const { return _isDependency; } - bool initialized() const { return _initialized; } - bool initializedWithValue() const { return _initializedWithValue; } - bool shouldShowFocus() const { return _shouldShowFocus; } - bool shouldStealHover() const { return _shouldStealHover; } - bool debug() const { return _debug; } - bool parentDebug() const { return _parentDebug; } - bool hasError() const; - bool hasWarning() const; - bool childHasError() const; - bool childHasWarning() const; - bool focusOnTab() const { return activeFocusOnTab(); } - bool hasUserInteractiveValue() const { return _hasUserInteractiveValue; } - - AnalysisForm * form() const { return _form; } - QQuickItem * childControlsArea() const { return _childControlsArea; } - JASPListControl * parentListView() const { return _parentListView; } - JASPControl * parentListViewEx() const; - QString parentListViewKey() const { return _parentListViewKey; } - QQuickItem * innerControl() const { return _innerControl; } - QQuickItem * background() const { return _background; } - QQuickItem * focusIndicator() const { return _focusIndicator; } - QStringList dependencyMustContain() const { return _dependencyMustContain; } - int preferredHeight() const { return _preferredHeight; } - int preferredWidth() const { return _preferredWidth; } - int cursorShape() const { return _cursorShape; } - bool hovered() const; - int alignment() const { return _alignment; } - Qt::FocusReason getFocusReason() const { return _focusReason; } - bool dependsOnDynamicComponents() const { return _dependsOnDynamicComponents; } - const QVariant& explicitDepends() const { return _explicitDepends; } - - QString humanFriendlyLabel() const; - - QVector getParentKeys(); - - static QString ControlTypeToFriendlyString(ControlType controlType); - static QList getChildJASPControls(const QQuickItem* item); - - virtual void setUp() {} - void setInitialized(const Json::Value& value = Json::nullValue); - virtual void cleanUp() { disconnect(); } - virtual BoundControl * boundControl(); - virtual bool encodeValue() const { return false; } - - const Set & depends() const { return _depends; } - bool addDependency(JASPControl* item); - void removeDependency(JASPControl* item); - virtual JASPControl * getChildControl(QString key, QString name) { return nullptr; } - void runRScript(const QString& script, bool whiteListedVersion = true); - virtual void rScriptDoneHandler(const QString& result); - - virtual QString friendlyName() const; - void addExplicitDependency(); - -public slots: - void setControlType( ControlType controlType) { _controlType = controlType; } - void setChildControlsArea( QQuickItem * childControlsArea); - void setFocusOnTab( bool focus); - void setHasError( bool hasError); - void setHasWarning( bool hasWarning); - void setDebug( bool debug); - void setParentDebug( bool parentDebug); - void setFocusIndicator( QQuickItem* focusIndicator); - void setInnerControl( QQuickItem* innerControl); - void setPreferredHeight( int preferredHeight, bool isBinding = false); - void setPreferredWidth( int preferredWidth, bool isBinding = false); - void setAlignment( int alignment) { _alignment = alignment; } - - void addControlError( QString message); - void addControlErrorTemporary( QString message); - void addControlWarning( QString message); - void addControlWarningTemporary( QString message); - void clearControlError(); - - void reconnectWithYourChildren(); - void parentListViewKeyChanged(const QString& oldName, const QString& newName); - void setName(const QString& name); - - GENERIC_SET_FUNCTION(Info , _info , infoChanged , QString ) - GENERIC_SET_FUNCTION(ToolTip , _toolTip , toolTipChanged , QString ) - GENERIC_SET_FUNCTION(Title , _title , titleChanged , QString ) - GENERIC_SET_FUNCTION(IsBound , _isBound , isBoundChanged , bool ) - GENERIC_SET_FUNCTION(Indent , _indent , indentChanged , bool ) - GENERIC_SET_FUNCTION(IsDependency , _isDependency , isDependencyChanged , bool ) - GENERIC_SET_FUNCTION(ShouldShowFocus , _shouldShowFocus , shouldShowFocusChanged , bool ) - GENERIC_SET_FUNCTION(ShouldStealHover , _shouldStealHover , shouldStealHoverChanged , bool ) - GENERIC_SET_FUNCTION(Background , _background , backgroundChanged , QQuickItem* ) - GENERIC_SET_FUNCTION(DependencyMustContain , _dependencyMustContain, dependencyMustContainChanged , QStringList ) - GENERIC_SET_FUNCTION(ExplicitDepends , _explicitDepends , explicitDependsChanged , QVariant ) - -private slots: - void _setFocusBorder(); - void _setShouldShowFocus(); - void _setBackgroundColor(); - void _setVisible(); - void _hoveredChangedSlot() { emit hoveredChanged(); } - void _resetBindingValue(); - void _setFocus(); - void _notifyFormOfActiveFocus(); - void _checkControlName(); - -signals: - void setOptionBlockSignal( bool blockSignal); - void nameChanged(); - void isBoundChanged(); - void indentChanged(); - void isDependencyChanged(); - void initializedChanged(); - void shouldShowFocusChanged(); - void shouldStealHoverChanged(); - void debugChanged(); - void parentDebugChanged(); - void hasErrorChanged(); - void hasWarningChanged(); - void focusOnTabChanged(); - void parentListViewChanged(); - void innerControlChanged(); - void backgroundChanged(); - void focusIndicatorChanged(); - void infoChanged(); - void toolTipChanged(); - void titleChanged(); - void helpMDChanged(); - void dependencyMustContainChanged(); - void preferredHeightChanged(); - void preferredWidthChanged(); - void hoveredChanged(); - void controlTypeChanged(); // Not used, defined only to suppress warning in QML - void boundValueChanged(JASPControl* control); - void usedVariablesChanged(); - void explicitDependsChanged(); - - void requestColumnCreation(std::string columnName, columnType columnType); - void requestComputedColumnCreation(std::string columnName); - void requestComputedColumnDestruction(std::string columnName); - -protected: - void componentComplete() override; - void _setType(); - void setCursorShape(int shape); - void setParentDebugToChildren(bool debug); - void focusInEvent(QFocusEvent* event) override; - bool eventFilter(QObject *watched, QEvent *event) override; - bool checkOptionName(const QString& name); - void _addExplicitDependency(const QVariant& depends); - bool dependingControlsAreInitialized(); - virtual void _setInitialized(const Json::Value &value); - -protected: - Set _depends; - ControlType _controlType; - AnalysisForm* _form = nullptr; - QString _name, - _info, - _toolTip, - _title, - _parentListViewKey; - bool _isBound = true, - _indent = false, - _initialized = false, - _initializedWithValue = false, - _debug = false, - _parentDebug = false, - _hasError = false, - _hasWarning = false, - _isDependency = false, - _useControlMouseArea = true, - _shouldShowFocus = false, - _shouldStealHover = false, - _nameIsOptionValue = false, - _hasUserInteractiveValue = true, - _hasActiveFocus = false; - JASPListControl * _parentListView = nullptr; - QQuickItem * _childControlsArea = nullptr, - * _innerControl = nullptr, - * _background = nullptr, - * _focusIndicator = nullptr; - - QColor _defaultBorderColor; - float _defaultBorderWidth = 0; - QPropertyAnimation _borderAnimation; - int _preferredHeight = 0, - _preferredWidth = 0; - bool _preferredHeightBinding = true, - _preferredWidthBinding = true; - QStringList _dependencyMustContain; - QQuickItem * _mouseAreaObj = nullptr; - int _cursorShape = Qt::PointingHandCursor; - int _alignment = Qt::AlignTop | Qt::AlignLeft; - Qt::FocusReason _focusReason = Qt::FocusReason::NoFocusReason; - bool _dependsOnDynamicComponents = false; - QVariant _explicitDepends; - - static QMap _mouseAreaComponentMap; - static QByteArray _mouseAreaDef; - static QQmlComponent* getMouseAreaComponent(QQmlEngine* engine); - static const QStringList _optionReservedNames; -}; - - -#endif // JASPCONTROL_H diff --git a/QMLComponents/controls/jaspdoublevalidator.cpp b/QMLComponents/controls/jaspdoublevalidator.cpp deleted file mode 100644 index b821bf98dea..00000000000 --- a/QMLComponents/controls/jaspdoublevalidator.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "jaspdoublevalidator.h" -#include - - -QValidator::State JASPDoubleValidator::validate(QString& s, int& pos) const -{ - if (s.isEmpty() || (s.startsWith("-") && s.length() == 1 && bottom() < 0)) - { - // allow empty field or standalone minus sign - return QValidator::Intermediate; - } - - if (s.startsWith("-") && bottom() >= 0) - return QValidator::Invalid; - - // check length of decimal places - QString point = locale().decimalPoint(); - int indexPoint = s.indexOf(point); - - if (indexPoint != -1) - { - if (decimals() == 0) - return QValidator::Invalid; - int lengthDecimals = s.length() - indexPoint - 1; - if (lengthDecimals > decimals()) - return QValidator::Invalid; - } - // check range of value - bool isNumber; - double value = locale().toDouble(s, &isNumber); - if (!isNumber) - { - if (s.length() == 1 && s[0] == point) - { - isNumber = true; - value = 0; - } - else - return QValidator::Invalid; - } - - bool isMaxExclusive = _inclusive == JASPControl::Inclusive::None || _inclusive == JASPControl::Inclusive::MinOnly; - bool isMinExclusive = _inclusive == JASPControl::Inclusive::None || _inclusive == JASPControl::Inclusive::MaxOnly; - - if (value >= 0) - { - if (value > top() || (isMaxExclusive && value == top())) - return QValidator::Intermediate; - else if (value < bottom() || (isMinExclusive && value == bottom())) - return QValidator::Intermediate; - } - else - { - if (value < bottom() || (isMinExclusive && value == bottom())) - return QValidator::Intermediate; - else if (value > top() || (isMaxExclusive && value == top())) - return QValidator::Intermediate; - } - - return QValidator::Acceptable; -} - -QString JASPDoubleValidator::validationMessage(const QString& fieldName) -{ - QString message = tr("The value must be "); - bool hasValidation = false; - if (!_isInf(bottom())) - { - hasValidation = true; - if (_inclusive == JASPControl::Inclusive::MinMax || _inclusive == JASPControl::Inclusive::MinOnly) - message += tr("≥ %1").arg(bottom()); - else - message += tr("> %1").arg(bottom()); - } - - if (!_isInf(top())) - { - if (hasValidation) - message += tr(" and "); - hasValidation = true; - if (_inclusive == JASPControl::Inclusive::MinMax || _inclusive == JASPControl::Inclusive::MaxOnly) - message += tr("≤ %1").arg(top()); - else - message += tr("< %1").arg(top()); - } - - if (!hasValidation) - message = tr("No validation error"); - - return message; -} - -bool JASPDoubleValidator::_isInf(double value) -{ - static int intInfinity = 2147483647; // 2 ^ 32 - 1 - - return isinf(value) || int(value) == intInfinity || int(value) == -intInfinity; -} diff --git a/QMLComponents/controls/jaspdoublevalidator.h b/QMLComponents/controls/jaspdoublevalidator.h deleted file mode 100644 index 1d1d7ed6f7d..00000000000 --- a/QMLComponents/controls/jaspdoublevalidator.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef JASPDOUBLEVALIDATOR_H -#define JASPDOUBLEVALIDATOR_H - -#include -#include "jaspcontrol.h" -#include "log.h" - -/// -/// This is used in QML to verify whether entered numbers in `DoubleField` are correct accordin to the desired settings. -/// -class JASPDoubleValidator : public QDoubleValidator -{ - Q_OBJECT - - Q_PROPERTY(JASPControl::Inclusive inclusive READ inclusive WRITE setInclusive NOTIFY inclusiveChanged ) - -public: - JASPDoubleValidator (QObject* parent = nullptr) : QDoubleValidator(parent) {} - - QValidator::State validate(QString& s, int& pos) const override; - - Q_INVOKABLE QString validationMessage(const QString& fieldName); - - GENERIC_SET_FUNCTION(Inclusive, _inclusive, inclusiveChanged, JASPControl::Inclusive) - - JASPControl::Inclusive inclusive() { return _inclusive; } - -signals: - void inclusiveChanged(); - -protected: - JASPControl::Inclusive _inclusive = JASPControl::Inclusive::MinMax; - -private: - bool _isInf(double value); -}; - -#endif // JASPDOUBLEVALIDATOR_H diff --git a/QMLComponents/controls/jasplistcontrol.cpp b/QMLComponents/controls/jasplistcontrol.cpp deleted file mode 100644 index 528d3700759..00000000000 --- a/QMLComponents/controls/jasplistcontrol.cpp +++ /dev/null @@ -1,288 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "jasplistcontrol.h" -#include "analysisform.h" -#include "jaspcontrol.h" -#include "models/listmodel.h" -#include "models/listmodellabelvalueterms.h" -#include "models/listmodelassignedinterface.h" -#include "log.h" -#include "rowcontrols.h" -#include "sourceitem.h" -#include "jasptheme.h" -#include "utilities/desktopcommunicator.h" - -#include - - -JASPListControl::JASPListControl(QQuickItem *parent) - : JASPControl(parent) -{ - _hasUserInteractiveValue = false; -} - -void JASPListControl::setUpModel() -{ - if (model() && form()) form()->addModel(model()); - - emit modelChanged(); -} - -void JASPListControl::_setupSources() -{ - for (SourceItem* sourceItem : _sourceItems) - { - if (sourceItem->sourceListModel()) - { - JASPListControl* sourceControl = sourceItem->sourceListModel()->listView(); - disconnect(sourceControl, &JASPListControl::containsVariablesChanged, this, &JASPListControl::setContainsVariables); - disconnect(sourceControl, &JASPListControl::containsInteractionsChanged, this, &JASPListControl::setContainsInteractions); - } - delete sourceItem; - } - _sourceItems.clear(); - - _sourceItems = SourceItem::readAllSources(this); - - for (SourceItem* sourceItem : _sourceItems) - { - if (sourceItem->sourceListModel()) - { - JASPListControl* sourceControl = sourceItem->sourceListModel()->listView(); - connect(sourceControl, &JASPListControl::containsVariablesChanged, this, &JASPListControl::setContainsVariables); - connect(sourceControl, &JASPListControl::containsInteractionsChanged, this, &JASPListControl::setContainsInteractions); - } - } - - setContainsVariables(); - setContainsInteractions(); -} - -void JASPListControl::setContainsVariables() -{ - bool containsVariables = _containsVariables; - - ListModelAssignedInterface* assignedModel = qobject_cast(model()); - if (assignedModel && assignedModel->availableModel()) - containsVariables = assignedModel->availableModel()->listView()->containsVariables(); - - if (!containsVariables) - { - for (SourceItem* sourceItem : _sourceItems) - { - if (sourceItem->isAnalysisDataSet()) containsVariables = true; - else if (sourceItem->sourceListModel()) - { - if (sourceItem->sourceListModel()->listView()->containsVariables() && sourceItem->rowControlName().isEmpty() && !sourceItem->sourceFilter().contains("levels")) - containsVariables = true; - } - } - } - - if (_containsVariables != containsVariables) - { - _containsVariables = containsVariables; - emit containsVariablesChanged(); - } -} - -void JASPListControl::setContainsInteractions() -{ - bool containsInteractions = false; - - if (_termsAreInteractions) - containsInteractions = true; - - if (!containsInteractions) - { - ListModelAssignedInterface* assignedModel = qobject_cast(model()); - if (assignedModel && assignedModel->availableModel()) - containsInteractions = assignedModel->availableModel()->listView()->containsInteractions(); - } - - if (!containsInteractions) - { - for (SourceItem* sourceItem : _sourceItems) - { - if (sourceItem->sourceListModel()) - { - JASPListControl* sourceControl = sourceItem->sourceListModel()->listView(); - if (sourceControl->containsInteractions() || sourceItem->generateInteractions()) - containsInteractions = true; - } - } - } - - if (_containsInteractions != containsInteractions) - { - _containsInteractions = containsInteractions; - emit containsInteractionsChanged(); - } -} - -void JASPListControl::_termsChangedHandler() -{ - termsChangedHandler(); - - if (containsVariables() && isBound() && model()) - emit usedVariablesChanged(); -} - -void JASPListControl::setUp() -{ - if (!model()) setUpModel(); - JASPControl::setUp(); - - ListModel* listModel = model(); - if (!listModel) return; - - listModel->setRowComponent(rowComponent()); - _setupSources(); - - connect(this, &JASPListControl::sourceChanged, this, &JASPListControl::sourceChangedHandler); - connect(listModel, &ListModel::termsChanged, this, &JASPListControl::_termsChangedHandler); - connect(listModel, &ListModel::termsChanged, this, [this]() { emit countChanged(); }); - connect(listModel, &ListModel::termsChanged, this, &JASPListControl::maxTermsWidthChanged); - connect(DesktopCommunicator::singleton(), &DesktopCommunicator::uiScaleChanged, this, &JASPListControl::maxTermsWidthChanged); - connect(DesktopCommunicator::singleton(), &DesktopCommunicator::interfaceFontChanged, this, &JASPListControl::maxTermsWidthChanged); - -} - -void JASPListControl::cleanUp() -{ - try - { - ListModel* _model = model(); - - if (_model) - { - _model->disconnect(); - for (RowControls* rowControls : _model->getAllRowControls().values()) - for (JASPControl* control : rowControls->getJASPControlsMap().values()) - control->cleanUp(); - } - - for (auto source : _sourceItems) - source->disconnectModels(); - - JASPControl::cleanUp(); - } - catch (...) {} -} - -Terms JASPListControl::_getCombinedTerms(SourceItem* sourceToCombine) -{ - Terms result = sourceToCombine->getTerms(); - Terms termsToBeCombinedWith; - for (SourceItem* sourceItem : _sourceItems) - if (sourceItem != sourceToCombine) - termsToBeCombinedWith.add(sourceItem->getTerms()); - - Terms termsToCombine = sourceToCombine->getTerms(); - for (const Term& termToCombine : termsToCombine) - { - for (const Term& termToBeCombined : termsToBeCombinedWith) - { - QStringList components = termToCombine.components(); - components.append(termToBeCombined.components()); - result.add(Term(components)); - } - } - - return result; -} - -void JASPListControl::applyToAllSources(std::function applyThis) -{ - for (SourceItem* sourceItem : _sourceItems) - applyThis(sourceItem, sourceItem->combineWithOtherModels() ? _getCombinedTerms(sourceItem) : sourceItem->getTerms()); -} - -bool JASPListControl::hasNativeSource() const -{ - return _sourceItems.size() == 1 && _sourceItems[0]->isNativeModel(); -} - -bool JASPListControl::addRowControl(const QString &key, JASPControl *control) -{ - return model() ? model()->addRowControl(key, control) : false; -} - -bool JASPListControl::hasRowComponent() const -{ - return rowComponent() != nullptr; -} - -JASPControl *JASPListControl::getChildControl(QString key, QString name) -{ - return getRowControl(key, name); -} - -JASPControl *JASPListControl::getRowControl(const QString &key, const QString &name) const -{ - return model() ? model()->getRowControl(key, name) : nullptr; -} - -QString JASPListControl::getSourceType(QString name) -{ - return model() ? model()->getItemType(name) : ""; -} - -bool JASPListControl::areTypesAllowed(QStringList types) -{ - bool result = true; - - if (!_variableTypesAllowed.empty()) - for (const QString& type : types) - if (!_variableTypesAllowed.contains(columnTypeFromQString(type))) - result = false; - - return result; -} - -int JASPListControl::count() -{ - return model() ? model()->rowCount() : 0; -} - -double JASPListControl::maxTermsWidth() -{ - if (!model()) return 0; - double maxWidth = 0; - - QFontMetricsF& metrics = JaspTheme::fontMetrics(); - for (const Term& term : model()->terms()) - maxWidth = std::max(maxWidth, metrics.horizontalAdvance(term.asQString())); - - return maxWidth; -} - -std::vector JASPListControl::usedVariables() const -{ - if (containsVariables() && isBound() && model()) return model()->terms().asVector(); - else return {}; -} - -void JASPListControl::sourceChangedHandler() -{ - if (!model()) return; - - _setupSources(); - model()->sourceTermsReset(); -} diff --git a/QMLComponents/controls/jasplistcontrol.h b/QMLComponents/controls/jasplistcontrol.h deleted file mode 100644 index b8117347e78..00000000000 --- a/QMLComponents/controls/jasplistcontrol.h +++ /dev/null @@ -1,173 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef JASPLISTCONTROL_H -#define JASPLISTCONTROL_H - -#include "jaspcontrol.h" -#include "boundcontrols/boundcontrol.h" -#include "common.h" -#include -#include -#include -#include -#include -#include "models/listmodel.h" - -class Options; -class RowControls; -class Terms; -class SourceItem; - -class JASPListControl : public JASPControl -{ - Q_OBJECT - - Q_PROPERTY( ListModel* model READ model NOTIFY modelChanged ) - Q_PROPERTY( QVariant source READ source WRITE setSource NOTIFY sourceChanged ) - Q_PROPERTY( QVariant rSource READ rSource WRITE setRSource NOTIFY sourceChanged ) - Q_PROPERTY( QVariant values READ values WRITE setValues NOTIFY sourceChanged ) - Q_PROPERTY( int count READ count NOTIFY countChanged ) - Q_PROPERTY( int maxRows READ maxRows WRITE setMaxRows NOTIFY maxRowsChanged ) - Q_PROPERTY( QString optionKey READ optionKey WRITE setOptionKey ) - Q_PROPERTY( bool addEmptyValue READ addEmptyValue WRITE setAddEmptyValue NOTIFY addEmptyValueChanged ) - Q_PROPERTY( QString placeholderText READ placeholderText WRITE setPlaceHolderText NOTIFY placeHolderTextChanged ) - Q_PROPERTY( QString labelRole READ labelRole WRITE setLabelRole NOTIFY labelRoleChanged ) - Q_PROPERTY( QString valueRole READ valueRole WRITE setValueRole NOTIFY valueRoleChanged ) - Q_PROPERTY( bool containsVariables READ containsVariables NOTIFY containsVariablesChanged ) - Q_PROPERTY( bool containsInteractions READ containsInteractions NOTIFY containsInteractionsChanged ) - Q_PROPERTY( double maxTermsWidth READ maxTermsWidth NOTIFY maxTermsWidthChanged ) - Q_PROPERTY( QQmlComponent* rowComponent READ rowComponent WRITE setRowComponent NOTIFY rowComponentChanged ) - Q_PROPERTY( bool addAvailableVariablesToAssigned READ addAvailableVariablesToAssigned WRITE setAddAvailableVariablesToAssigned NOTIFY addAvailableVariablesToAssignedChanged ) - Q_PROPERTY( bool allowAnalysisOwnComputedColumns READ allowAnalysisOwnComputedColumns WRITE setAllowAnalysisOwnComputedColumns NOTIFY allowAnalysisOwnComputedColumnsChanged ) - - -public: - typedef QVector > LabelValueMap; - - JASPListControl(QQuickItem* parent); - - virtual ListModel * model() const = 0; - virtual void setUpModel(); - void setUp() override; - void cleanUp() override; - - const QSet& variableTypesAllowed() const { return _variableTypesAllowed; } - - const QVector& sourceItems() const { return _sourceItems; } - void applyToAllSources(std::function applyThis); - - bool hasSource() const { return _sourceItems.size() > 0; } - bool hasNativeSource() const; - - JASPControl * getRowControl(const QString& key, const QString& name) const; - virtual bool addRowControl(const QString& key, JASPControl* control); - bool hasRowComponent() const; - - const QString& optionKey() const { return _optionKey; } - JASPControl * getChildControl(QString key, QString name) override; - - Q_INVOKABLE QString getSourceType(QString name); - Q_INVOKABLE bool areTypesAllowed(QStringList types); - - const QVariant& source() const { return _source; } - const QVariant& values() const { return _values; } - const QVariant& rSource() const { return _rSource; } - QQmlComponent* rowComponent() const { return _rowComponent; } - int count(); - int maxRows() const { return _maxRows; } - bool addEmptyValue() const { return _addEmptyValue; } - const QString& placeholderText() const { return _placeHolderText; } - const QString& labelRole() const { return _labelRole; } - const QString& valueRole() const { return _valueRole; } - bool containsVariables() const { return _containsVariables; } - bool containsInteractions() const { return _containsInteractions; } - bool encodeValue() const override { return containsVariables() || containsInteractions(); } - bool useSourceLevels() const { return _useSourceLevels; } - void setUseSourceLevels(bool b) { _useSourceLevels = b; } - double maxTermsWidth(); - virtual stringvec usedVariables() const; - bool addAvailableVariablesToAssigned() const { return _addAvailableVariablesToAssigned; } - bool allowAnalysisOwnComputedColumns() const { return _allowAnalysisOwnComputedColumns; } - -signals: - void modelChanged(); - void sourceChanged(); - void countChanged(); - void maxRowsChanged(); - void addEmptyValueChanged(); - void placeHolderTextChanged(); - void labelRoleChanged(); - void valueRoleChanged(); - void containsVariablesChanged(); - void containsInteractionsChanged(); - void maxTermsWidthChanged(); - void rowComponentChanged(); - void addAvailableVariablesToAssignedChanged(); - void allowAnalysisOwnComputedColumnsChanged(); - -public slots: - void setContainsVariables(); - void setContainsInteractions(); - -protected slots: - virtual void termsChangedHandler(){}; // This slot must be overriden in order to update the options when the model has changed - void _termsChangedHandler(); - void sourceChangedHandler(); - - void setOptionKey(const QString& optionKey) { _optionKey = optionKey; } - - GENERIC_SET_FUNCTION(Source, _source, sourceChanged, QVariant ) - GENERIC_SET_FUNCTION(RSource, _rSource, sourceChanged, QVariant ) - GENERIC_SET_FUNCTION(Values, _values, sourceChanged, QVariant ) - GENERIC_SET_FUNCTION(AddEmptyValue, _addEmptyValue, addEmptyValueChanged, bool ) - GENERIC_SET_FUNCTION(PlaceHolderText, _placeHolderText, placeHolderTextChanged, QString ) - GENERIC_SET_FUNCTION(LabelRole, _labelRole, labelRoleChanged, QString ) - GENERIC_SET_FUNCTION(ValueRole, _valueRole, valueRoleChanged, QString ) - GENERIC_SET_FUNCTION(RowComponent, _rowComponent, rowComponentChanged, QQmlComponent* ) - GENERIC_SET_FUNCTION(MaxRows, _maxRows, maxRows, int ) - GENERIC_SET_FUNCTION(AddAvailableVariablesToAssigned, _addAvailableVariablesToAssigned, addAvailableVariablesToAssignedChanged, bool ) - GENERIC_SET_FUNCTION(AllowAnalysisOwnComputedColumns, _allowAnalysisOwnComputedColumns, allowAnalysisOwnComputedColumnsChanged, bool ) - -protected: - QVector _sourceItems; - QSet _variableTypesAllowed; - QString _optionKey = "value"; - QVariant _source; - QVariant _rSource; - QVariant _values; - bool _addEmptyValue = false, - _containsVariables = false, - _containsInteractions = false, - _termsAreInteractions = false, - _useSourceLevels = false, - _addAvailableVariablesToAssigned = false, - _allowAnalysisOwnComputedColumns = true; - - int _maxRows = -1; - QString _placeHolderText = tr(""), - _labelRole = "label", - _valueRole = "value"; - QQmlComponent * _rowComponent = nullptr; - -private: - void _setupSources(); - Terms _getCombinedTerms(SourceItem* sourceToCombine); -}; - -#endif // JASPLISTCONTROL_H diff --git a/QMLComponents/controls/lavaansyntaxhighlighter.cpp b/QMLComponents/controls/lavaansyntaxhighlighter.cpp deleted file mode 100644 index cc0424a5f16..00000000000 --- a/QMLComponents/controls/lavaansyntaxhighlighter.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "lavaansyntaxhighlighter.h" - -LavaanSyntaxHighlighter::LavaanSyntaxHighlighter(QTextDocument *parent) - : QSyntaxHighlighter(parent) -{ - - HighlightingRule rule; - - // operators - operatorFormat.setForeground(Qt::darkGreen); - QStringList operatorPatterns; - operatorPatterns << "\\=" << "\\~" << "\\<" - << "\\*" << "\\>" << "\\:" - << "\\%" << "\\|" << "\\+"; - for (const QString &pattern : operatorPatterns) { - rule.pattern = QRegularExpression(pattern); - rule.format = operatorFormat; - highlightingRules.append(rule); - } - - // variables - variableFormat.setToolTip("variable"); - rule.pattern = QRegularExpression("\\b\\w*\\b"); - rule.format = variableFormat; - highlightingRules.append(rule); - - // comments - commentFormat.setForeground(Qt::darkGray); - commentFormat.setFontItalic(true); - rule.pattern = QRegularExpression("#[^\n]*"); - rule.format = commentFormat; - highlightingRules.append(rule); -} - -void LavaanSyntaxHighlighter::highlightBlock(const QString &text) -{ - for (const HighlightingRule &rule : highlightingRules) - { - QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); - while (matchIterator.hasNext()) - { - QRegularExpressionMatch match = matchIterator.next(); - setFormat(match.capturedStart(), match.capturedLength(), rule.format); - } - } -} diff --git a/QMLComponents/controls/lavaansyntaxhighlighter.h b/QMLComponents/controls/lavaansyntaxhighlighter.h deleted file mode 100644 index badfcb1b9e8..00000000000 --- a/QMLComponents/controls/lavaansyntaxhighlighter.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LAVAANSYNTAXHIGHLIGHTER_H -#define LAVAANSYNTAXHIGHLIGHTER_H - -#include -#include -#include - -class LavaanSyntaxHighlighter : public QSyntaxHighlighter -{ -public: - LavaanSyntaxHighlighter(QTextDocument *parent); - virtual void highlightBlock(const QString &text) override; -private: - struct HighlightingRule - { - QRegularExpression pattern; - QTextCharFormat format; - }; - QVector highlightingRules; - QTextCharFormat operatorFormat; - QTextCharFormat variableFormat; - QTextCharFormat commentFormat; -}; - -#endif // LAVAANSYNTAXHIGHLIGHTER_H diff --git a/QMLComponents/controls/radiobuttonbase.cpp b/QMLComponents/controls/radiobuttonbase.cpp deleted file mode 100644 index 1c0801b6087..00000000000 --- a/QMLComponents/controls/radiobuttonbase.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "radiobuttonbase.h" -#include "radiobuttonsgroupbase.h" - -RadioButtonBase::RadioButtonBase(QQuickItem* item) - : JASPControl(item) -{ - _controlType = ControlType::RadioButton; - _isBound = false; - _nameIsOptionValue = true; - - connect(this, &QQuickItem::parentChanged, this, &RadioButtonBase::registerWithParent); - connect(this, &JASPControl::nameChanged, this, &RadioButtonBase::valueChangeHandler); -} - -JASPControl *RadioButtonBase::group() -{ - return _group; -} - -void RadioButtonBase::registerWithParent() -{ - // Warning: this slot can be called either by the Component.onCompleted of the RadioButton.qml or by a parentChanged signal - - QQuickItem* ancestor = parentItem(); - while(ancestor) - { - RadioButtonsGroupBase* group = qobject_cast(ancestor); - if(group) - { - if (_group) - { - if (_group == group) return; // Already registered - - //We are already registered somewhere so lets undo that - _group->unregisterRadioButton(this); - } - _group = group; - _group->registerRadioButton(this); - - emit groupChanged(); - return; - } - ancestor = ancestor->parentItem(); - } - - unregisterRadioButton(); -} - -void RadioButtonBase::unregisterRadioButton() -{ - if (_group && _form) //On destruction of static buttons outside of form values would change in RadioButtonGroup - { - _group->unregisterRadioButton(this); - _group = nullptr; - } -} - -void RadioButtonBase::clickHandler() -{ - if (_group) - _group->clickHandler(this); -} - -void RadioButtonBase::valueChangeHandler() -{ - if (_group) - _group->radioButtonValueChanged(this); -} diff --git a/QMLComponents/controls/radiobuttonbase.h b/QMLComponents/controls/radiobuttonbase.h deleted file mode 100644 index 016ab29add0..00000000000 --- a/QMLComponents/controls/radiobuttonbase.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef RADIOBUTTONBASE_H -#define RADIOBUTTONBASE_H - -#include "jaspcontrol.h" - -class RadioButtonsGroupBase; - -class RadioButtonBase : public JASPControl -{ - Q_OBJECT - Q_PROPERTY(JASPControl* group READ group NOTIFY groupChanged) // Cannot have a RadioButtonsGroupBase property: compilation error in the moc stuff. - -public: - RadioButtonBase(QQuickItem* parent = nullptr); - - JASPControl* group(); - -public slots: - Q_INVOKABLE void registerWithParent(); - Q_INVOKABLE void unregisterRadioButton(); - Q_INVOKABLE void clickHandler(); - -signals: - void clicked(); - void groupChanged(); - -protected slots: - void valueChangeHandler(); - -private: - RadioButtonsGroupBase* _group = nullptr; - -}; - -#endif // RADIOBUTTONBASE_H diff --git a/QMLComponents/controls/radiobuttonsgroupbase.cpp b/QMLComponents/controls/radiobuttonsgroupbase.cpp deleted file mode 100644 index 8b70fd92d35..00000000000 --- a/QMLComponents/controls/radiobuttonsgroupbase.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "radiobuttonsgroupbase.h" -#include "radiobuttonbase.h" -#include -#include -#include "log.h" - -using namespace std; - -RadioButtonsGroupBase::RadioButtonsGroupBase(QQuickItem* item) - : JASPControl(item), BoundControlBase(this) -{ - _controlType = ControlType::RadioButtonGroup; - _dependsOnDynamicComponents = true; -} - -void RadioButtonsGroupBase::setUp() -{ - JASPControl::setUp(); - // During the form initialization: - // . all the controls are first setup (mainly to set the sources, models and connections), and the dependecies between the controls can be then deduced. - // . the default values are then kept (this is used for the R Syntax to generate only options that do not have their default value) - // . by order of dependency, the controls get their value (either their default value, or the one set by a JASP file), and are set as 'initialized' - // So we need to know what is the default checked Radio Button during the setUp function. - // But for dynamicly created Radio Buttons (ie created by a ComponentsList), the Radio Buttons are created only when the ComponentsList get its value (the terms of its model). - // In this case, there is no Radio Buttons during the setup call (and no default value can be known): so we need here to set the checked button only when the RadioButtonGroup is initialzed. - _setCheckedButtonHandler(); - connect(this, &RadioButtonsGroupBase::initializedChanged, this, &RadioButtonsGroupBase::_setCheckedButtonHandler); -} - -void RadioButtonsGroupBase::_setCheckedButtonHandler() -{ - if (checkedButton()) return; - - for (auto* button : _buttons) - { - if (button->property("checked").toBool()) - _setCheckedButton(button); - } - if (!checkedButton() && _buttons.size() > 0) - _setCheckedButton(*(_buttons.begin())); - -} - -void RadioButtonsGroupBase::registerRadioButton(RadioButtonBase* button) -{ - const QString& controlName = button->name(); - if (form() && controlName.isEmpty()) - addControlError(tr("A RadioButton inside RadioButtonGroup element (name: %1) does not have any name").arg(name())); - else - { - _buttons.insert(button); - if(initialized()) - { - // Case when Radio Button is dynamically added - if (checkedButton() == nullptr || button->property("checked").toBool()) - _setCheckedButton(button); - } - emit buttonsChanged(); - } -} - -void RadioButtonsGroupBase::unregisterRadioButton(RadioButtonBase* button) -{ - _buttons.remove(button); - if (button == _selectedButton && _buttons.size() > 0) - _setCheckedButton(*_buttons.begin()); - emit buttonsChanged(); -} - -void RadioButtonsGroupBase::radioButtonValueChanged(RadioButtonBase *button) -{ - if (_selectedButton == button) - { - emit valueChanged(); - setBoundValue(fq(value())); - } -} - - -const QString RadioButtonsGroupBase::value() const -{ - return _selectedButton ? _selectedButton->name() : ""; -} - -void RadioButtonsGroupBase::bindTo(const Json::Value &jsonValue) -{ - BoundControlBase::bindTo(jsonValue); - - QString value = tq(jsonValue.asString()); - if (!value.isEmpty()) - { - for (auto* button: qAsConst(_buttons)) - { - if (button->name() == value) - { - _setCheckedButton(button); - return; - } - } - - addControlError(tr("No radio button corresponding to name %1").arg(value)); - Log::log() << "Known buttons: "; - for (auto* button : _buttons) Log::log() << button->name() << ","; - Log::log() << std::endl; - } -} - -Json::Value RadioButtonsGroupBase::createJson() const -{ - return fq(value()); -} - -bool RadioButtonsGroupBase::isJsonValid(const Json::Value &value) const -{ - return value.isString(); -} - -void RadioButtonsGroupBase::clickHandler(RadioButtonBase* button) -{ - if (!initialized()) return; - - if (button) - _setCheckedButton(button); - else - Log::log() << "Object clicked is not a RadioButton item! Name" << button->objectName().toStdString(); - emit clicked(); -} - -void RadioButtonsGroupBase::_setCheckedButton(RadioButtonBase* button) -{ - QString buttonName = button->name(); - - if (!_buttons.contains(button)) - { - Log::log() << "Set Checked button of a radio button " << buttonName << " that is not registered" << std::endl; - return; - } - - if (_selectedButton != button) - { - _selectedButton = button; // Setting the checked property will call _setCheckedButton: so set first the _selectedButton so that it does set unnecessarily the button - for (auto b : _buttons) - b->setProperty("checked", _selectedButton == b); - emit valueChanged(); - setBoundValue(fq(buttonName)); - } -} diff --git a/QMLComponents/controls/radiobuttonsgroupbase.h b/QMLComponents/controls/radiobuttonsgroupbase.h deleted file mode 100644 index 4f6a2f77a8d..00000000000 --- a/QMLComponents/controls/radiobuttonsgroupbase.h +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef RADIOBUTTONSGROUPBASE_H -#define RADIOBUTTONSGROUPBASE_H - -#include "jaspcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include - -class RadioButtonBase; - -class RadioButtonsGroupBase : public JASPControl, public BoundControlBase -{ - Q_OBJECT - - Q_PROPERTY( QString value READ value NOTIFY valueChanged ) - Q_PROPERTY( RadioButtonBase* checkedButton READ checkedButton NOTIFY valueChanged ) - Q_PROPERTY( QList buttons READ buttons NOTIFY buttonsChanged ) - -public: - RadioButtonsGroupBase(QQuickItem* parent = nullptr); - - bool isJsonValid(const Json::Value& value) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - void setUp() override; - - void registerRadioButton(RadioButtonBase* button); - void unregisterRadioButton(RadioButtonBase* button); - void radioButtonValueChanged(RadioButtonBase* button); - - void clickHandler(RadioButtonBase* button); - - const QString value() const; - -signals: - void valueChanged(); - void clicked(); - void buttonsChanged(); - -protected: - - RadioButtonBase* checkedButton() { return _selectedButton; } - QList buttons() { return _buttons.values(); } - - void _setCheckedButtonHandler(); - void _setCheckedButton(RadioButtonBase* button); - - - QSet _buttons; - RadioButtonBase* _selectedButton = nullptr; -}; - -#endif // RADIOBUTTONSGROUPBASE_H diff --git a/QMLComponents/controls/rowcontrols.cpp b/QMLComponents/controls/rowcontrols.cpp deleted file mode 100644 index 7cb069fa86c..00000000000 --- a/QMLComponents/controls/rowcontrols.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "rowcontrols.h" -#include "analysisform.h" -#include "jaspcontrol.h" -#include "jasplistcontrol.h" -#include "sourceitem.h" - -#include "log.h" - -#include - -RowControls::RowControls(ListModel* parent - , QQmlComponent* component - , const QMap& rowValues) - : QObject(parent), _parentModel(parent), _rowComponent(component), _initialValues(rowValues) -{ -} - -// Cannot do this code in the constructor: the Component create function (comp->create(context)) will call the addJASPControl method in JASPControl (or ListView), -// So this RowControls instance needs to exist already. -void RowControls::init(int row, const Term& key, bool isNew) -{ - JASPListControl* listView = _parentModel->listView(); - - QQmlContext* context = new QQmlContext(qmlContext(listView), listView); - context->setContextProperty("isDynamic", true); - context->setContextProperty("form", listView->form()); - context->setContextProperty("listView", listView); - context->setContextProperty("isNew", isNew); - context->setContextProperty("rowIndex", row); - context->setContextProperty("rowValue", key.asQString()); - - _rowObject = qobject_cast(_rowComponent->create(context)); // The _rowJASPControlMap will be filled during this step - _rowObject->setParent(_parentModel); - _context = context; - - if (_rowObject) _initializeControls(); - else Log::log() << "Could not create control in ListView " << listView->name() << std::endl; -} - -void RowControls::_initializeControls(bool useInitialValue) -{ - // The controls (when created or reused) need to be initialized - QList controls = _rowJASPControlMap.values(); - AnalysisForm* form = _parentModel->listView()->form(); - - if (form) - { - form->sortControls(controls); - form->blockValueChangeSignal(true); - } - - for (JASPControl* control : controls) - { - JASPListControl* listView = dynamic_cast(control); - if (listView) - for (SourceItem* source : listView->sourceItems()) - source->connectModels(); // If the source was disconnected, reconnect it. - - Json::Value optionValue = Json::nullValue; - BoundControl* boundItem = control->boundControl(); - if (boundItem && _initialValues.contains(control->name())) - { - // When a control is created before its parent, it has no value yet. - // In this case use its initial value. - if (useInitialValue || boundItem->boundValue().isNull()) - optionValue = _initialValues[control->name()]; - } - - control->setInitialized(optionValue); - } - - if (form) - form->blockValueChangeSignal(false); -} - -void RowControls::setContext(int row, const QString &key) -{ - // Cannot use qmlContext(item) : setContextProperty would generate: 'Cannot set property on internal context.' error - _context->setContextProperty("rowIndex", row); - _context->setContextProperty("rowValue", key); - _context->setContextProperty("isNew", false); - - _initializeControls(false); -} - -bool RowControls::addJASPControl(JASPControl *control) -{ - bool success = false; - JASPListControl* listView = _parentModel->listView(); - - if (control->isBound() && control->name().isEmpty()) - listView->addControlError(tr("A row component in %1 does not have a name").arg(listView->name())); - else if (_rowJASPControlMap.contains(control->name())) - listView->addControlError(tr("2 row components in %1 have the same name").arg(listView->name()).arg(control->name())); - else - success = true; - - if (!control->name().isEmpty() && success) - _rowJASPControlMap[control->name()] = control; - - return success; -} - -void RowControls::disconnectControls() -{ - // If a control depends on a source, disconnect this source with this control. - JASPListControl* parentControl = _parentModel->listView(); - for (JASPControl* control : _rowJASPControlMap.values()) - { - JASPListControl* listControl = qobject_cast(control); - if (listControl) - for (SourceItem* source : listControl->sourceItems()) - source->disconnectModels(); - } -} diff --git a/QMLComponents/controls/rowcontrols.h b/QMLComponents/controls/rowcontrols.h deleted file mode 100644 index 91f7845c53f..00000000000 --- a/QMLComponents/controls/rowcontrols.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef ROWCOMPONENTS_H -#define ROWCOMPONENTS_H - -#include "common.h" -#include -#include -#include - -class JASPListControl; -class ListModel; -class JASPControl; -class Option; -class Term; - -class RowControls : public QObject -{ -Q_OBJECT - -public: - - RowControls( - ListModel* parent - , QQmlComponent* components - , const QMap& rowValues); - - void init(int row, const Term& key, bool isNew); - void setContext(int row, const QString& key); - QQmlComponent* getComponent() const { return _rowComponent; } - QQuickItem* getRowObject() const { return _rowObject; } - const QMap& getJASPControlsMap() const { return _rowJASPControlMap; } - JASPControl* getJASPControl(const QString& name) { return _rowJASPControlMap.contains(name) ? _rowJASPControlMap[name] : nullptr; } - bool addJASPControl(JASPControl* control); - void disconnectControls(); - -private: - - void _initializeControls(bool useInitialValue = true); - - ListModel* _parentModel; - QQmlComponent* _rowComponent = nullptr; - QQuickItem* _rowObject = nullptr; - QMap _rowJASPControlMap; - QQmlContext* _context; - QMap _initialValues; -}; - -#endif // ROWCOMPONENTS_H diff --git a/QMLComponents/controls/sliderbase.cpp b/QMLComponents/controls/sliderbase.cpp deleted file mode 100644 index 4b19421d5b0..00000000000 --- a/QMLComponents/controls/sliderbase.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "sliderbase.h" -#include "analysisform.h" -#include -#include -#include "log.h" - -SliderBase::SliderBase(QQuickItem* parent) - : JASPControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::Slider; -} - -bool SliderBase::isJsonValid(const Json::Value &value) const -{ - return value.isNumeric(); -} - -Json::Value SliderBase::createJson() const -{ - return property("value").toDouble(); -} - -void SliderBase::bindTo(const Json::Value &value) -{ - BoundControlBase::bindTo(value); - setProperty("value", value.asDouble()); -} - -void SliderBase::setUp() -{ - JASPControl::setUp(); - connect(this, &SliderBase::moved, this, &SliderBase::movedSlot); -} - -void SliderBase::movedSlot() -{ - if (_changing) - return; - _changing = true; - QTimer::singleShot(300, this, SLOT(_movedDelayedSlot())); -} - -void SliderBase::_movedDelayedSlot() -{ - setBoundValue(property("value").toDouble()); - _changing = false; -} diff --git a/QMLComponents/controls/sliderbase.h b/QMLComponents/controls/sliderbase.h deleted file mode 100644 index 9318439d4e9..00000000000 --- a/QMLComponents/controls/sliderbase.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef SLIDERBASE_H -#define SLIDERBASE_H - -#include "jaspcontrol.h" -#include "boundcontrols/boundcontrolbase.h" - -class SliderBase : public JASPControl, public BoundControlBase -{ - Q_OBJECT - -public: - SliderBase(QQuickItem* parent = nullptr); - - Json::Value createJson() const override; - bool isJsonValid(const Json::Value& optionValue) const override; - void bindTo(const Json::Value& value) override; - void setUp() override; - -signals: - void moved(); - -protected slots: - void movedSlot(); - void _movedDelayedSlot(); - -protected: - bool _changing = false; -}; - -#endif // SLIDERBASE_H diff --git a/QMLComponents/controls/sourceitem.cpp b/QMLComponents/controls/sourceitem.cpp deleted file mode 100644 index da849babca4..00000000000 --- a/QMLComponents/controls/sourceitem.cpp +++ /dev/null @@ -1,680 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "sourceitem.h" - -#include "analysisform.h" -#include "jasplistcontrol.h" -#include "models/listmodellabelvalueterms.h" -#include "log.h" -#include "rowcontrols.h" -#include - -SourceItem::SourceItem( - JASPListControl* targetListControl - , QMap& map - , const JASPListControl::LabelValueMap& values - , const QVector rSources - , QAbstractItemModel* nativeModel - , const QVector& discardSources - , const QVector >& conditionVariables - ) - : QObject(targetListControl), _targetListControl(targetListControl) -{ - QString modelUse = map["use"].toString().trimmed(); - - _sourceName = map["name"].toString(); - _rowControlName = map["controlName"].toString(); - _sourceFilter = !modelUse.isEmpty() ? modelUse.split(",") : QStringList(); - _conditionExpression = map["condition"].toString(); - _values = values; - _sourceNativeModel = nativeModel; - _discardSources = discardSources; - _rSources = rSources; - - _isValuesSource = map.contains("isValuesSource") ? map["isValuesSource"].toBool() : false; - _isDataSetVariables = map.contains("isDataSetVariables") ? map["isDataSetVariables"].toBool() : false; - _combineWithOtherModels = map.contains("combineWithOtherModels") ? map["combineWithOtherModels"].toBool() : false; - _nativeModelRole = map.contains("nativeModelRole") ? map["nativeModelRole"].toInt() : Qt::DisplayRole; - _combineTerms = map.contains("combineTerms") ? JASPControl::CombinationType(map["combineTerms"].toInt()) : JASPControl::CombinationType::NoCombination; - if (isInfoProviderModel(_sourceNativeModel)) _isDataSetVariables = true; - if (_sourceFilter.contains("levels")) _targetListControl->setUseSourceLevels(true); - if (_targetListControl->useSourceLevels() && !_sourceFilter.contains("levels")) _sourceFilter.append("levels"); - - for (const QMap& conditionVariable : conditionVariables) - { - _conditionVariables.push_back(ConditionVariable(conditionVariable["name"].toString() - , conditionVariable["component"].toString() - , conditionVariable["property"].toString() - , conditionVariable["addQuotes"].toBool()) - ); - } - - _setUp(); -} - -SourceItem::SourceItem(JASPListControl *listControl, const JASPListControl::LabelValueMap &values) - : QObject(listControl), _targetListControl(listControl), _values(values), _isValuesSource(true) -{ - _setUp(); -} - -SourceItem::SourceItem(JASPListControl *listControl, const QString& rSourceName, const QString& modelUse) - : QObject(listControl), _targetListControl(listControl), _sourceName(rSourceName), _isRSource(true) -{ - if (!modelUse.isEmpty()) _sourceFilter = modelUse.split("."); - - _setUp(); -} - -SourceItem::SourceItem(JASPListControl *listControl) - : QObject(listControl), _targetListControl(listControl), _isDataSetVariables(true) -{ - _setUp(); -} - -void SourceItem::connectModels() -{ - if (!_targetListControl->initialized() || _connected) return; - - ListModel *controlModel = _targetListControl->model(); - AnalysisForm* form = _targetListControl->form(); - - if (_isRSource && form) - connect(form, &AnalysisForm::rSourceChanged, this, &SourceItem::_rSourceChanged); - - if (_sourceNativeModel) - { - connect(_sourceNativeModel, &QAbstractItemModel::dataChanged, this, &SourceItem::_dataChangedHandler); - connect(_sourceNativeModel, &QAbstractItemModel::rowsInserted, this, &SourceItem::_resetModel); - connect(_sourceNativeModel, &QAbstractItemModel::rowsRemoved, this, &SourceItem::_resetModel); - connect(_sourceNativeModel, &QAbstractItemModel::rowsMoved, this, &SourceItem::_resetModel); - connect(_sourceNativeModel, &QAbstractItemModel::modelReset, this, &SourceItem::_resetModel); - } - if (_targetListControl->useSourceLevels() && _sourceNativeModel != infoProviderModel()) - { - QAbstractItemModel* providerModel = infoProviderModel(); // When the levels/labels of the source is used, then any change of the provider model must also be signalled - connect(providerModel, &QAbstractItemModel::rowsInserted, this, &SourceItem::_resetModel); - connect(providerModel, &QAbstractItemModel::rowsRemoved, this, &SourceItem::_resetModel); - connect(providerModel, &QAbstractItemModel::rowsMoved, this, &SourceItem::_resetModel); - connect(providerModel, &QAbstractItemModel::modelReset, this, &SourceItem::_resetModel); - } - - if (_isDataSetVariables) - { - VariableInfo* variableInfo = VariableInfo::info(); - connect(variableInfo, &VariableInfo::namesChanged, controlModel, &ListModel::sourceNamesChanged ); - connect(variableInfo, &VariableInfo::columnTypeChanged, controlModel, &ListModel::sourceColumnTypeChanged ); - connect(variableInfo, &VariableInfo::labelsChanged, controlModel, &ListModel::sourceLabelsChanged ); - connect(variableInfo, &VariableInfo::labelsReordered, controlModel, &ListModel::sourceLabelsReordered ); - connect(variableInfo, &VariableInfo::columnsChanged, controlModel, &ListModel::sourceColumnsChanged ); - } - - if (_sourceListModel) - { - connect(_sourceListModel, &ListModel::namesChanged, controlModel, &ListModel::sourceNamesChanged); - connect(_sourceListModel, &ListModel::columnTypeChanged, controlModel, &ListModel::sourceColumnTypeChanged); - connect(_sourceListModel, &ListModel::labelsChanged, controlModel, &ListModel::sourceLabelsChanged ); - connect(_sourceListModel, &ListModel::labelsReordered, controlModel, &ListModel::sourceLabelsReordered ); - connect(_sourceListModel, &ListModel::columnsChanged, controlModel, &ListModel::sourceColumnsChanged ); - } - - _connected = true; -} - -void SourceItem::disconnectModels() -{ - if (!_connected) return; - - ListModel *controlModel = _targetListControl->model(); - AnalysisForm* form = _targetListControl->form(); - - if (_isRSource && form) - disconnect(form, &AnalysisForm::rSourceChanged, this, &SourceItem::_rSourceChanged); - - if (_sourceNativeModel) - _sourceNativeModel->disconnect(this); - - if (_isDataSetVariables) - infoProviderModel()->disconnect(controlModel); - - if (_sourceListModel) - _sourceListModel->disconnect(controlModel); - - _connected = false; -} - - -void SourceItem::_resetModel() -{ - if (!_isDataSetVariables || !requestInfo(VariableInfo::SignalsBlocked).toBool()) - _targetListControl->model()->sourceTermsReset(); -} - -void SourceItem::_dataChangedHandler(const QModelIndex &, const QModelIndex &, const QVector &roles) -{ - // If the dataChanged is due to a selection, don't reset the model: it is just that the QML item should get the right color. - if (roles.size() == 1 && roles.contains(ListModel::SelectedRole)) return; - - _resetModel(); -} - -void SourceItem::_rSourceChanged(const QString& name) -{ - if (_isRSource && name == _sourceName) - _targetListControl->model()->sourceTermsReset(); -} - -void SourceItem::_setUp() -{ - if (_isValuesSource) _sourceNativeModel = new ListModelLabelValueTerms(_targetListControl, _values); - else if (_targetListControl->form() && !_sourceName.isEmpty()) _sourceNativeModel = _targetListControl->form()->getModel(_sourceName); - else if (_isDataSetVariables) - { - _sourceNativeModel = infoProviderModel(); - _nativeModelRole = requestInfo(VariableInfo::NameRole).toInt(); - } - - if (_sourceNativeModel || _isRSource) - { - _sourceListModel = qobject_cast(_sourceNativeModel); - if (_sourceListModel) _targetListControl->addDependency(_sourceListModel->listView()); - - // Do not connect before this control (and the controls of the source) are completely initialized - // The source could sent some data to this control before it is completely ready for it. - if (_targetListControl->initialized()) connectModels(); - else connect(_targetListControl, &JASPControl::initializedChanged, this, &SourceItem::connectModels); - } - else if (_rSources.length() == 0) - { - if (_sourceName.isEmpty()) - { - if (_targetListControl->form()) _targetListControl->addControlError(QObject::tr("No name given for the source of %1").arg(_targetListControl->name())); - else _targetListControl->addControlError(QObject::tr("No source given for %1").arg(_targetListControl->name())); - } - else _targetListControl->addControlError(QObject::tr("Cannot find component %1 for the source of %2").arg(_sourceName).arg(_targetListControl->name())); - } -} - -QList SourceItem::getListVariant(QVariant var) -{ - QList listVar; - - if (!var.isValid() || var.isNull()) - return listVar; - - if(var.typeId() == QMetaType::QString) listVar = QList({var}); - else listVar = var.toList(); - - if (listVar.isEmpty()) - { - QStringList stringSources = var.toStringList(); - for (const QString& stringSource : stringSources) - listVar.push_back(stringSource); - } - - if (listVar.isEmpty()) - { - if (var.canConvert >()) - { - QMap map = var.toMap(); - listVar.push_back(map); - } - } - - if (listVar.isEmpty()) - listVar.push_back(var); - - return listVar; -} - -QString SourceItem::_readSourceName(const QString& sourceNameExt, QString& sourceControl, QString& sourceUse) -{ - QStringList nameSplit = sourceNameExt.split("."); - if (nameSplit.length() > 1) - { - sourceControl = nameSplit[1]; - sourceUse = "control=" + nameSplit[1]; - } - - return nameSplit[0]; -} - -QString SourceItem::_readRSourceName(const QString& sourceNameExt, QString& sourceUse) -{ - QStringList nameSplit = sourceNameExt.split("."); - QString name = nameSplit[0]; - if (nameSplit.length() > 1) - { - nameSplit.removeAt(0); - sourceUse = nameSplit.join("."); - } - - return name; -} - - -QMap SourceItem::_readSource(JASPListControl* listControl, const QVariant& source, JASPListControl::LabelValueMap& sourceValues, QVector& rSources, QAbstractItemModel*& nativeModel) -{ - QMap map; - QString sourceName, sourceControl, sourceUse; - - JASPControl* sourceItem = source.value(); - if (sourceItem) sourceName = sourceItem->name(); - else if (source.typeId() == QMetaType::QString) sourceName = _readSourceName(source.toString(), sourceControl, sourceUse); - else if (source.canConvert >()) - { - map = source.toMap(); - if (map.contains("id")) - { - JASPControl* sourceItem2 = map["id"].value(); - if (sourceItem2) sourceName = sourceItem2->name(); - } - - if (map.contains("name")) - sourceName = _readSourceName(map["name"].toString(), sourceControl, sourceUse); - - if (map.contains("use")) - { - if (!sourceUse.isEmpty()) - sourceUse += ","; - sourceUse += map["use"].toString(); - } - - if (map.contains("values")) - { - sourceValues = _readValues(listControl, map["values"]); - map["isValuesSource"] = true; - } - - if (map.contains("rSource")) - { - QList rawRSources = getListVariant(map["rSource"]); - for (const QVariant& rawSource : rawRSources) - rSources.append(_readRSource(listControl, rawSource)); - } - - if (map.contains("model")) - nativeModel = map["model"].value(); - } - else - nativeModel = source.value(); - - - if (nativeModel) - { - QString roleName = sourceUse.isEmpty() ? listControl->labelRole() : sourceUse; - map["nativeModelRole"] = Qt::DisplayRole; - - if (!roleName.isEmpty()) - { - QHashIterator it(nativeModel->roleNames()); - - while (it.hasNext()) - { - it.next(); - if (it.value() == roleName) - { - map["nativeModelRole"] = it.key(); - break; - } - } - } - } - map["name"] = sourceName; - map["controlName"] = sourceControl; - map["use"] = sourceUse; - return map; -} - -JASPListControl::LabelValueMap SourceItem::_readValues(JASPListControl* listControl, const QVariant& values) -{ - JASPListControl::LabelValueMap result; - - bool isInteger = false; - int count = values.toInt(&isInteger); - - if (isInteger) - { - for (int i = 1; i <= count; i++) - { - QString number = QString::number(i); - result.push_back(std::make_pair(number, number)); - } - } - else - { - QList list = values.toList(); - if (!list.isEmpty()) - { - for (const QVariant& itemVariant : list) - { - //It is called labelValuePair but it might in fact also contain "info" - QMap labelValuePair = itemVariant.toMap(); - if (labelValuePair.isEmpty()) - { - QString value = itemVariant.toString(); - result.push_back(std::make_pair(value, value)); - } - else - { - QString label = labelValuePair[listControl->labelRole()].toString(); - QString value = labelValuePair[listControl->valueRole()].toString(); - result.push_back(std::make_pair(label, value)); - } - } - } - } - - return result; -} - -SourceItem* SourceItem::_readRSource(JASPListControl* listControl, const QVariant& rSource) -{ - QString sourceName, sourceUse; - QMap map; - - if (rSource.typeId() == QMetaType::QString) sourceName = _readRSourceName(rSource.toString(), sourceUse); - else if (rSource.canConvert >()) - { - map = rSource.toMap(); - if (map.contains("name")) - sourceName = _readRSourceName(map["name"].toString(), sourceUse); - - if (map.contains("use")) - { - if (!sourceUse.isEmpty()) - sourceUse += "."; - sourceUse += map["use"].toString().trimmed(); - } - } - - return new SourceItem(listControl, sourceName, sourceUse); -} - -QVector SourceItem::readAllSources(JASPListControl* listControl) -{ - QVector sources; - - if (listControl->values().isValid() && !listControl->values().isNull()) - sources.append(new SourceItem(listControl, _readValues(listControl, listControl->values()))); - - if (listControl->rSource().isValid() && !listControl->rSource().isNull()) - { - QList rSources = getListVariant(listControl->rSource()); - for (const QVariant& rSource : rSources) - sources.append(_readRSource(listControl, rSource)); - } - - QList rawSources = getListVariant(listControl->source()); - - for (const QVariant& rawSource : rawSources) - { - JASPListControl::LabelValueMap sourceValues; - QVector rSources; - QAbstractItemModel* nativeModel = nullptr; - QMap map = _readSource(listControl, rawSource, sourceValues, rSources, nativeModel); - QVector discards; - QVector > conditionVariables; - - if (map.contains("discard") || map.contains("discardSource")) - { - QList discardSources = map.contains("discard") ? getListVariant(map["discard"]) : getListVariant(map["discardSource"]); - - for (const QVariant& discardSource : discardSources) - { - JASPListControl::LabelValueMap discardValues; - QVector discardRSources; - QAbstractItemModel* discardNativeModel = nullptr; - QMap discardMap = _readSource(listControl, discardSource, discardValues, discardRSources, discardNativeModel); - - discards.push_back(new SourceItem(listControl, discardMap, discardValues, discardRSources, discardNativeModel)); - } - } - - if (map.contains("conditionVariables")) - { - QList conditionVariablesList = getListVariant(map["conditionVariables"]); - for (const QVariant& conditionVariablesVar : conditionVariablesList) - if (conditionVariablesVar.canConvert >()) - conditionVariables.push_back(conditionVariablesVar.toMap()); - } - - sources.append(new SourceItem(listControl, map, sourceValues, rSources, nativeModel, discards, conditionVariables)); - } - - if (sources.isEmpty() && listControl->model()->needsSource()) - sources.append(new SourceItem(listControl)); // Add all columns source - - return sources; -} - -Terms SourceItem::_readAllTerms() -{ - Terms terms; - - if (_isRSource) - terms = _targetListControl->form()->getValuesFromRSource(_sourceName, _sourceFilter); - else if (_rSources.length() > 0) - { - for (SourceItem* rSource : _rSources) - terms.add(rSource->getTerms()); - } - else if (_sourceListModel) - { - terms = _sourceListModel->termsEx(_sourceFilter); - if (_targetListControl->useSourceLevels()) - _targetListControl->model()->setColumnsUsedForLabels(_sourceListModel->terms().asQList()); - } - else if (_isDataSetVariables) - terms = requestInfo(VariableInfo::VariableNames).toStringList(); - else if (_sourceNativeModel) - { - int nbRows = _sourceNativeModel->rowCount(); - int nbCols = _sourceNativeModel->columnCount(); - for (int i = 0; i < nbRows; i++) - { - QStringList row; - for (int j = 0; j < nbCols; j++) - row.append(_sourceNativeModel->data(_sourceNativeModel->index(i, j), _nativeModelRole).toString()); - terms.add(Term(row), false); - } - if (!_sourceFilter.empty()) - // If the 'use' parameter of the source property asks for the levels, or to filter some types - // of the variables of this 'native' model (probably the columnsModel), - // then just use the filterTerms method of the model object of the current control. - terms = _targetListControl->model()->filterTerms(terms, _sourceFilter); - } - - if (_combineTerms != JASPControl::CombinationType::NoCombination) - terms = terms.combineTerms(_combineTerms); - - if (_onlyTermsWithXComponents > 0) - { - Terms termsWithOnlyXComponents; - for (const Term & term : terms) - if (term.size() == _onlyTermsWithXComponents) - termsWithOnlyXComponents.add(term); - - terms = termsWithOnlyXComponents; - } - - return terms; -} - -Terms SourceItem::filterTermsWithCondition(ListModel* model, const Terms& terms, const QString& condition, const QVector& conditionVariables, const QMap& termsMap) -{ - Terms filteredTerms; - JASPListControl* listControl = model->listView(); - QJSEngine* jsEngine = qmlEngine(listControl); - - for (const Term& term : terms) - { - QString value = term.asQString(); - // There might be several original values: see jaspTestModule, "Test Sources with special attributes" analysis, "Source with controls" section - QStringList originalValues = termsMap.contains(value) ? termsMap[value] : QStringList{value}; - - if (conditionVariables.length() > 0) - { - // If condition variables are used, use them - for (const ConditionVariable& conditionVariable : conditionVariables) - { - QJSValue value; - for (const QString& originalValue : originalValues) - { - JASPControl* control = model->getRowControl(originalValue, conditionVariable.controlName); - if (control) - { - QVariant valueVar = control->property(conditionVariable.propertyName.toStdString().c_str()); - - switch (valueVar.typeId()) - { - case QMetaType::Int: - case QMetaType::UInt: value = valueVar.toInt(); break; - case QMetaType::Double: value = valueVar.toDouble(); break; - // If at least one of the control is true, then the condition should be true. We can think of adding an extra attribute in the source property to be able to change this rule, - // but yeah, I cannot come up already with an understandable attribute name for the user, so it means that this situation is really really peculiar. - // Again, to understand the situation, look at the jaspTestModule, "Test Sources with special attributes" analysis, "Source with controls" section - case QMetaType::Bool: value = (value.isBool() ? value.toBool() : false) || valueVar.toBool(); break; - default: value = valueVar.toString(); break; - } - - } - } - jsEngine->globalObject().setProperty(conditionVariable.name, value); - } - } - else - { - // If no condition variables are used, then set the values of the row controls in variables - QMap conditionValues; - - for (const QString& originalValue : originalValues) - { - RowControls* rowControls = model->getRowControls(originalValue); - if (!rowControls) - continue; - - for (const QString& variable : rowControls->getJASPControlsMap().keys()) - { - JASPControl * control = rowControls->getJASPControl(variable); - BoundControl* boundControl = control ? control->boundControl() : nullptr; - - if (boundControl) - { - QJSValue value; - bool addValue = true; - const Json::Value & jsonValue = boundControl->boundValue(); - - switch (jsonValue.type()) - { - case Json::booleanValue: value = jsonValue.asBool(); break; - case Json::uintValue: value = jsonValue.asUInt(); break; - case Json::intValue: value = jsonValue.asInt(); break; - case Json::realValue: value = jsonValue.asDouble(); break; - case Json::stringValue: value = tq(jsonValue.asString()); break; - default: addValue = false; break; - } - - if (addValue) - { - // Same remark as above, when condition variables are used - if (value.isBool() && conditionValues.contains(variable) && conditionValues[variable].isBool()) - value = value.toBool() || conditionValues[variable].toBool(); - conditionValues[variable] = value; - } - } - } - - for (const QString& variable : conditionValues.keys()) - jsEngine->globalObject().setProperty(variable, conditionValues[variable]); - } - } - - QJSValue result = jsEngine->evaluate(condition); - - if (result.isError()) - listControl->addControlError("Error when evaluating : " + condition + ": " + result.toString()); - - else if (result.toBool()) - filteredTerms.add(term); - } - - return filteredTerms; -} - -Terms SourceItem::getTerms() -{ - Terms sourceTerms = _readAllTerms(); - - for (SourceItem* discardModel : _discardSources) - sourceTerms.discardWhatDoesContainTheseComponents(discardModel->_readAllTerms()); - - if (!_conditionExpression.isEmpty() && _sourceListModel) - { - QMap map; - if (!_rowControlName.isEmpty()) //The sourceTerms are the values of this control, but to filter we need the values of the source - { - QStringList controlValues = sourceTerms.asQList(); - for (const QString& sourceValue : _sourceListModel->terms().asQList()) - { - JASPControl* control = _sourceListModel->getRowControl(sourceValue, _rowControlName); - if (control) - { - QString controlValue = control->property("value").toString(); - if (controlValues.contains(controlValue)) - { - QStringList list = map[controlValue]; - list.push_back(sourceValue); - map[controlValue] = list; - } - } - } - } - - sourceTerms = filterTermsWithCondition(_sourceListModel, sourceTerms, _conditionExpression, _conditionVariables, map); - } - - return sourceTerms; -} - -QSet SourceItem::usedControls() const -{ - QSet result; - - if (!_rowControlName.isEmpty()) - result.insert(_rowControlName); - - if (_conditionVariables.length() > 0) - { - for (const ConditionVariable& conditionVariable : _conditionVariables) - if (!conditionVariable.controlName.isEmpty()) - result.insert(conditionVariable.controlName); - } - else if (!_conditionExpression.isEmpty() && _sourceListModel->getAllRowControls().size() > 0) - { - // Take the controls of the first row, and check whether the expression contains their names. - RowControls * rowControls = _sourceListModel->getAllRowControls().begin().value(); - - for (const QString & controlName : rowControls->getJASPControlsMap().keys()) - if (_conditionExpression.contains(controlName)) - result.insert(controlName); - } - - return result; -} diff --git a/QMLComponents/controls/sourceitem.h b/QMLComponents/controls/sourceitem.h deleted file mode 100644 index f28fc22419c..00000000000 --- a/QMLComponents/controls/sourceitem.h +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef SOURCEITEM_H -#define SOURCEITEM_H - -#include -#include -#include -#include -#include -#include - -#include "jasplistcontrol.h" -#include "variableinfo.h" - -class SourceItem : public QObject, public VariableInfoConsumer -{ - Q_OBJECT -public: - - struct ConditionVariable - { - QString name, - controlName, - propertyName; - bool addQuotes = false; - ConditionVariable(const QString& _name, const QString& _controlName, const QString& _propertyName, bool _addQuotes = false) - : name(_name), controlName(_controlName), propertyName(_propertyName), addQuotes(_addQuotes) {} - ConditionVariable(const ConditionVariable& source) - : name(source.name), controlName(source.controlName), propertyName(source.propertyName), addQuotes(source.addQuotes) {} - ConditionVariable() {} - }; - - SourceItem( - JASPListControl* targetListControl - , QMap& map - , const JASPListControl::LabelValueMap& values - , const QVector rSources - , QAbstractItemModel* nativeModel = nullptr - , const QVector& discardSources = QVector() - , const QVector >& conditionVariables = QVector >() - ); - - SourceItem(JASPListControl* _listControl, const JASPListControl::LabelValueMap& _values); - - SourceItem(JASPListControl* _listControl, const QString& sourceName, const QString& sourceUse); - - SourceItem(JASPListControl* _listControl = nullptr); - - ListModel* sourceListModel() { return _sourceListModel; } - const QString& rowControlName() const { return _rowControlName; } - const QStringList& sourceFilter() const { return _sourceFilter; } - bool combineWithOtherModels() const { return _combineWithOtherModels; } - bool generateInteractions() const { return _combineWithOtherModels || (_combineTerms != JASPControl::CombinationType::NoCombination); } - bool isAnalysisDataSet() const { return _isDataSetVariables; } - bool isNativeModel() const { return _sourceNativeModel != nullptr; } - QAbstractItemModel* nativeModel() { return _sourceNativeModel; } - Terms getTerms(); - QSet usedControls() const; - - - void connectModels(); - void disconnectModels(); - static QVector readAllSources(JASPListControl* _listControl); - static QList getListVariant(QVariant var); - static Terms filterTermsWithCondition(ListModel* model, const Terms& terms, const QString& condition, const QVector& conditionVariables = {}, const QMap &termsMap = {}); - - -private: - static QString _readSourceName(const QString& sourceNameExt, QString& sourceControl, QString& sourceUse); - static QString _readRSourceName(const QString& sourceNameExt, QString& sourceUse); - static QMap _readSource(JASPListControl* _listControl, const QVariant& source, JASPListControl::LabelValueMap& sourceValues, QVector& rSources, QAbstractItemModel*& _nativeModel); - static JASPListControl::LabelValueMap _readValues(JASPListControl* _listControl, const QVariant& _values); - static SourceItem* _readRSource(JASPListControl* listControl, const QVariant& rSource); - - void _setUp(); - Terms _readAllTerms(); - -private slots: - void _resetModel(); - void _dataChangedHandler(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); - void _rSourceChanged(const QString& name); - -private: - JASPListControl * _targetListControl = nullptr; - QString _sourceName, - _rowControlName; - QStringList _sourceFilter; - QVector _discardSources; - QVector _rSources; - JASPListControl::LabelValueMap _values; - bool _isValuesSource = false; - bool _isRSource = false; - ListModel * _sourceListModel = nullptr; - QAbstractItemModel * _sourceNativeModel = nullptr; - int _nativeModelRole = Qt::DisplayRole; - bool _isDataSetVariables = false; - bool _combineWithOtherModels = false; - QString _conditionExpression; - QVector _conditionVariables; - bool _connected = false; - JASPControl::CombinationType _combineTerms = JASPControl::CombinationType::NoCombination; - int _onlyTermsWithXComponents = 0; -}; - -#endif // SOURCEITEM_H diff --git a/QMLComponents/controls/tableviewbase.cpp b/QMLComponents/controls/tableviewbase.cpp deleted file mode 100644 index 889073e6e15..00000000000 --- a/QMLComponents/controls/tableviewbase.cpp +++ /dev/null @@ -1,273 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "log.h" -#include -#include "tableviewbase.h" -#include "models/listmodeljagsdatainput.h" -#include "analysisform.h" -#include "models/listmodelfiltereddataentry.h" -#include "models/listmodelmultinomialchi2test.h" -#include "models/listmodelfactorlevels.h" -#include "models/listmodelcustomcontrasts.h" -#include "models/listmodelgridinput.h" -#include "boundcontrols/boundcontrolcontraststableview.h" -#include "boundcontrols/boundcontrolfilteredtableview.h" -#include "boundcontrols/boundcontrolgridtableview.h" -#include "sourceitem.h" - -TableViewBase::TableViewBase(QQuickItem* parent) - : JASPListControl(parent) -{ - _controlType = ControlType::TableView; -} - -void TableViewBase::setUpModel() -{ - switch (modelType()) - { - case ModelType::MultinomialChi2Model : _tableModel = new ListModelMultinomialChi2Test( this ); break; - case ModelType::JAGSDataInputModel : _tableModel = new ListModelJAGSDataInput( this ); break; - case ModelType::CustomContrasts : _tableModel = new ListModelCustomContrasts( this ); break; - case ModelType::FilteredDataEntryModel : _tableModel = new ListModelFilteredDataEntry( this ); break; - case ModelType::GridInput : _tableModel = new ListModelGridInput( this ); break; - case ModelType::Simple : _tableModel = new ListModelTableViewBase( this ); break; - } - - JASPListControl::setUpModel(); - - connect(_tableModel, &ListModelTableViewBase::columnCountChanged, this, &TableViewBase::columnCountChanged); - connect(_tableModel, &ListModelTableViewBase::rowCountChanged, this, &TableViewBase::rowCountChanged); - connect(_tableModel, &ListModelTableViewBase::variableCountChanged, this, &TableViewBase::variableCountChanged); -} - -void TableViewBase::setUp() -{ - switch (modelType()) - { - case ModelType::CustomContrasts : _boundControl = new BoundControlContrastsTableView(this); break; - case ModelType::FilteredDataEntryModel : _boundControl = new BoundControlFilteredTableView(this); break; - case ModelType::GridInput : _boundControl = new BoundControlGridTableView(this); break; - case ModelType::MultinomialChi2Model : - case ModelType::JAGSDataInputModel : - case ModelType::Simple : - default : _boundControl = new BoundControlTableView(this); - } - - JASPListControl::setUp(); - - if (modelType() == ModelType::GridInput && hasNativeSource()) setUpdateSource(true); - - setInitialValuesControl(); - connect(this, &TableViewBase::initialValuesSourceChanged, this, &TableViewBase::setInitialValuesControl); - - // form is not always known in the constructor, so all references to form (and dataset) must be done here - if (form()) - connect(form(), &AnalysisForm::refreshTableViewModels, this, &TableViewBase::refreshMe ); - _tableModel->setup(); -} - -void TableViewBase::addColumn(int col, bool left) -{ - if (!_tableModel) return; - - if (_sourceItems.length() > 0 && updateSource()) - { - SourceItem* source = _sourceItems[0]; - QAbstractItemModel* nativeModel = source->nativeModel(); - if (!left) col++; - nativeModel->insertColumns(col, 1); - } - else - _tableModel->addColumn(); -} - -void TableViewBase::removeColumn(int col) -{ - if (!_tableModel) return; - - if (_sourceItems.length() > 0 && updateSource()) - { - SourceItem* source = _sourceItems[0]; - QAbstractItemModel* nativeModel = source->nativeModel(); - nativeModel->removeColumns(col, 1); - } - else - _tableModel->removeColumn(col); -} - -void TableViewBase::addRow() -{ - if (_tableModel) - _tableModel->addRow(); -} - -void TableViewBase::removeRow(int row) -{ - if (_tableModel) - _tableModel->removeRow(row); -} - -void TableViewBase::setSize(int rows, int columns) -{ - if (_tableModel) - { - _tableModel->setSize(rows, columns); - - if(_tableModel->areColumnNamesVariables()) - emit usedVariablesChanged(); //Well, they might have - } -} - -void TableViewBase::reset() -{ - if (_tableModel) - _tableModel->reset(); -} - -void TableViewBase::itemChanged(int col, int row, QString value, QString type) -{ - if (!_tableModel || _tableModel->data(_tableModel->index(row, col)).toString() == value) return; - - if (_tableModel->valueOk(value, col, row)) - { - if (_sourceItems.length() > 0 && updateSource()) - { - QAbstractItemModel* nativeModel = _sourceItems[0]->nativeModel(); - nativeModel->setData(nativeModel->index(row, col), value); - } - else - _tableModel->itemChanged(col, row, value, type); - } - else - QTimer::singleShot(0, _tableModel, &ListModelTableViewBase::refreshModel); - } - -void TableViewBase::setInitialValuesControl() -{ - if (_initialValuesControl) - disconnect(_initialValuesControl->model(), &ListModel::termsChanged, _tableModel, &ListModelTableViewBase::initialValuesChanged); - - QString initialValuesSourceName = initialValuesSource().toString(); - if (!initialValuesSourceName.isEmpty() && form()) - { - _initialValuesControl = qobject_cast(form()->getControl(initialValuesSourceName)); - addDependency(_initialValuesControl); - connect(_initialValuesControl->model(), &ListModel::termsChanged, _tableModel, &ListModelTableViewBase::initialValuesChanged); - _tableModel->initialValuesChanged(); - } -} - -void TableViewBase::rScriptDoneHandler(const QString & result) -{ - if(_tableModel) - _tableModel->rScriptDoneHandler(result); -} - -JASPControl::ItemType TableViewBase::itemTypePerItem(int col, int row) const -{ - if (col >= 0 && _itemTypePerColumn.length() > col) return _itemTypePerColumn[col]; - if (row >= 0 && _itemTypePerRow.length() > row) return _itemTypePerRow[row]; - - return _itemType; -} - -void TableViewBase::refreshMe() -{ - if(_tableModel) - _tableModel->refreshModel(); -} - -void TableViewBase::termsChangedHandler() -{ - if (_boundControl) - _boundControl->resetBoundValue(); -} - -QVariant TableViewBase::defaultValue(int colIndex, int rowIndex) -{ - QVariant defValue = _defaultValue; - if (colIndex >= 0 && rowIndex >= 0) - { - QMetaObject::invokeMethod(this, "getDefaultValue", Qt::DirectConnection, - Q_RETURN_ARG(QVariant, defValue), - Q_ARG(QVariant, colIndex), - Q_ARG(QVariant, rowIndex)); - } - // Force the QVariant to have the right type - switch (itemTypePerItem(colIndex, rowIndex)) - { - case JASPControl::ItemType::Integer: - { - if (defValue.typeId() == QMetaType::Int) return defValue; - if (defValue.canConvert()) return defValue.toInt(); - break; - } - case JASPControl::ItemType::Double: - { - if (defValue.typeId() == QMetaType::Double) return defValue; - if (defValue.canConvert()) return defValue.toDouble(); - break; - } - case JASPControl::ItemType::String: - { - if (defValue.typeId() == QMetaType::QString) return defValue; - if (defValue.canConvert()) return defValue.toString(); - break; - } - } - - return defValue; -} - -std::vector TableViewBase::usedVariables() const -{ - std::vector result; - - if (_tableModel && _tableModel->areColumnNamesVariables()) - { - for (int i = 0; i < _tableModel->columnCount(); i++) - result.push_back(fq(_tableModel->headerData(i, Qt::Horizontal).toString())); - } - - return result; -} - -void TableViewBase::setItemTypePerRow(QVariantList list) -{ - QList typeList; - for (const QVariant& t : list) typeList.append(JASPControl::ItemType(t.toInt())); - - if (typeList != _itemTypePerRow) - { - _itemTypePerRow = typeList; - emit itemTypePerRowChanged(); - } -} - -void TableViewBase::setItemTypePerColumn(QVariantList list) -{ - QList typeList; - for (const QVariant& t : list) typeList.append(JASPControl::ItemType(t.toInt())); - - if (typeList != _itemTypePerColumn) - { - _itemTypePerColumn = typeList; - emit itemTypePerColumnChanged(); - } -} diff --git a/QMLComponents/controls/tableviewbase.h b/QMLComponents/controls/tableviewbase.h deleted file mode 100644 index fae1b59d68a..00000000000 --- a/QMLComponents/controls/tableviewbase.h +++ /dev/null @@ -1,174 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef TABLEVIEWBASE_H -#define TABLEVIEWBASE_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontroltableview.h" -#include "models/listmodeltableviewbase.h" - -class TableViewBase : public JASPListControl, public BoundControl -{ - Q_OBJECT - - Q_PROPERTY( ModelType modelType READ modelType WRITE setModelType NOTIFY modelTypeChanged ) - Q_PROPERTY( ItemType itemType READ itemType WRITE setItemType NOTIFY itemTypeChanged ) - Q_PROPERTY( QVariantList itemTypePerColumn READ itemTypePerColumn WRITE setItemTypePerColumn NOTIFY itemTypePerColumnChanged ) - Q_PROPERTY( QVariantList itemTypePerRow READ itemTypePerRow WRITE setItemTypePerRow NOTIFY itemTypePerRowChanged ) - Q_PROPERTY( QVariant defaultValue READ defaultValue WRITE setDefaultValue NOTIFY defaultValueChanged ) - Q_PROPERTY( QVariant initialValuesSource READ initialValuesSource WRITE setInitialValuesSource NOTIFY initialValuesSourceChanged ) - Q_PROPERTY( int initialColumnCount READ initialColumnCount WRITE setInitialColumnCount NOTIFY initialColumnCountChanged ) - Q_PROPERTY( int initialRowCount READ initialRowCount WRITE setInitialRowCount NOTIFY initialRowCountChanged ) - Q_PROPERTY( int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged ) - Q_PROPERTY( int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged ) - Q_PROPERTY( int variableCount READ variableCount NOTIFY variableCountChanged ) - Q_PROPERTY( int minRow READ minRow WRITE setMinRow NOTIFY minRowChanged ) - Q_PROPERTY( int maxRow READ maxRow WRITE setMaxRow NOTIFY maxRowChanged ) - Q_PROPERTY( int minColumn READ minColumn WRITE setMinColumn NOTIFY minColumnChanged ) - Q_PROPERTY( int maxColumn READ maxColumn WRITE setMaxColumn NOTIFY maxColumnChanged ) - Q_PROPERTY( QStringList columnNames READ columnNames WRITE setColumnNames NOTIFY columnNamesChanged ) - Q_PROPERTY( QStringList rowNames READ rowNames WRITE setRowNames NOTIFY rowNamesChanged ) - Q_PROPERTY( bool updateSource READ updateSource WRITE setUpdateSource NOTIFY updateSourceChanged ) - -public: - TableViewBase(QQuickItem* parent = nullptr); - - void bindTo(const Json::Value &value) override { _boundControl->bindTo(value); } - bool isJsonValid(const Json::Value& optionValue) const override { return _boundControl->isJsonValid(optionValue); } - void resetBoundValue() override { return _boundControl->resetBoundValue(); } - const Json::Value& boundValue() const override { return _boundControl->boundValue(); } - Json::Value createJson() const override { return _boundControl->createJson(); } - Json::Value createMeta() const override { return _boundControl->createMeta(); } - const Json::Value& defaultBoundValue() const override { return _boundControl->defaultBoundValue(); } - void setDefaultBoundValue(const Json::Value& defaultValue) override { _boundControl->setDefaultBoundValue(defaultValue); } - - void setBoundValue(const Json::Value& value, - bool emitChange = true) override { return _boundControl->setBoundValue(value, emitChange); } - - ListModel* model() const override { return _tableModel; } - ListModelTableViewBase* tableModel() const { return _tableModel; } - void setUpModel() override; - void setUp() override; - void rScriptDoneHandler(const QString & result) override; - - ItemType itemTypePerItem(int col = -1, int row = -1) const; - - JASPControl::ModelType modelType() const { return _modelType; } - JASPControl::ItemType itemType() const { return _itemType; } - QVariant defaultValue(int colIndex = -1, int rowIndex = -1); - QVariantList itemTypePerRow() const { QVariantList l; for (auto t : _itemTypePerRow) l.append(int(t)); return l; } - QVariantList itemTypePerColumn() const { QVariantList l; for (auto t : _itemTypePerColumn) l.append(int(t)); return l; } - QVariant initialValuesSource() const { return _initialValuesSource; } - JASPListControl* initialValuesControl() const { return _initialValuesControl; } - int initialColumnCount() const { return _initialColumnCount; } - int initialRowCount() const { return _initialRowCount; } - int rowCount() const { return _tableModel ? _tableModel->rowCount() : 0; } - int columnCount() const { return _tableModel ? _tableModel->columnCount() : 0; } - int variableCount() const { return _tableModel ? _tableModel->variableCount() : 0; } - int minRow() const { return _minRow; } - int maxRow() const { return _maxRow; } - int minColumn() const { return _minColumn; } - int maxColumn() const { return _maxColumn; } - QStringList columnNames() const { return _columnNames; } - QStringList rowNames() const { return _rowNames; } - bool updateSource() const { return _updateSource; } - std::vector usedVariables() const override; - - void setRowCount(int rows) { setSize(rows, -1); } - void setColumnCount(int columns) { setSize(-1, columns); } - - Q_INVOKABLE void addColumn(int col = -1, bool left = true); - Q_INVOKABLE void removeColumn(int col); - Q_INVOKABLE void addRow(); - Q_INVOKABLE void removeRow(int row); - Q_INVOKABLE void setSize(int rows, int columns); - Q_INVOKABLE void reset(); - Q_INVOKABLE void itemChanged(int col, int row, QString value, QString type); - - -signals: - void modelTypeChanged(); - void itemTypeChanged(); - void itemTypePerRowChanged(); - void itemTypePerColumnChanged(); - void defaultValueChanged(); - void initialRowCountChanged(); - void initialColumnCountChanged(); - void initialValuesSourceChanged(); - void rowCountChanged(); - void columnCountChanged(); - void variableCountChanged(); - void minRowChanged(); - void maxRowChanged(); - void minColumnChanged(); - void maxColumnChanged(); - void columnNamesChanged(); - void rowNamesChanged(); - void updateSourceChanged(); - -public slots: - void refreshMe(); - -protected slots: - void termsChangedHandler() override; - - GENERIC_SET_FUNCTION(ModelType, _modelType, modelTypeChanged, ModelType ) - GENERIC_SET_FUNCTION(ItemType, _itemType, itemTypeChanged, ItemType ) - GENERIC_SET_FUNCTION(DefaultValue, _defaultValue, defaultValueChanged, QVariant ) - GENERIC_SET_FUNCTION(InitialRowCount, _initialRowCount, initialRowCountChanged, int ) - GENERIC_SET_FUNCTION(InitialColumnCount, _initialColumnCount, initialColumnCountChanged, int ) - GENERIC_SET_FUNCTION(InitialValuesSource, _initialValuesSource, initialValuesSourceChanged, QVariant ) - GENERIC_SET_FUNCTION(MinRow, _minRow, minRowChanged, int ) - GENERIC_SET_FUNCTION(MaxRow, _maxRow, maxRowChanged, int ) - GENERIC_SET_FUNCTION(MinColumn, _minColumn, minColumnChanged, int ) - GENERIC_SET_FUNCTION(MaxColumn, _maxColumn, maxColumnChanged, int ) - GENERIC_SET_FUNCTION(ColumnNames, _columnNames, columnNamesChanged, QStringList ) - GENERIC_SET_FUNCTION(RowNames, _rowNames, rowNamesChanged, QStringList ) - GENERIC_SET_FUNCTION(UpdateSource, _updateSource, updateSourceChanged, bool ) - - void setItemTypePerRow(QVariantList list); - void setItemTypePerColumn(QVariantList list); - -protected: - BoundControlTableView * _boundControl = nullptr; - ListModelTableViewBase * _tableModel = nullptr; - -private slots: - void setInitialValuesControl(); - -private: - QVariant _defaultValue; - ModelType _modelType = ModelType::Simple; - ItemType _itemType = ItemType::Double; - QList _itemTypePerRow, - _itemTypePerColumn; - int _initialRowCount = 0, - _initialColumnCount = 0, - _minRow = 0, - _minColumn = 0, - _maxRow = -1, - _maxColumn = -1; - QStringList _columnNames, - _rowNames; - QVariant _initialValuesSource; - JASPListControl* _initialValuesControl = nullptr; - bool _updateSource = false; -}; - -#endif // TABLEVIEWBASE_H diff --git a/QMLComponents/controls/textareabase.cpp b/QMLComponents/controls/textareabase.cpp deleted file mode 100644 index 1a0a499e602..00000000000 --- a/QMLComponents/controls/textareabase.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "textareabase.h" -#include "analysisform.h" -#include "boundcontrols/boundcontrolsourcetextarea.h" -#include "boundcontrols/boundcontroljagstextarea.h" -#include "boundcontrols/boundcontrollavaantextarea.h" -#include "boundcontrols/boundcontrolcsemtextarea.h" - - -#include -#include -#include -#include - -#include "log.h" - -TextAreaBase::TextAreaBase(QQuickItem* parent) - : JASPListControl(parent) -{ - _controlType = ControlType::TextArea; -} - -void TextAreaBase::setUpModel() -{ - if (_textType == TextType::TextTypeSource || _textType == TextType::TextTypeJAGSmodel || _textType == TextType::TextTypeLavaan || _textType == TextType::TextTypeCSem) - { - _model = new ListModelTermsAvailable(this); - _model->setNeedsSource(_textType == TextType::TextTypeLavaan || _textType == TextType::TextTypeCSem); - - JASPListControl::setUpModel(); - } -} - -void TextAreaBase::setUp() -{ - switch (_textType) - { - case TextType::TextTypeSource: _boundControl = new BoundControlSourceTextArea(this); break; - case TextType::TextTypeLavaan: _boundControl = new BoundControlLavaanTextArea(this); break; - case TextType::TextTypeJAGSmodel: _boundControl = new BoundControlJAGSTextArea(this); break; - case TextType::TextTypeCSem: _boundControl = new BoundControlCSemTextArea(this); break; - default: _boundControl = new BoundControlTextArea(this); break; - } - - JASPListControl::setUp(); - - QList separators = property("separators").toList(); - if (separators.isEmpty()) - _separators.push_back(property("separator").toString()); - else - { - for (QVariant& separator : separators) - _separators.push_back(separator.toString()); - } - - //If "rowCount" changes on VariableInfo it means a column has been added or removed, this means the model should be reencoded and checked - //Fixes https://github.com/jasp-stats/jasp-issues/issues/2462 - connect(VariableInfo::info(), &VariableInfo::rowCountChanged, this, &TextAreaBase::checkSyntaxHandler); - - //Also do it on request of course ;) - connect(this, &TextAreaBase::applyRequest, this, &TextAreaBase::checkSyntaxHandler); -} - -void TextAreaBase::rScriptDoneHandler(const QString & result) -{ - QString error = _boundControl->rScriptDoneHandler(result); - if (error.isEmpty()) - { - setHasScriptError(false); - setProperty("infoText", tr("Model applied")); - } - else - { - setHasScriptError(true); - setProperty("infoText", result); - } -} - -QString TextAreaBase::text() -{ - return property("text").toString(); -} - -void TextAreaBase::setText(const QString& text) -{ - setProperty("text", text); -} - -void TextAreaBase::termsChangedHandler() -{ - if (_textType == TextType::TextTypeLavaan || _textType == TextType::TextTypeCSem && form() && initialized()) - form()->refreshAnalysis(); - -} diff --git a/QMLComponents/controls/textareabase.h b/QMLComponents/controls/textareabase.h deleted file mode 100644 index e73afb27094..00000000000 --- a/QMLComponents/controls/textareabase.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -#ifndef TEXTAREABASE_H -#define TEXTAREABASE_H - -#include "jasplistcontrol.h" -#include "boundcontrols/boundcontrolbase.h" -#include "models/listmodeltermsavailable.h" -#include "boundcontrols/boundcontroltextarea.h" - -#include - -#include -#include -#include -#include - -class TextAreaBase : public JASPListControl, public BoundControl -{ - Q_OBJECT - - Q_PROPERTY( TextType textType READ textType WRITE setTextType NOTIFY textTypeChanged ) - Q_PROPERTY( bool hasScriptError READ hasScriptError WRITE setHasScriptError NOTIFY hasScriptErrorChanged ) - -public: - TextAreaBase(QQuickItem* parent = nullptr); - - void bindTo(const Json::Value &value) override { _boundControl->bindTo(value); } - bool isJsonValid(const Json::Value& optionValue) const override { return _boundControl->isJsonValid(optionValue); } - void resetBoundValue() override { return _boundControl->resetBoundValue(); } - const Json::Value& boundValue() const override { return _boundControl->boundValue(); } - Json::Value createJson() const override { return _boundControl->createJson(); } - Json::Value createMeta() const override { return _boundControl->createMeta(); } - const Json::Value& defaultBoundValue() const override { return _boundControl->defaultBoundValue(); } - void setDefaultBoundValue(const Json::Value& defaultValue) override { _boundControl->setDefaultBoundValue(defaultValue); } - void setBoundValue(const Json::Value& value, - bool emitChange = true) override { return _boundControl->setBoundValue(value, emitChange); } - - ListModel* model() const override { return _model; } - ListModelTermsAvailable* availableModel() const { return _model; } - void setUp() override; - void setUpModel() override; - - void rScriptDoneHandler(const QString &result) override; - - TextType textType() const { return _textType; } - bool hasScriptError() const { return _hasScriptError; } - const QList& separators() const { return _separators; } - QString text(); - void setText(const QString& text); - -public slots: - GENERIC_SET_FUNCTION(TextType, _textType, textTypeChanged, TextType ) - GENERIC_SET_FUNCTION(HasScriptError, _hasScriptError, hasScriptErrorChanged, bool ) - - void checkSyntaxHandler() { _boundControl->checkSyntax(); } - -signals: - void textTypeChanged(); - void hasScriptErrorChanged(); - void applyRequest(); - void editingFinished(); - -protected slots: - void termsChangedHandler() override; - -protected: - - BoundControlTextArea* _boundControl = nullptr; - TextType _textType = TextType::TextTypeDefault; - bool _hasScriptError = false; - QList _separators; - - ListModelTermsAvailable* _model = nullptr; - -}; - - -#endif // TEXTAREABASE_H diff --git a/QMLComponents/controls/textinputbase.cpp b/QMLComponents/controls/textinputbase.cpp deleted file mode 100644 index 12c49ac38cb..00000000000 --- a/QMLComponents/controls/textinputbase.cpp +++ /dev/null @@ -1,398 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "textinputbase.h" -#include "analysisform.h" - -using namespace std; - -TextInputBase::TextInputBase(QQuickItem* parent) - : JASPControl(parent), BoundControlBase(this) -{ - _controlType = ControlType::TextField; -} - -QString TextInputBase::_getPercentValue(double dblVal) -{ - double doubleValue = dblVal * 100; // The value is stored as a double from 0...1, but is displayed as a percent number - doubleValue = std::max(0., std::min(100., doubleValue)); - - int decimals = property("decimals").toInt(); - return QString::number(doubleValue, 'f', decimals); -} - -QString TextInputBase::_getIntegerArrayValue(const std::vector& intValues) -{ - QString value; - bool first = true; - for (int intValue : intValues) - { - if (!first) - value += ","; - first = false; - value += QString::number(intValue); - } - - return value; -} - -QString TextInputBase::_getDoubleArrayValue(const std::vector& doubleValues) -{ - QString value; - bool first = true; - for (double doubleValue : doubleValues) - { - if (!first) - value += ","; - first = false; - value += QString::number(doubleValue); - } - - return value; -} - -void TextInputBase::bindTo(const Json::Value& value) -{ - switch (_inputType) - { - case TextInputType::IntegerInputType: - if (value.isNumeric()) _value = value.asInt(); - else if (value.isString()) _value = std::stoi(value.asString()); - break; - case TextInputType::NumberInputType: - case TextInputType::PercentIntputType: - { - double dblVal = 0; - if (value.isNumeric()) dblVal = value.asDouble(); - else if (value.isString()) dblVal = std::stod(value.asString()); - if (_inputType == TextInputType::PercentIntputType) - _value = _getPercentValue(dblVal); - else - _value = dblVal; - - break; - } - case TextInputType::IntegerArrayInputType: - { - std::vector arrayVal; - if (value.isArray()) - { - for (const Json::Value& oneValue : value) - if (oneValue.isNumeric()) arrayVal.push_back(oneValue.asInt()); - } - _value = _getIntegerArrayValue(arrayVal); - break; - } - case TextInputType::DoubleArrayInputType: - { - std::vector arrayVal; - if (value.isArray()) - { - for (const Json::Value& oneValue : value) - if (oneValue.isNumeric()) arrayVal.push_back(oneValue.asDouble()); - } - _value = _getDoubleArrayValue(arrayVal); - break; - } - case TextInputType::FormulaType: - case TextInputType::FormulaArrayType: - { - QString strValue; - if (value.isString()) strValue = tq(value.asString()); - _value = strValue; - setIsRCode(); - - if (!strValue.isEmpty()) - { - if (_inputType == TextInputType::FormulaType) runRScript("as.character(" + strValue + ")", true); - else runRScript("paste(as.array(" + strValue + "), collapse=\"|\")", true); - } - break; - } - case TextInputType::ComputedColumnType: - { - if (value.isString()) _value = tq(value.asString()); - setIsColumn(true); - break; - } - case TextInputType::AddColumnType: - { - if (value.isString()) _value = tq(value.asString()); - columnType colType = static_cast(property("columnType").toInt()); - setIsColumn(false, colType); - break; - } - default: - { - if (value.isString()) _value = tq(value.asString()); - break; - } - } - - setDisplayValue(); - emit valueChanged(); - - BoundControlBase::bindTo(value); -} - -Json::Value TextInputBase::createJson() const -{ - QVariant value = property("displayValue"); - if (value.toString() == "" && !_defaultValue.isNull()) value = _defaultValue; - - return _getJsonValue(value); -} - -bool TextInputBase::isJsonValid(const Json::Value &value) const -{ - bool valid = false; - switch (_inputType) - { - case TextInputType::IntegerArrayInputType: - case TextInputType::DoubleArrayInputType: - case TextInputType::FormulaArrayType: valid = value.isArray(); break; - default: valid = value.isNumeric() || value.isString(); break; - } - return valid; -} - -void TextInputBase::setUp() -{ - QString type = property("inputType").toString(); - - if (type == "integer") _inputType = TextInputType::IntegerInputType; - else if (type == "number") _inputType = TextInputType::NumberInputType; - else if (type == "percent") _inputType = TextInputType::PercentIntputType; - else if (type == "integerArray") _inputType = TextInputType::IntegerArrayInputType; - else if (type == "doubleArray") _inputType = TextInputType::DoubleArrayInputType; - else if (type == "computedColumn") _inputType = TextInputType::ComputedColumnType; - else if (type == "addColumn") _inputType = TextInputType::AddColumnType; - else if (type == "formula") _inputType = TextInputType::FormulaType; - else if (type == "formulaArray") _inputType = TextInputType::FormulaArrayType; - else _inputType = TextInputType::StringInputType; - - _parseDefaultValue = property("parseDefaultValue").toBool(); - - QQuickItem::connect(this, SIGNAL(editingFinished()), this, SLOT(valueChangedSlot())); - - if (form()) - // For unknown reason, when the language is changed, QML reset the default value. - // We have then to set back the value from the option - connect(form(), &AnalysisForm::languageChanged, this, &TextInputBase::setDisplayValue); - - if (_value.isNull()) // If the value is not directly set, use the default value. - setValue(_defaultValue); - - JASPControl::setUp(); // It might need the _inputType, so call it after it is set. -} - -void TextInputBase::setDisplayValue() -{ - setProperty("displayValue", _value); -} - -void TextInputBase::rScriptDoneHandler(const QString &result) -{ - QStringList results; - QVariantList values; - - if (_inputType == TextInputType::FormulaType) - results.push_back(result); - else - results = result.split("|"); - - bool succes = true; - for (const QString& valStr : results) - { - double val = valStr.toDouble(&succes); - - if (!succes) - { - addControlError(tr("The expression did not return a number.")); - setHasScriptError(true); - break; - } - - if (!_formulaResultInBounds(val)) - { - succes = false; - break; - } - - values.push_back(val); - } - - if (succes) - { - emit formulaCheckSucceeded(); - setProperty("realValues", values); - if (values.length() > 0) - setProperty("realValue", values[0]); - } - - setBoundValue(fq(_value.toString())); -} - -QString TextInputBase::friendlyName() const -{ - switch (_inputType) - { - case TextInputType::IntegerInputType: return tr("Integer Field"); - case TextInputType::NumberInputType: return tr("Number Field"); - case TextInputType::PercentIntputType: return tr("Percentage Field"); - case TextInputType::IntegerArrayInputType: return tr("Integers Field"); - case TextInputType::DoubleArrayInputType: return tr("Doubles Field"); - case TextInputType::AddColumnType: return tr("Add Column Field"); - case TextInputType::ComputedColumnType: return tr("Add Computed Column Field"); - case TextInputType::FormulaType: return tr("Formula Field"); - case TextInputType::FormulaArrayType: return tr("Formulas Field"); - case TextInputType::StringInputType: - default: return tr("Text Field"); - } -} - -QString TextInputBase::helpMD(SetConst & markdowned, int howDeep, bool) const -{ - markdowned.insert(this); - - if(info() == "" || (label() == "" && afterLabel() == "")) - return ""; - - QStringList md; - - md << QString{howDeep, '#' } << " " << friendlyName() << "\n" - << "`" << label() << " ... " << afterLabel() << "`\n\n" - << info() << "\n"; - - - return md.join(""); -} - - -bool TextInputBase::_formulaResultInBounds(double result) -{ - double min = property("min").toDouble(); - double max = property("max").toDouble(); - JASPControl::Inclusive inclusive = JASPControl::Inclusive(property("inclusive").toInt()); - bool includeMin = (inclusive == JASPControl::Inclusive::MinMax || inclusive == JASPControl::Inclusive::MinOnly); - bool includeMax = (inclusive == JASPControl::Inclusive::MinMax || inclusive == JASPControl::Inclusive::MaxOnly); - - bool tooSmall = includeMin ? result < min : result <= min; - bool tooLarge = includeMax ? result > max : result >= max; - bool inBounds = !(tooSmall || tooLarge); - - if (!inBounds) - { - QString end; - if (tooSmall) end = (includeMin ? "≥ " : "> ") + property("min").toString(); - else end = (includeMax ? "≤ " : "< ") + property("max").toString(); - addControlError(tr("The value (%1) must be %2").arg(result).arg(end)); - setHasScriptError(true); - } - else - { - setHasScriptError(false); - clearControlError(); - } - - return inBounds; -} - -Json::Value TextInputBase::_getJsonValue(const QVariant& value) const -{ - switch (_inputType) - { - case TextInputType::IntegerInputType: return (value.toInt()); - case TextInputType::NumberInputType: return value.toDouble(); - case TextInputType::PercentIntputType: return std::min(std::max(value.toDouble(), 0.0), 100.0) / 100; - case TextInputType::IntegerArrayInputType: - case TextInputType::DoubleArrayInputType: - { - QString str = value.toString(); - str.replace(QString(" "), QString(",")); - Json::Value values(Json::arrayValue); - QStringList chunks = str.split(QChar(','), Qt::SkipEmptyParts); - - for (QString &chunk: chunks) - { - bool ok; - if (_inputType == TextInputType::IntegerInputType) - { - int value = chunk.toInt(&ok); - if (ok) values.append(value); - } - else - { - double value = chunk.toDouble(&ok); - if (ok) values.append(value); - } - } - return values; - } - default: return fq(value.toString()); - } -} - -void TextInputBase::valueChangedSlot() -{ - setValue(property("displayValue")); -} - -void TextInputBase::setValue(const QVariant &value) -{ - bool hasChanged = _value != value; - _value = value; - - setDisplayValue(); - - if (hasChanged) - { - emit valueChanged(); - - if (_initialized) - _setBoundValue(); - } -} - -void TextInputBase::_setBoundValue() -{ - if (_inputType == TextInputType::FormulaType || _inputType == TextInputType::FormulaArrayType) - { - QString strValue = _value.toString(); - - // _formula might be empty (in TableView the FormulaType is not directly bound, and has its own model). - if (boundValue().asString() != fq(strValue)) - { - if (!_parseDefaultValue && _defaultValue == _value) - { - // The value is the same as the default value and this default value should not be parsed (this might be just a string like '...') - // So just set this value and emit that the formula is succesfully checked without running the R script. - setBoundValue(fq(strValue)); - emit formulaCheckSucceeded(); - } - else if (_inputType == TextInputType::FormulaType) - runRScript("as.character(" + strValue + ")", true); - else - runRScript("paste(as.array(" + strValue + "), collapse=\"|\")", true); - - } - } - else setBoundValue(_getJsonValue(_value)); - -} - diff --git a/QMLComponents/controls/textinputbase.h b/QMLComponents/controls/textinputbase.h deleted file mode 100644 index 17a2505e89e..00000000000 --- a/QMLComponents/controls/textinputbase.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef TEXTINPUTBASE_H -#define TEXTINPUTBASE_H - -#include "jaspcontrol.h" -#include "boundcontrols/boundcontrolbase.h" - -class TextInputBase : public JASPControl, public BoundControlBase -{ - Q_OBJECT - - Q_PROPERTY( bool hasScriptError READ hasScriptError WRITE setHasScriptError NOTIFY hasScriptErrorChanged ) - Q_PROPERTY( QVariant defaultValue READ defaultValue WRITE setDefaultValue NOTIFY defaultValueChanged ) - Q_PROPERTY( QString label READ label WRITE setLabel NOTIFY labelChanged ) - Q_PROPERTY( QString afterLabel READ afterLabel WRITE setAfterLabel NOTIFY afterLabelChanged ) - Q_PROPERTY( QVariant value READ value WRITE setValue NOTIFY valueChanged ) - -public: - enum TextInputType { IntegerInputType = 0, StringInputType, NumberInputType, PercentIntputType, IntegerArrayInputType, DoubleArrayInputType, ComputedColumnType, AddColumnType, FormulaType, FormulaArrayType}; - - TextInputBase(QQuickItem* parent = nullptr); - - bool isJsonValid(const Json::Value& value) const override; - Json::Value createJson() const override; - void bindTo(const Json::Value& value) override; - void setUp() override; - void rScriptDoneHandler(const QString& result) override; - QString helpMD(SetConst & markdowned, - int howDeep = 2, bool asList=true) const override; - - TextInputType inputType() { return _inputType; } - QString friendlyName() const override; - bool hasScriptError() const { return _hasScriptError; } - QVariant defaultValue() const { return _defaultValue; } - QVariant value() const { return _value.isNull() ? _defaultValue : _value; } // Sometimes the value is asked before the control is setup, so in this case give the default value - - const QString &label() const { return _label; } - const QString &afterLabel() const { return _afterLabel; } - -signals: - void formulaCheckSucceeded(); - void hasScriptErrorChanged(); - void defaultValueChanged(); - void valueChanged(); - void labelChanged(); - void afterLabelChanged(); - -public slots: - GENERIC_SET_FUNCTION(HasScriptError, _hasScriptError, hasScriptErrorChanged, bool ) - GENERIC_SET_FUNCTION(DefaultValue, _defaultValue, defaultValueChanged, QVariant ) - GENERIC_SET_FUNCTION(Label, _label, labelChanged, QString ) - GENERIC_SET_FUNCTION(AfterLabel, _afterLabel, afterLabelChanged, QString ) - void setValue(const QVariant &value); - -private slots: - void valueChangedSlot(); - void setDisplayValue(); - -private: - Json::Value _getJsonValue(const QVariant& value) const; - bool _formulaResultInBounds(double result); - - QString _getPercentValue(double val); - QString _getIntegerArrayValue(const std::vector& intValues); - QString _getDoubleArrayValue(const std::vector& dblValues); - - void _setBoundValue(); - - TextInputType _inputType; - QString _label, - _afterLabel; - - bool _parseDefaultValue = true; - QVariant _defaultValue = "", - _value; // value should not be set: we can then make the difference whether the QML sets directly the value or not - bool _hasScriptError = false; -}; - -#endif // TEXTINPUTBASE_H diff --git a/QMLComponents/controls/variablesformbase.cpp b/QMLComponents/controls/variablesformbase.cpp deleted file mode 100644 index a4aecb15677..00000000000 --- a/QMLComponents/controls/variablesformbase.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "variablesformbase.h" -#include "variableslistbase.h" -#include "jasptheme.h" - -VariablesFormBase::VariablesFormBase(QQuickItem* parent) : JASPControl(parent) -{ - _controlType = ControlType::VariablesForm; -} - -void VariablesFormBase::componentComplete() -{ - JASPControl::componentComplete(); - - _allJASPControls.clear(); - _allAssignedVariablesList.clear(); - _availableVariablesList = nullptr; - - QQuickItem* contentItems = property("contentItems").value(); - QList items = contentItems->childItems(); - - bool debugMode = false; -#ifdef JASP_DEBUG - debugMode = true; -#endif - - for (QQuickItem* item : items) - { - JASPControl* control = qobject_cast(item); - if (!control) continue; - - if (debug()) control->setDebug(true); - if (debugMode || !control->debug()) - { - VariablesListBase* variablesList = qobject_cast(control); - if (variablesList) - { - if (variablesList->listViewType() == JASPControl::ListViewType::AvailableVariables || variablesList->listViewType() == JASPControl::ListViewType::AvailableInteraction) - { - if (_availableVariablesList) - addControlError(tr("Only 1 Available Variables list can be set in a VariablesForm")); - - _availableVariablesList = variablesList; - } - else - _allAssignedVariablesList.push_back(control); - } - if (control != _availableVariablesList) - _allJASPControls.push_back(control); - - control->setParentItem(this); - } - } - - if (!_availableVariablesList) - { - addControlError(tr("There is no Available List in the Variables Form")); - return; - } - - _availableVariablesList->setY(0); - _availableVariablesList->setX(0); - - // Set the width of the VariablesList to listWidth only if it is not set explicitely - // Implicitely, the width is set to the parent width. - if (qFuzzyCompare(_availableVariablesList->width(), width())) - _controlsWidthSetByForm.push_back(_availableVariablesList); - - for (JASPControl* control : _allJASPControls) - { - ControlType type = control->controlType(); - if ((type == ControlType::VariablesListView) || (type == ControlType::FactorLevelList) || (type == ControlType::InputListView)) - { - if (qFuzzyCompare(control->width(), width())) - _controlsWidthSetByForm.push_back(control); - - if (qFuzzyCompare(control->height(), double(JaspTheme::currentTheme()->defaultVariablesFormHeight()))) - _controlsHeightSetByForm.push_back(control); - } - else if (type == ControlType::ComboBox) - { - _controlsWidthSetByForm.push_back(control); - connect(control, &QQuickItem::heightChanged, this, &VariablesFormBase::setControlsSizeSlot); - } - } - - QMetaObject::invokeMethod(this, "init"); - - setInitialized(); -} - -void VariablesFormBase::setMarginBetweenVariablesLists(qreal value) -{ - if (qFuzzyCompare(value, _marginBetweenVariablesLists)) - { - _marginBetweenVariablesLists = value; - emit marginBetweenVariablesListsChanged(); - } -} - -void VariablesFormBase::setMinimumHeightVariablesLists(qreal value) -{ - if (qFuzzyCompare(value, _minimumHeightVariablesLists)) - { - _minimumHeightVariablesLists = value; - emit minimumHeightVariablesListsChanged(); - } -} - -JASPControl* VariablesFormBase::availableVariablesList() const -{ - return _availableVariablesList; -} - -void VariablesFormBase::setControlsSizeSlot() -{ - QMetaObject::invokeMethod(this, "setControlsSize"); -} diff --git a/QMLComponents/controls/variablesformbase.h b/QMLComponents/controls/variablesformbase.h deleted file mode 100644 index cccf3009821..00000000000 --- a/QMLComponents/controls/variablesformbase.h +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef VARIABLESFROMBASE_H -#define VARIABLESFROMBASE_H - -#include "jaspcontrol.h" - -class VariablesListBase; - -class VariablesFormBase : public JASPControl -{ - Q_OBJECT - - Q_PROPERTY( JASPControl* availableVariablesList READ availableVariablesList NOTIFY availableVariablesListChanged ) - Q_PROPERTY( QList allAssignedVariablesList READ allAssignedVariablesList NOTIFY allAssignedVariablesListChanged ) - Q_PROPERTY( QList allJASPControls READ allJASPControls NOTIFY allJASPControlsChanged ) - Q_PROPERTY( qreal marginBetweenVariablesLists READ marginBetweenVariablesLists WRITE setMarginBetweenVariablesLists NOTIFY marginBetweenVariablesListsChanged ) - Q_PROPERTY( qreal minimumHeightVariablesLists READ minimumHeightVariablesLists WRITE setMinimumHeightVariablesLists NOTIFY minimumHeightVariablesListsChanged ) - -public: - VariablesFormBase(QQuickItem* parent = nullptr); - - JASPControl* availableVariablesList() const; - QList allAssignedVariablesList() const { return _allAssignedVariablesList; } - QList allJASPControls() const { return _allJASPControls; } - qreal marginBetweenVariablesLists() const { return _marginBetweenVariablesLists; } - qreal minimumHeightVariablesLists() const { return _minimumHeightVariablesLists; } - - Q_INVOKABLE bool widthSetByForm(JASPControl* control) { return _controlsWidthSetByForm.contains(control); } - Q_INVOKABLE bool heightSetByForm(JASPControl* control) { return _controlsHeightSetByForm.contains(control); } - -signals: - void availableVariablesListChanged(); - void allAssignedVariablesListChanged(); - void allJASPControlsChanged(); - void marginBetweenVariablesListsChanged(); - void minimumHeightVariablesListsChanged(); - -protected: - void componentComplete() override; - -protected slots: - void setMarginBetweenVariablesLists(qreal value); - void setMinimumHeightVariablesLists(qreal value); - void setControlsSizeSlot(); - -private: - - VariablesListBase* _availableVariablesList = nullptr; - QList _allAssignedVariablesList, - _allJASPControls, - _controlsWidthSetByForm, - _controlsHeightSetByForm; - qreal _marginBetweenVariablesLists = 8; - qreal _minimumHeightVariablesLists = 25; - -}; - -#endif // VARIABLESFROMBASE_H diff --git a/QMLComponents/controls/variableslistbase.cpp b/QMLComponents/controls/variableslistbase.cpp deleted file mode 100644 index 70af5d27a62..00000000000 --- a/QMLComponents/controls/variableslistbase.cpp +++ /dev/null @@ -1,474 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "variableslistbase.h" -#include "checkboxbase.h" -#include "models/listmodeltermsavailable.h" -#include "models/listmodelinteractionavailable.h" -#include "models/listmodeltermsassigned.h" -#include "models/listmodelmeasurescellsassigned.h" -#include "models/listmodelinteractionassigned.h" -#include "models/listmodellayersassigned.h" -#include "models/listmodelmultitermsassigned.h" -#include "boundcontrols/boundcontrolmeasurescells.h" -#include "boundcontrols/boundcontrollayers.h" -#include "boundcontrols/boundcontrolterms.h" -#include "boundcontrols/boundcontrolmultiterms.h" -#include "utilities/desktopcommunicator.h" -#include "rowcontrols.h" -#include "analysisform.h" -#include "sourceitem.h" -#include -#include -#include "log.h" - -VariablesListBase::VariablesListBase(QQuickItem* parent) - : JASPListControl(parent) -{ - _controlType = ControlType::VariablesListView; - _useControlMouseArea = false; -} - -void VariablesListBase::setUp() -{ - JASPListControl::setUp(); - - if (listViewType() == ListViewType::RepeatedMeasures) - { - for (SourceItem* sourceItem : _sourceItems) - { - ListModelFactorLevels* factorsModel = dynamic_cast(sourceItem->sourceListModel()); - if (!factorsModel) - addControlError(tr("Source model of %1 must be from a Factor List").arg(name())); - else - { - addDependency(factorsModel->listView()); - BoundControlMeasuresCells* measuresCellsControl = dynamic_cast(_boundControl); - measuresCellsControl->addFactorModel(factorsModel); - } - } - } - - _setRelations(); - - ListModelAvailableInterface* availableModel = qobject_cast(_draggableModel); - - if (availableModel) - { - SortMenuModel* sortedMenuModel = new SortMenuModel(_draggableModel, {Sortable::None, Sortable::SortByName, Sortable::SortByType}); - setProperty("sortMenuModel", QVariant::fromValue(sortedMenuModel)); - } - - _setAllowedVariables(); - - connect(DesktopCommunicator::singleton(), &DesktopCommunicator::currentJaspThemeChanged, this, &VariablesListBase::_setAllowedVariables); - - _draggableModel->setItemType(property("itemType").toString()); - JASPControl::DropMode dropMode = JASPControl::DropMode(property("dropMode").toInt()); - _draggableModel->setDropMode(dropMode); - - //We use macros here because the signals come from QML - QQuickItem::connect(this, SIGNAL(itemDoubleClicked(int)), this, SLOT(itemDoubleClickedHandler(int))); - QQuickItem::connect(this, SIGNAL(itemsDropped(QVariant, QVariant, int)), this, SLOT(itemsDroppedHandler(QVariant, QVariant, int))); - connect(this, &VariablesListBase::allowedColumnsChanged, this, &VariablesListBase::_setAllowedVariables); - connect(this, &VariablesListBase::suggestedColumnsChanged, this, &VariablesListBase::_setAllowedVariables); -} - -void VariablesListBase::_setInitialized(const Json::Value &value) -{ - ListModelAvailableInterface* availableModel = qobject_cast(_draggableModel); - if (availableModel) - availableModel->resetTermsFromSources(false); - else if (value == Json::nullValue && addAvailableVariablesToAssigned()) - { - // If addAvailableVariablesToAssigned is true and this is initialized without value, - // maybe the availableAssignedList has some default values that must be assigned to this VariablesList - ListModelAssignedInterface* assignedModel = qobject_cast(_draggableModel); - if (assignedModel) - assignedModel->initTerms(assignedModel->availableModel()->terms()); - } - - JASPListControl::_setInitialized(value); -} - - -ListModel *VariablesListBase::model() const -{ - return _draggableModel; -} - -void VariablesListBase::setUpModel() -{ - switch (_listViewType) - { - case ListViewType::AvailableVariables: - _isBound = false; - _draggableModel = new ListModelTermsAvailable(this); - break; - - case ListViewType::AvailableInteraction: - _isBound = false; - _termsAreInteractions = true; - _draggableModel = new ListModelInteractionAvailable(this); - break; - - case ListViewType::Layers: - { - auto * layersModel = new ListModelLayersAssigned(this); - _boundControl = new BoundControlLayers(layersModel); - _draggableModel = layersModel; - break; - } - - case ListViewType::RepeatedMeasures: - { - auto * measuresCellsModel = new ListModelMeasuresCellsAssigned(this); - _boundControl = new BoundControlMeasuresCells(measuresCellsModel); - _draggableModel = measuresCellsModel; - break; - } - - case ListViewType::AssignedVariables: - { - ListModelAssignedInterface* termsModel = nullptr; - - if (columns() > 1) - { - auto * multiTermsModel = new ListModelMultiTermsAssigned(this, columns()); - _boundControl = new BoundControlMultiTerms(multiTermsModel); - _draggableModel = multiTermsModel; - } - else - { - termsModel = new ListModelTermsAssigned(this); - _boundControl = new BoundControlTerms(termsModel, _maxRows == 1); - _draggableModel = termsModel; - } - break; - } - - case ListViewType::Interaction: - { - _termsAreInteractions = true; - - bool interactionContainLowerTerms = property("interactionContainLowerTerms").toBool(), - addInteractionsByDefault = property("addInteractionsByDefault").toBool(); - - auto * termsModel = new ListModelInteractionAssigned(this, interactionContainLowerTerms, addInteractionsByDefault); - _boundControl = new BoundControlTerms(termsModel); - _draggableModel = termsModel; - break; - } - - } - - JASPListControl::setUpModel(); -} - -bool VariablesListBase::addRowControl(const QString &key, JASPControl *control) -{ - bool result = JASPListControl::addRowControl(key, control); - - if (result && !_interactionHighOrderCheckBox.isEmpty() && _interactionHighOrderCheckBox == control->name()) - connect(control, &JASPControl::boundValueChanged, this, &VariablesListBase::interactionHighOrderHandler); - - return result; -} - -void VariablesListBase::itemDoubleClickedHandler(int index) -{ - ListModel *targetModel = getRelatedModel(); - - if (!targetModel) - { - addControlError(tr("No related list found for VariablesList %1").arg(name())); - return; - } - - ListModelDraggable *draggableTargetModel = dynamic_cast(targetModel); - if (!draggableTargetModel) - { - addControlError(tr("Wrong kind of related list (%1) found for VariablesList %2").arg(targetModel->name()).arg(name())); - return; - } - - QList indexes; - indexes.push_back(index); - moveItems(indexes, draggableTargetModel); -} - -void VariablesListBase::itemsDroppedHandler(QVariant vindexes, QVariant vdropList, int dropItemIndex) -{ - JASPListControl * dropList = qobject_cast(vdropList.value()); - ListModelDraggable * dropModel = !dropList ? qobject_cast(getRelatedModel()) - : qobject_cast(dropList->model()); - - if (!dropModel) - { - Log::log() << "No drop element!" << std::endl; - return; - } - - QList vvindexes = vindexes.toList(); - if (!vvindexes.empty()) - { - _tempIndexes.clear(); - for (QVariant &index : vvindexes) - _tempIndexes.push_back(index.toInt()); - } - else - _tempIndexes = vindexes.value >(); - - _tempDropModel = dropModel; - _tempDropItemIndex = dropItemIndex; - // the call to itemsDropped is called from an item that will be removed (the items of the variable list - // will be re-created). So itemsDropped should not call _moveItems directly. - QTimer::singleShot(0, this, SLOT(moveItemsDelayedHandler())); -} - -void VariablesListBase::moveItemsDelayedHandler() -{ - moveItems(_tempIndexes, _tempDropModel, _tempDropItemIndex); -} - -void VariablesListBase::moveItems(QList &indexes, ListModelDraggable* targetModel, int dropItemIndex) -{ - if (targetModel && indexes.size() > 0) - { - std::sort(indexes.begin(), indexes.end()); - if (form()) form()->blockValueChangeSignal(true); - - ListModelDraggable* sourceModel = _draggableModel; - if (sourceModel == targetModel) - sourceModel->moveTerms(indexes, dropItemIndex); - else - { - bool refreshSource = false; - Terms termsAdded; - Terms removedTermsWhenAdding; - QList indexAdded = indexes; - - if (!sourceModel->copyTermsWhenDropped()) - { - Terms terms = sourceModel->termsFromIndexes(indexes); - if (terms.size() == 0) - Log::log() << "No terms found when trying to move them" << std::endl; - - termsAdded = targetModel->canAddTerms(terms); - - if (termsAdded.size() > 0) - removedTermsWhenAdding = targetModel->addTerms(termsAdded, dropItemIndex); - - if (termsAdded.size() != terms.size()) - { - indexAdded.clear(); - for (int i = 0; i < indexes.size(); i++) - { - int index = indexes[i]; - if (i < int(terms.size())) - { - const Term& term = terms[size_t(i)]; - if (termsAdded.contains(term)) - indexAdded.append(index); - } - } - refreshSource = true; - } - } - - if (!targetModel->copyTermsWhenDropped()) - { - if (indexAdded.size() > 0) - { - sourceModel->removeTerms(indexAdded); - refreshSource = false; - } - if (removedTermsWhenAdding.size() > 0) - { - sourceModel->addTerms(removedTermsWhenAdding); - refreshSource = false; - } - } - - if (refreshSource) - sourceModel->refresh(); - } - - if (form()) form()->blockValueChangeSignal(false); - } - else - { - Log::log() << (!targetModel ? "no dropModel" : "no indexes") << std::endl; - } -} - -void VariablesListBase::setDropKeys(const QStringList &dropKeys) -{ - if (dropKeys != _dropKeys) - { - _dropKeys = dropKeys; - _setRelations(); - emit dropKeysChanged(); - } - -} - -ListModel *VariablesListBase::getRelatedModel() -{ - ListModel* result = nullptr; - if (dropKeys().count() > 0) - { - QString relatedName = dropKeys()[0]; // The first key gives the default drop item. - if (_parentListView) - { - JASPListControl* relatedControl = qobject_cast(_parentListView->model()->getRowControl(_parentListViewKey, relatedName)); - if (relatedControl) - result = relatedControl->model(); - } - if (!result && form()) result = form()->getModel(relatedName); - } - - return result; -} - -void VariablesListBase::termsChangedHandler() -{ - setColumnsTypes(model()->termsTypes()); - setColumnsNames(model()->terms().asQList()); - - if (_boundControl) _boundControl->resetBoundValue(); - else JASPListControl::termsChangedHandler(); -} - -void VariablesListBase::_setAllowedVariables() -{ - QSet implicitAllowedTypes; - - // The implicitAllowedTypes is either the allowedColumns if they are explicitely defined - // or the suggestedColumns with extra permitted types, with these rules: - // . if suggestedType contains the scale type, then nomincal & ordinal types are then also allowed. - // . if suggestedType contains the nomincal type, then nominalText & ordinal types are also allowed. - - auto listToSet = [](QStringList l) { return QSet (l.constBegin(), l.constEnd()); }; - if (!allowedColumns().empty()) - implicitAllowedTypes = listToSet(allowedColumns()); - else if (!suggestedColumns().empty()) - { - implicitAllowedTypes = listToSet(suggestedColumns()); - if (suggestedColumns().contains("scale")) - { - implicitAllowedTypes.insert("nominal"); - implicitAllowedTypes.insert("ordinal"); - } - if (suggestedColumns().contains("nominal")) - { - implicitAllowedTypes.insert("nominalText"); - implicitAllowedTypes.insert("ordinal"); - } - } - - _variableTypesAllowed.clear(); - for (const QString& typeStr: implicitAllowedTypes) - _variableTypesAllowed.insert(columnTypeFromString(fq(typeStr), columnType::unknown)); - - // The suggectedColumnsIcons indicates which columns are allowed in the VariableList view. - // It shows per default the suggested columns list, but if empty, it shows the alloaed columns list. - QStringList iconTypeList, - columnTypes = allowedColumns().isEmpty() ? suggestedColumns() : allowedColumns(); - for (const QString& columnTypeStr : columnTypes) - { - columnType type = columnTypeFromString(fq(columnTypeStr), columnType::unknown); - if (type != columnType::unknown) - iconTypeList.push_back(VariableInfo::getIconFile(type, VariableInfo::InactiveIconType)); - } - setSuggestedColumnsIcons(iconTypeList); - - if (form() && form()->initialized()) - // If the allowed columns have changed, then refresh the model so that columns that are not allowed anymore are removed. - model()->refresh(); -} - -void VariablesListBase::_setRelations() -{ - ListModelAssignedInterface* assignedModel = qobject_cast(_draggableModel); - if (assignedModel) - { - ListModel* relatedModel = getRelatedModel(); - if (relatedModel) - { - ListModelAvailableInterface* availableModel = dynamic_cast(relatedModel); - if (!availableModel) - addControlError(tr("Wrong kind of source for VariableList %1").arg(name())); - else - { - assignedModel->setAvailableModel(availableModel); - availableModel->addAssignedModel(assignedModel); - addDependency(availableModel->listView()); - setContainsVariables(); - setContainsInteractions(); - } - } - } -} - -void VariablesListBase::interactionHighOrderHandler(JASPControl* checkBoxControl) -{ - CheckBoxBase* checkBox = qobject_cast(checkBoxControl); - if (checkBox == nullptr) - { - Log::log() << "interactionHighOrderHandler is called with a control that is not a CheckBox!" << std::endl; - return; - } - - bool checked = checkBox->checked(); - if (form()) form()->blockValueChangeSignal(true); - - // if a higher order interaction is specified as nuisance, then all lower order terms should be changed to nuisance as well - Term keyTerm = Term::readTerm(checkBoxControl->parentListViewKey()); - for (const Term& otherTerm : _draggableModel->terms()) - { - if (otherTerm == keyTerm) - continue; - - RowControls* rowControls = _draggableModel->getRowControls(otherTerm.asQString()); - if (!rowControls) continue; // Apparently the controls are not created yet for this row. Does not matter: this function will be called when they are created - CheckBoxBase* otherCheckBox = qobject_cast(rowControls->getJASPControl(_interactionHighOrderCheckBox)); - bool otherChecked = otherCheckBox->checked(); - - if (checked) - { - if (keyTerm.containsAll(otherTerm) && !otherChecked) - { - otherCheckBox->setChecked(true); - otherCheckBox->setBoundValue(Json::Value(true)); - } - } - else - { - if (otherTerm.containsAll(keyTerm) && otherChecked) - { - otherCheckBox->setChecked(false); - otherCheckBox->setBoundValue(Json::Value(false)); - } - } - } - - if (form()) form()->blockValueChangeSignal(false); -} - - diff --git a/QMLComponents/controls/variableslistbase.h b/QMLComponents/controls/variableslistbase.h deleted file mode 100644 index 7e6c0fd33fa..00000000000 --- a/QMLComponents/controls/variableslistbase.h +++ /dev/null @@ -1,131 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef VARIABLESLISTBASE_H -#define VARIABLESLISTBASE_H - -#include "jasplistcontrol.h" -#include -#include - -class ListModelDraggable; -class CheckBoxBase; - -class VariablesListBase : public JASPListControl, public BoundControl -{ - Q_OBJECT - - Q_PROPERTY( ListViewType listViewType READ listViewType WRITE setListViewType NOTIFY listViewTypeChanged ) - Q_PROPERTY( int columns READ columns WRITE setColumns NOTIFY columnsChanged ) - Q_PROPERTY( QStringList allowedColumns READ allowedColumns WRITE setAllowedColumns NOTIFY allowedColumnsChanged ) - Q_PROPERTY( QStringList suggestedColumns READ suggestedColumns WRITE setSuggestedColumns NOTIFY suggestedColumnsChanged ) - Q_PROPERTY( QStringList suggestedColumnsIcons READ suggestedColumnsIcons NOTIFY suggestedColumnsIconsChanged ) - Q_PROPERTY( QStringList columnsTypes READ columnsTypes NOTIFY columnsTypesChanged ) - Q_PROPERTY( QStringList columnsNames READ columnsNames NOTIFY columnsNamesChanged ) - Q_PROPERTY( QStringList dropKeys READ dropKeys WRITE setDropKeys NOTIFY dropKeysChanged ) - Q_PROPERTY( QString interactionHighOrderCheckBox READ interactionHighOrderCheckBox WRITE setInteractionHighOrderCheckBox NOTIFY interactionHighOrderCheckBoxChanged ) - - -public: - VariablesListBase(QQuickItem* parent = nullptr); - - void setUp() override; - ListModel* model() const override; - ListModelDraggable* draggableModel() const { return _draggableModel; } - void setUpModel() override; - void bindTo(const Json::Value &value) override { _boundControl->bindTo(value); } - const Json::Value& boundValue() const override { return _boundControl->boundValue(); } - bool isJsonValid(const Json::Value& optionValue) const override { return _boundControl->isJsonValid(optionValue); } - void resetBoundValue() override { return _boundControl->resetBoundValue(); } - Json::Value createJson() const override { return _boundControl->createJson(); } - Json::Value createMeta() const override { return _boundControl->createMeta(); } - void setBoundValue(const Json::Value& value, - bool emitChange = true) override { return _boundControl->setBoundValue(value, emitChange); } - const Json::Value& defaultBoundValue() const override { return _boundControl->defaultBoundValue(); } - void setDefaultBoundValue(const Json::Value& defaultValue) override { _boundControl->setDefaultBoundValue(defaultValue); } - - ListViewType listViewType() const { return _listViewType; } - BoundControl* boundControl() override { return _boundControl; } - int columns() const { return _columns; } - const QStringList& allowedColumns() const { return _allowedColumns; } - const QStringList& suggestedColumns() const { return _suggestedColumns; } - const QStringList& suggestedColumnsIcons() const { return _suggestedColumnsIcons; } - const QStringList& columnsTypes() const { return _columnsTypes; } - const QStringList& columnsNames() const { return _columnsNames; } - const QStringList& dropKeys() const { return _dropKeys; } - const QString& interactionHighOrderCheckBox() const { return _interactionHighOrderCheckBox; } - bool addRowControl(const QString& key, JASPControl* control) override; - void moveItems(QList &indexes, ListModelDraggable* dropModel, int dropItemIndex = -1); - -signals: - void listViewTypeChanged(); - void columnsChanged(); - void allowedColumnsChanged(); - void suggestedColumnsChanged(); - void suggestedColumnsIconsChanged(); - void columnsTypesChanged(); - void columnsNamesChanged(); - void dropKeysChanged(); - void interactionHighOrderCheckBoxChanged(); - -protected: - GENERIC_SET_FUNCTION(ListViewType, _listViewType, listViewTypeChanged, ListViewType ) - GENERIC_SET_FUNCTION(Columns, _columns, columnsChanged, int ) - GENERIC_SET_FUNCTION(AllowedColumns, _allowedColumns, allowedColumnsChanged, QStringList ) - GENERIC_SET_FUNCTION(SuggestedColumns, _suggestedColumns, suggestedColumnsChanged, QStringList ) - GENERIC_SET_FUNCTION(SuggestedColumnsIcons, _suggestedColumnsIcons, suggestedColumnsIconsChanged, QStringList ) - GENERIC_SET_FUNCTION(ColumnsTypes, _columnsTypes, columnsTypesChanged, QStringList ) - GENERIC_SET_FUNCTION(ColumnsNames, _columnsNames, columnsNamesChanged, QStringList ) - GENERIC_SET_FUNCTION(InteractionHighOrderCheckBox, _interactionHighOrderCheckBox, interactionHighOrderCheckBoxChanged, QString ) - - void _setInitialized(const Json::Value& value = Json::nullValue) override; - void setDropKeys(const QStringList& dropKeys); - ListModel* getRelatedModel(); - - ListModelDraggable* _draggableModel = nullptr; - ListViewType _listViewType = ListViewType::AssignedVariables; - BoundControl* _boundControl = nullptr; - -protected slots: - void termsChangedHandler() override; - void moveItemsDelayedHandler(); - void itemDoubleClickedHandler(int index); - void itemsDroppedHandler(QVariant indexes, QVariant vdropList, int dropItemIndex); - void interactionHighOrderHandler(JASPControl* checkBoxControl); - -private: - void _setAllowedVariables(); - void _setRelations(); - - int _columns = 1; - - ListModelDraggable * _tempDropModel = nullptr; - QList _tempIndexes; - int _tempDropItemIndex; - - QStringList _allowedColumns, - _suggestedColumns, - _suggestedColumnsIcons, - _columnsTypes, - _columnsNames, - _dropKeys; - QString _interactionHighOrderCheckBox; - -}; - -#endif // VARIABLESLISTBASE_H diff --git a/QMLComponents/jasptheme.cpp b/QMLComponents/jasptheme.cpp deleted file mode 100644 index ce14caf9371..00000000000 --- a/QMLComponents/jasptheme.cpp +++ /dev/null @@ -1,1320 +0,0 @@ -#include "jasptheme.h" -#include "log.h" -#include "qutils.h" -#include "preferencesmodelbase.h" -#include - -JaspTheme * JaspTheme::_currentTheme = nullptr; -QFontMetricsF JaspTheme::_fontMetrics = QFontMetricsF(QFont()); - -std::map JaspTheme::_themes; - -JaspTheme::JaspTheme(QQuickItem * parent) : QQuickItem(parent) -{ - connectSizeDistancesToUiScaleChanged(); - - if(_currentTheme == nullptr) - setCurrentTheme(this); - - //_fontCode.setStyleHint(QFont::Monospace); // Cannot be set in QML https://bugreports.qt.io/browse/QTBUG-38931 - - updateFontMetrics(); - - connect(this, &JaspTheme::uiScaleChanged, this, &JaspTheme::updateFontMetrics ); -} - -JaspTheme::~JaspTheme() -{ - if(_currentTheme == this) - setCurrentTheme(nullptr); -} - -#define CONNECT_UISCALE(toThis) connect(this, &JaspTheme::uiScaleChanged, this, &JaspTheme::toThis) - -void JaspTheme::connectSizeDistancesToUiScaleChanged() -{ - CONNECT_UISCALE(borderRadiusChanged); - CONNECT_UISCALE(shadowRadiusChanged); - CONNECT_UISCALE(itemPaddingChanged); - CONNECT_UISCALE(jaspControlPaddingChanged); - CONNECT_UISCALE(ribbonButtonPaddingChanged); - CONNECT_UISCALE(groupContentPaddingChanged); - CONNECT_UISCALE(rowSpacingChanged); - CONNECT_UISCALE(rowGridSpacingChanged); - CONNECT_UISCALE(rowGroupSpacingChanged); - CONNECT_UISCALE(columnGridSpacingChanged); - CONNECT_UISCALE(columnGroupSpacingChanged); - CONNECT_UISCALE(indentationLengthChanged); - CONNECT_UISCALE(labelSpacingChanged); - CONNECT_UISCALE(menuSpacingChanged); - CONNECT_UISCALE(menuPaddingChanged); - CONNECT_UISCALE(generalAnchorMarginChanged); - CONNECT_UISCALE(generalMenuMarginChanged); - CONNECT_UISCALE(titleBottomMarginChanged); - CONNECT_UISCALE(contentMarginChanged); - CONNECT_UISCALE(subOptionOffsetChanged); - CONNECT_UISCALE(minPanelWidthChanged); - CONNECT_UISCALE(resultWidthChanged); - CONNECT_UISCALE(formWidthChanged); - CONNECT_UISCALE(iconSizeChanged); - CONNECT_UISCALE(formMarginChanged); - CONNECT_UISCALE(formExpanderHeaderHeightChanged); - CONNECT_UISCALE(sliderWidthChanged); - CONNECT_UISCALE(sliderLengthChanged); - CONNECT_UISCALE(switchHeightChanged); - CONNECT_UISCALE(spinBoxHeightChanged); - CONNECT_UISCALE(spinBoxWidthChanged); - CONNECT_UISCALE(comboBoxHeightChanged); - CONNECT_UISCALE(textFieldWidthChanged); - CONNECT_UISCALE(textFieldHeightChanged); - CONNECT_UISCALE(numericFieldWidthChanged); - CONNECT_UISCALE(splitHandleWidthChanged); - CONNECT_UISCALE(subMenuIconHeightChanged); - CONNECT_UISCALE(ribbonButtonHeightChanged); - CONNECT_UISCALE(variablesListTitleChanged); - CONNECT_UISCALE(sliderHandleDiameterChanged); - CONNECT_UISCALE(defaultTextAreaHeightChanged); - CONNECT_UISCALE(jaspControlHighlightWidthChanged); - CONNECT_UISCALE(defaultVariablesFormHeightChanged); - CONNECT_UISCALE(defaultSingleItemListHeightChanged); - CONNECT_UISCALE(defaultRectangularButtonHeightChanged); - CONNECT_UISCALE(smallDefaultVariablesFormHeightChanged); - CONNECT_UISCALE(messageBoxButtonHeightChanged); - CONNECT_UISCALE(scrollbarBoxWidthBigChanged); - CONNECT_UISCALE(scrollbarBoxWidthChanged); - CONNECT_UISCALE(menuItemHeightChanged); - CONNECT_UISCALE(menuGroupTitleHeightChanged); - CONNECT_UISCALE(menuHeaderHeightChanged); -} - -void JaspTheme::setCurrentTheme(JaspTheme * theme) -{ - if(theme == _currentTheme) - return; - - _currentTheme = theme; - - if(_currentTheme) - { - _currentTheme->updateFontMetrics(); - emit _currentTheme->currentThemeReady(theme); - } -} - -void JaspTheme::setCurrentThemeFromName(QString name) -{ - if(name == "") - return; - - //Log::log() << "void JaspTheme::setCurrentThemeFromName( "<< name << " )" << std::endl; - - if(_themes.count(name) == 0) - { - Log::log() << "Could not find theme " << name << std::endl; - return; - } - - setCurrentTheme(_themes[name]); -} - -void JaspTheme::initializeUIScales() -{ - for(auto& keyval : _themes) - keyval.second->uiScaleHandler(); -} - -void JaspTheme::setRibbonScaleHovered(float ribbonScaleHovered) -{ - - if (qFuzzyCompare(_ribbonScaleHovered, ribbonScaleHovered)) - return; - - _ribbonScaleHovered = ribbonScaleHovered; - emit ribbonScaleHoveredChanged(_ribbonScaleHovered); -} - -void JaspTheme::setWhite(QColor white) -{ - if (_white == white) - return; - - _white = white; - emit whiteChanged(_white); -} - -void JaspTheme::setWhiteBroken(QColor whiteBroken) -{ - if (_whiteBroken == whiteBroken) - return; - - _whiteBroken = whiteBroken; - emit whiteBrokenChanged(_whiteBroken); -} - -void JaspTheme::setBlack(QColor black) -{ - if (_black == black) - return; - - _black = black; - emit blackChanged(_black); -} - -void JaspTheme::setGray(QColor gray) -{ - if (_gray == gray) - return; - - _gray = gray; - emit grayChanged(_gray); -} - -void JaspTheme::setGrayDarker(QColor grayDarker) -{ - if (_grayDarker == grayDarker) - return; - - _grayDarker = grayDarker; - emit grayDarkerChanged(_grayDarker); -} - -void JaspTheme::setGrayLighter(QColor grayLighter) -{ - if (_grayLighter == grayLighter) - return; - - _grayLighter = grayLighter; - emit grayLighterChanged(_grayLighter); -} - -void JaspTheme::setGrayMuchLighter(QColor grayMuchLighter) -{ - if (_grayMuchLighter == grayMuchLighter) - return; - - _grayMuchLighter = grayMuchLighter; - emit grayMuchLighterChanged(_grayMuchLighter); -} - -void JaspTheme::setGrayVeryMuchLighter(QColor grayVeryMuchLighter) -{ - if (_grayVeryMuchLighter == grayVeryMuchLighter) - return; - - _grayVeryMuchLighter = grayVeryMuchLighter; - emit grayVeryMuchLighterChanged(_grayVeryMuchLighter); -} - -void JaspTheme::setBlue(QColor blue) -{ - if (_blue == blue) - return; - - _blue = blue; - emit blueChanged(_blue); -} - -void JaspTheme::setBlueDarker(QColor blueDarker) -{ - if (_blueDarker == blueDarker) - return; - - _blueDarker = blueDarker; - emit blueDarkerChanged(_blueDarker); -} - -void JaspTheme::setBlueLighter(QColor blueLighter) -{ - if (_blueLighter == blueLighter) - return; - - _blueLighter = blueLighter; - emit blueLighterChanged(_blueLighter); -} - -void JaspTheme::setBlueMuchLighter(QColor blueMuchLighter) -{ - if (_blueMuchLighter == blueMuchLighter) - return; - - _blueMuchLighter = blueMuchLighter; - emit blueMuchLighterChanged(_blueMuchLighter); -} - -void JaspTheme::setRed(QColor red) -{ - if (_red == red) - return; - - _red = red; - emit redChanged(_red); -} - -void JaspTheme::setRedDarker(QColor redDarker) -{ - if (_redDarker == redDarker) - return; - - _redDarker = redDarker; - emit redDarkerChanged(_redDarker); -} - -void JaspTheme::setGreen(QColor green) -{ - if (_green == green) - return; - - _green = green; - emit greenChanged(_green); -} - -void JaspTheme::setYellowLight(QColor yellowLight) -{ - if (_yellowLight == yellowLight) - return; - - _yellowLight = yellowLight; - emit yellowLightChanged(_yellowLight); -} - -void JaspTheme::setRose(QColor rose) -{ - if (_rose == rose) - return; - - _rose = rose; - emit roseChanged(_rose); -} - -void JaspTheme::setRoseLight(QColor roseLight) -{ - if (_roseLight == roseLight) - return; - - _roseLight = roseLight; - emit roseLightChanged(_roseLight); -} - -void JaspTheme::setCyan(QColor cyan) -{ - if (_cyan == cyan) - return; - - _cyan = cyan; - emit cyanChanged(_cyan); -} - -void JaspTheme::setShadow(QColor shadow) -{ - if (_shadow == shadow) - return; - - _shadow = shadow; - emit shadowChanged(_shadow); -} - - -void JaspTheme::setJaspBlue(QColor jaspBlue) -{ - if (_jaspBlue == jaspBlue) - return; - - _jaspBlue = jaspBlue; - emit jaspBlueChanged(_jaspBlue); -} - -void JaspTheme::setJaspGreen(QColor jaspGreen) -{ - if (_jaspGreen == jaspGreen) - return; - - _jaspGreen = jaspGreen; - emit jaspGreenChanged(_jaspGreen); -} - -void JaspTheme::setTextEnabled(QColor textEnabled) -{ - if (_textEnabled == textEnabled) - return; - - _textEnabled = textEnabled; - emit textEnabledChanged(_textEnabled); -} - -void JaspTheme::setTextDisabled(QColor textDisabled) -{ - if (_textDisabled == textDisabled) - return; - - _textDisabled = textDisabled; - emit textDisabledChanged(_textDisabled); -} - -void JaspTheme::setUiBackground(QColor uiBackground) -{ - if (_uiBackground == uiBackground) - return; - - _uiBackground = uiBackground; - emit uiBackgroundChanged(_uiBackground); -} - -void JaspTheme::setUiBorder(QColor uiBorder) -{ - if (_uiBorder == uiBorder) - return; - - _uiBorder = uiBorder; - emit uiBorderChanged(_uiBorder); -} - -void JaspTheme::setFileMenuColorBackground(QColor fileMenuColorBackground) -{ - if (_fileMenuColorBackground == fileMenuColorBackground) - return; - - _fileMenuColorBackground = fileMenuColorBackground; - emit fileMenuColorBackgroundChanged(_fileMenuColorBackground); -} - -void JaspTheme::setFileMenuLightBorder(QColor fileMenuLightBorder) -{ - if (_fileMenuLightBorder == fileMenuLightBorder) - return; - - _fileMenuLightBorder = fileMenuLightBorder; - emit fileMenuLightBorderChanged(_fileMenuLightBorder); -} - -void JaspTheme::setButtonColor(QColor buttonColor) -{ - if (_buttonColor == buttonColor) - return; - - _buttonColor = buttonColor; - emit buttonColorChanged(_buttonColor); -} - -void JaspTheme::setButtonColorHovered(QColor buttonColorHovered) -{ - if (_buttonColorHovered == buttonColorHovered) - return; - - _buttonColorHovered = buttonColorHovered; - emit buttonColorHoveredChanged(_buttonColorHovered); -} - -void JaspTheme::setButtonColorPressed(QColor buttonColorPressed) -{ - if (_buttonColorPressed == buttonColorPressed) - return; - - _buttonColorPressed = buttonColorPressed; - emit buttonColorPressedChanged(_buttonColorPressed); -} - -void JaspTheme::setButtonBorderColor(QColor buttonBorderColor) -{ - if (_buttonBorderColor == buttonBorderColor) - return; - - _buttonBorderColor = buttonBorderColor; - emit buttonBorderColorChanged(_buttonBorderColor); -} - -void JaspTheme::setButtonBorderColorHovered(QColor buttonBorderColorHovered) -{ - if (_buttonBorderColorHovered == buttonBorderColorHovered) - return; - - _buttonBorderColorHovered = buttonBorderColorHovered; - emit buttonBorderColorHoveredChanged(_buttonBorderColorHovered); -} - -void JaspTheme::setItemHighlight(QColor itemHighlight) -{ - if (_itemHighlight == itemHighlight) - return; - - _itemHighlight = itemHighlight; - emit itemHighlightChanged(_itemHighlight); -} - -void JaspTheme::setItemHoverColor(QColor itemHoverColor) -{ - if (_itemHoverColor == itemHoverColor) - return; - - _itemHoverColor = itemHoverColor; - emit itemHoverColorChanged(_itemHoverColor); -} - -void JaspTheme::setItemSelectedColor(QColor itemSelectedColor) -{ - if (_itemSelectedColor == itemSelectedColor) - return; - - _itemSelectedColor = itemSelectedColor; - emit itemSelectedColorChanged(_itemSelectedColor); -} - -void JaspTheme::setItemSelectedNoFocusColor(QColor itemSelectedNoFocusColor) -{ - if (_itemSelectedNoFocusColor == itemSelectedNoFocusColor) - return; - - _itemSelectedNoFocusColor = itemSelectedNoFocusColor; - emit itemSelectedNoFocusColorChanged(_itemSelectedNoFocusColor); -} - -void JaspTheme::setBorderColor(QColor borderColor) -{ - if (_borderColor == borderColor) - return; - - _borderColor = borderColor; - emit borderColorChanged(_borderColor); -} - -void JaspTheme::setFocusBorderColor(QColor focusBorderColor) -{ - if (_focusBorderColor == focusBorderColor) - return; - - _focusBorderColor = focusBorderColor; - emit focusBorderColorChanged(_focusBorderColor); -} - -void JaspTheme::setDependencyBorderColor(QColor dependencyBorderColor) -{ - if (_dependencyBorderColor == dependencyBorderColor) - return; - - _dependencyBorderColor = dependencyBorderColor; - emit dependencyBorderColorChanged(_dependencyBorderColor); -} - -void JaspTheme::setDependencySelectedColor(QColor dependencySelectedColor) -{ - if (_dependencySelectedColor == dependencySelectedColor) - return; - - _dependencySelectedColor = dependencySelectedColor; - emit dependencySelectedColorChanged(_dependencySelectedColor); -} - -void JaspTheme::setContainsDragBorderColor(QColor containsDragBorderColor) -{ - if (_containsDragBorderColor == containsDragBorderColor) - return; - - _containsDragBorderColor = containsDragBorderColor; - emit containsDragBorderColorChanged(_containsDragBorderColor); -} - -void JaspTheme::setAnalysisBackgroundColor(QColor analysisBackgroundColor) -{ - if (_analysisBackgroundColor == analysisBackgroundColor) - return; - - _analysisBackgroundColor = analysisBackgroundColor; - emit analysisBackgroundColorChanged(_analysisBackgroundColor); -} - -void JaspTheme::setControlBackgroundColor(QColor controlBackgroundColor) -{ - if (_controlBackgroundColor == controlBackgroundColor) - return; - - _controlBackgroundColor = controlBackgroundColor; - emit controlBackgroundColorChanged(_controlBackgroundColor); -} - -void JaspTheme::setControlDisabledBackgroundColor(QColor controlDisabledBackgroundColor) -{ - if (_controlDisabledBackgroundColor == controlDisabledBackgroundColor) - return; - - _controlDisabledBackgroundColor = controlDisabledBackgroundColor; - emit controlDisabledBackgroundColorChanged(_controlDisabledBackgroundColor); -} - -void JaspTheme::setRowEvenColor(QColor rowEvenColor) -{ - if (_rowEvenColor == rowEvenColor) - return; - - _rowEvenColor = rowEvenColor; - emit rowEvenColorChanged(_rowEvenColor); -} - -void JaspTheme::setRowOnevenColor(QColor rowOnevenColor) -{ - if (_rowOnevenColor == rowOnevenColor) - return; - - _rowOnevenColor = rowOnevenColor; - emit rowOnevenColorChanged(_rowOnevenColor); -} - -void JaspTheme::setControlErrorBackgroundColor(QColor controlErrorBackgroundColor) -{ - if (_controlErrorBackgroundColor == controlErrorBackgroundColor) - return; - - _controlErrorBackgroundColor = controlErrorBackgroundColor; - emit controlErrorBackgroundColorChanged(_controlErrorBackgroundColor); -} - -void JaspTheme::setControlErrorTextColor(QColor controlErrorTextColor) -{ - if (_controlErrorTextColor == controlErrorTextColor) - return; - - _controlErrorTextColor = controlErrorTextColor; - emit controlErrorTextColorChanged(_controlErrorTextColor); -} - -void JaspTheme::setControlWarningBackgroundColor(QColor controlWarningBackgroundColor) -{ - if (_controlWarningBackgroundColor == controlWarningBackgroundColor) - return; - - _controlWarningBackgroundColor = controlWarningBackgroundColor; - emit controlWarningBackgroundColorChanged(_controlWarningBackgroundColor); -} - -void JaspTheme::setControlWarningTextColor(QColor controlWarningTextColor) -{ - if (_controlWarningTextColor == controlWarningTextColor) - return; - - _controlWarningTextColor = controlWarningTextColor; - emit controlWarningTextColorChanged(_controlWarningTextColor); -} - -void JaspTheme::setButtonBackgroundColor(QColor buttonBackgroundColor) -{ - if (_buttonBackgroundColor == buttonBackgroundColor) - return; - - _buttonBackgroundColor = buttonBackgroundColor; - emit buttonBackgroundColorChanged(_buttonBackgroundColor); -} - -void JaspTheme::setTooltipBackgroundColor(QColor tooltipBackgroundColor) -{ - if (_tooltipBackgroundColor == tooltipBackgroundColor) - return; - - _tooltipBackgroundColor = tooltipBackgroundColor; - emit tooltipBackgroundColorChanged(_tooltipBackgroundColor); -} - -void JaspTheme::setDebugBackgroundColor(QColor debugBackgroundColor) -{ - if (_debugBackgroundColor == debugBackgroundColor) - return; - - _debugBackgroundColor = debugBackgroundColor; - emit debugBackgroundColorChanged(_debugBackgroundColor); -} - -void JaspTheme::setErrorMessagesBackgroundColor(QColor errorMessagesBackgroundColor) -{ - if (_errorMessagesBackgroundColor == errorMessagesBackgroundColor) - return; - - _errorMessagesBackgroundColor = errorMessagesBackgroundColor; - emit errorMessagesBackgroundColorChanged(_errorMessagesBackgroundColor); -} - -void JaspTheme::setSliderPartOn(QColor sliderPartOn) -{ - if (_sliderPartOn == sliderPartOn) - return; - - _sliderPartOn = sliderPartOn; - emit sliderPartOnChanged(_sliderPartOn); -} - -void JaspTheme::setSliderPartOff(QColor sliderPartOff) -{ - if (_sliderPartOff == sliderPartOff) - return; - - _sliderPartOff = sliderPartOff; - emit sliderPartOffChanged(_sliderPartOff); -} - -void JaspTheme::setAltNavTagColor(QColor altNavTagColor) -{ - if (_altNavTagColor == altNavTagColor) - return; - - _altNavTagColor = altNavTagColor; - emit altNavTagColorChanged(_altNavTagColor); -} - -void JaspTheme::setBorderRadius(theme_distanceType borderRadius) -{ - if (_borderRadius == borderRadius) - return; - - _borderRadius = borderRadius; - emit borderRadiusChanged(); -} - -void JaspTheme::setShadowRadius(theme_distanceType shadowRadius) -{ - if (_shadowRadius == shadowRadius) - return; - - _shadowRadius = shadowRadius; - emit shadowRadiusChanged(); -} - -void JaspTheme::setItemPadding(theme_distanceType itemPadding) -{ - if (_itemPadding == itemPadding) - return; - - _itemPadding = itemPadding; - emit itemPaddingChanged(); -} - -void JaspTheme::setJaspControlPadding(theme_distanceType jaspControlPadding) -{ - if (_jaspControlPadding == jaspControlPadding) - return; - - _jaspControlPadding = jaspControlPadding; - emit jaspControlPaddingChanged(); -} - -void JaspTheme::setRibbonButtonPadding(theme_distanceType ribbonButtonPadding) -{ - if (_ribbonButtonPadding == ribbonButtonPadding) - return; - - _ribbonButtonPadding = ribbonButtonPadding; - emit ribbonButtonPaddingChanged(); -} - -void JaspTheme::setGroupContentPadding(theme_distanceType groupContentPadding) -{ - if (_groupContentPadding == groupContentPadding) - return; - - _groupContentPadding = groupContentPadding; - emit groupContentPaddingChanged(); -} - -void JaspTheme::setRowSpacing(theme_distanceType rowSpacing) -{ - if (_rowSpacing == rowSpacing) - return; - - _rowSpacing = rowSpacing; - emit rowSpacingChanged(); -} - -void JaspTheme::setRowGridSpacing(theme_distanceType rowGridSpacing) -{ - if (_rowGridSpacing == rowGridSpacing) - return; - - _rowGridSpacing = rowGridSpacing; - emit rowGridSpacingChanged(); -} - -void JaspTheme::setRowGroupSpacing(theme_distanceType rowGroupSpacing) -{ - if (_rowGroupSpacing == rowGroupSpacing) - return; - - _rowGroupSpacing = rowGroupSpacing; - emit rowGroupSpacingChanged(); -} - -void JaspTheme::setColumnGridSpacing(theme_distanceType columnGridSpacing) -{ - if (_columnGridSpacing == columnGridSpacing) - return; - - _columnGridSpacing = columnGridSpacing; - emit columnGridSpacingChanged(); -} - -void JaspTheme::setColumnGroupSpacing(theme_distanceType columnGroupSpacing) -{ - if (_columnGroupSpacing == columnGroupSpacing) - return; - - _columnGroupSpacing = columnGroupSpacing; - emit columnGroupSpacingChanged(); -} - -void JaspTheme::setIndentationLength(theme_distanceType indentationLength) -{ - if (_indentationLength == indentationLength) - return; - - _indentationLength = indentationLength; - emit indentationLengthChanged(); -} - -void JaspTheme::setLabelSpacing(theme_distanceType labelSpacing) -{ - if (_labelSpacing == labelSpacing) - return; - - _labelSpacing = labelSpacing; - emit labelSpacingChanged(); -} - -void JaspTheme::setMenuSpacing(theme_distanceType menuSpacing) -{ - if (_menuSpacing == menuSpacing) - return; - - _menuSpacing = menuSpacing; - emit menuSpacingChanged(); -} - -void JaspTheme::setMenuPadding(theme_distanceType menuPadding) -{ - if (_menuPadding == menuPadding) - return; - - _menuPadding = menuPadding; - emit menuPaddingChanged(); -} - -void JaspTheme::setGeneralAnchorMargin(theme_distanceType generalAnchorMargin) -{ - if (_generalAnchorMargin == generalAnchorMargin) - return; - - _generalAnchorMargin = generalAnchorMargin; - emit generalAnchorMarginChanged(); -} - -void JaspTheme::setGeneralMenuMargin(theme_distanceType generalMenuMargin) -{ - if (_generalMenuMargin == generalMenuMargin) - return; - - _generalMenuMargin = generalMenuMargin; - emit generalMenuMarginChanged(); -} - -void JaspTheme::setTitleBottomMargin(theme_distanceType titleBottomMargin) -{ - if (_titleBottomMargin == titleBottomMargin) - return; - - _titleBottomMargin = titleBottomMargin; - emit titleBottomMarginChanged(); -} - -void JaspTheme::setContentMargin(theme_distanceType contentMargin) -{ - if (_contentMargin == contentMargin) - return; - - _contentMargin = contentMargin; - emit contentMarginChanged(); -} - -void JaspTheme::setSubOptionOffset(theme_distanceType subOptionOffset) -{ - if (_subOptionOffset == subOptionOffset) - return; - - _subOptionOffset = subOptionOffset; - emit subOptionOffsetChanged(); -} - -void JaspTheme::setMinPanelWidth(theme_sizeType minPanelWidth) -{ - if (_minPanelWidth == minPanelWidth) - return; - - _minPanelWidth = minPanelWidth; - emit minPanelWidthChanged(); -} - -void JaspTheme::setResultWidth(theme_sizeType resultWidth) -{ - if (_resultWidth == resultWidth) - return; - - _resultWidth = resultWidth; - emit resultWidthChanged(); -} - -void JaspTheme::setFormWidth(theme_sizeType formWidth) -{ - if (_formWidth == formWidth) - return; - - _formWidth = formWidth; - emit formWidthChanged(); -} - -void JaspTheme::setIconSize(theme_sizeType iconSize) -{ - if (_iconSize == iconSize) - return; - - _iconSize = iconSize; - emit iconSizeChanged(); -} - -void JaspTheme::setFormMargin(theme_sizeType formMargin) -{ - if (_formMargin == formMargin) - return; - - _formMargin = formMargin; - emit formMarginChanged(); -} - -void JaspTheme::setFormExpanderHeaderHeight(theme_sizeType formExpanderHeaderHeight) -{ - if (_formExpanderHeaderHeight == formExpanderHeaderHeight) - return; - - _formExpanderHeaderHeight = formExpanderHeaderHeight; - emit formExpanderHeaderHeightChanged(); -} - -void JaspTheme::setSliderWidth(theme_sizeType sliderWidth) -{ - if (_sliderWidth == sliderWidth) - return; - - _sliderWidth = sliderWidth; - emit sliderWidthChanged(); -} - -void JaspTheme::setSliderLength(theme_sizeType sliderLength) -{ - if (_sliderLength == sliderLength) - return; - - _sliderLength = sliderLength; - emit sliderLengthChanged(); -} - -void JaspTheme::setSwitchHeight(theme_sizeType switchHeight) -{ - if (_switchHeight == switchHeight) - return; - - _switchHeight = switchHeight; - emit switchHeightChanged(); -} - -void JaspTheme::setSpinBoxHeight(theme_sizeType spinBoxHeight) -{ - if (_spinBoxHeight == spinBoxHeight) - return; - - _spinBoxHeight = spinBoxHeight; - emit spinBoxHeightChanged(); -} - -void JaspTheme::setSpinBoxWidth(theme_sizeType spinBoxWidth) -{ - if (_spinBoxWidth == spinBoxWidth) - return; - - _spinBoxWidth = spinBoxWidth; - emit spinBoxWidthChanged(); -} - -void JaspTheme::setComboBoxHeight(theme_sizeType comboBoxHeight) -{ - if (_comboBoxHeight == comboBoxHeight) - return; - - _comboBoxHeight = comboBoxHeight; - emit comboBoxHeightChanged(); -} - -void JaspTheme::setTextFieldWidth(theme_sizeType textFieldWidth) -{ - if (_textFieldWidth == textFieldWidth) - return; - - _textFieldWidth = textFieldWidth; - emit textFieldWidthChanged(); -} - -void JaspTheme::setTextFieldHeight(theme_sizeType textFieldHeight) -{ - if (_textFieldHeight == textFieldHeight) - return; - - _textFieldHeight = textFieldHeight; - emit textFieldHeightChanged(); -} - -void JaspTheme::setNumericFieldWidth(theme_sizeType numericFieldWidth) -{ - if (_numericFieldWidth == numericFieldWidth) - return; - - _numericFieldWidth = numericFieldWidth; - emit numericFieldWidthChanged(); -} - -void JaspTheme::setSplitHandleWidth(theme_sizeType splitHandleWidth) -{ - if (_splitHandleWidth == splitHandleWidth) - return; - - _splitHandleWidth = splitHandleWidth; - emit splitHandleWidthChanged(); -} - -void JaspTheme::setSubMenuIconHeight(theme_sizeType subMenuIconHeight) -{ - if (_subMenuIconHeight == subMenuIconHeight) - return; - - _subMenuIconHeight = subMenuIconHeight; - emit subMenuIconHeightChanged(); -} - -void JaspTheme::setRibbonButtonHeight(theme_sizeType ribbonButtonHeight) -{ - if (_ribbonButtonHeight == ribbonButtonHeight) - return; - - _ribbonButtonHeight = ribbonButtonHeight; - emit ribbonButtonHeightChanged(); -} - -void JaspTheme::setVariablesListTitle(theme_sizeType variablesListTitle) -{ - if (_variablesListTitle == variablesListTitle) - return; - - _variablesListTitle = variablesListTitle; - emit variablesListTitleChanged(); -} - -void JaspTheme::setSliderHandleDiameter(theme_sizeType sliderHandleDiameter) -{ - if (_sliderHandleDiameter == sliderHandleDiameter) - return; - - _sliderHandleDiameter = sliderHandleDiameter; - emit sliderHandleDiameterChanged(); -} - -void JaspTheme::setDefaultTextAreaHeight(theme_sizeType defaultTextAreaHeight) -{ - if (_defaultTextAreaHeight == defaultTextAreaHeight) - return; - - _defaultTextAreaHeight = defaultTextAreaHeight; - emit defaultTextAreaHeightChanged(); -} - -void JaspTheme::setJaspControlHighlightWidth(theme_sizeType jaspControlHighlightWidth) -{ - if (_jaspControlHighlightWidth == jaspControlHighlightWidth) - return; - - _jaspControlHighlightWidth = jaspControlHighlightWidth; - emit jaspControlHighlightWidthChanged(); -} - -void JaspTheme::setDefaultVariablesFormHeight(theme_sizeType defaultVariablesFormHeight) -{ - if (_defaultVariablesFormHeight == defaultVariablesFormHeight) - return; - - _defaultVariablesFormHeight = defaultVariablesFormHeight; - emit defaultVariablesFormHeightChanged(); -} - -void JaspTheme::setDefaultSingleItemListHeight(theme_sizeType defaultSingleItemListHeight) -{ - if (_defaultSingleItemListHeight == defaultSingleItemListHeight) - return; - - _defaultSingleItemListHeight = defaultSingleItemListHeight; - emit defaultSingleItemListHeightChanged(); -} - -void JaspTheme::setDefaultRectangularButtonHeight(theme_sizeType defaultRectangularButtonHeight) -{ - if (_defaultRectangularButtonHeight == defaultRectangularButtonHeight) - return; - - _defaultRectangularButtonHeight = defaultRectangularButtonHeight; - emit defaultRectangularButtonHeightChanged(); -} - -void JaspTheme::setSmallDefaultVariablesFormHeight(theme_sizeType smallDefaultVariablesFormHeight) -{ - if (_smallDefaultVariablesFormHeight == smallDefaultVariablesFormHeight) - return; - - _smallDefaultVariablesFormHeight = smallDefaultVariablesFormHeight; - emit smallDefaultVariablesFormHeightChanged(); -} - -void JaspTheme::setMessageBoxButtonHeight(theme_sizeType messageBoxButtonHeight) -{ - if (_messageBoxButtonHeight == messageBoxButtonHeight) - return; - - _messageBoxButtonHeight = messageBoxButtonHeight; - emit messageBoxButtonHeightChanged(); -} - -void JaspTheme::setScrollbarBoxWidthBig(theme_sizeType scrollbarBoxWidthBig) -{ - if (_scrollbarBoxWidthBig == scrollbarBoxWidthBig) - return; - - _scrollbarBoxWidthBig = scrollbarBoxWidthBig; - emit scrollbarBoxWidthBigChanged(); -} - -void JaspTheme::setScrollbarBoxWidth(theme_sizeType scrollbarBoxWidth) -{ - if (_scrollbarBoxWidth == scrollbarBoxWidth) - return; - - _scrollbarBoxWidth = scrollbarBoxWidth; - emit scrollbarBoxWidthChanged(); -} - -void JaspTheme::setMenuItemHeight(theme_sizeType menuItemHeight) -{ - if (_menuItemHeight == menuItemHeight) - return; - - _menuItemHeight = menuItemHeight; - emit menuItemHeightChanged(); -} - -void JaspTheme::setMenuGroupTitleHeight(theme_sizeType menuGroupTitleHeight) -{ - if (_menuGroupTitleHeight == menuGroupTitleHeight) - return; - - _menuGroupTitleHeight = menuGroupTitleHeight; - emit menuGroupTitleHeightChanged(); -} - -void JaspTheme::setMenuHeaderHeight(theme_sizeType menuHeaderHeight) -{ - if (_menuHeaderHeight == menuHeaderHeight) - return; - - _menuHeaderHeight = menuHeaderHeight; - emit menuHeaderHeightChanged(); -} - -void JaspTheme::setHoverTime(theme_timeType hoverTime) -{ - if (_hoverTime == hoverTime) - return; - - _hoverTime = hoverTime; - emit hoverTimeChanged(_hoverTime); -} - -void JaspTheme::setFileMenuSlideDuration(theme_timeType fileMenuSlideDuration) -{ - if (_fileMenuSlideDuration == fileMenuSlideDuration) - return; - - _fileMenuSlideDuration = fileMenuSlideDuration; - emit fileMenuSlideDurationChanged(_fileMenuSlideDuration); -} - -void JaspTheme::setToolTipDelay(theme_timeType toolTipDelay) -{ - if (_toolTipDelay == toolTipDelay) - return; - - _toolTipDelay = toolTipDelay; - emit toolTipDelayChanged(_toolTipDelay); -} - -void JaspTheme::setToolTipTimeout(theme_timeType toolTipTimeout) -{ - if (_toolTipTimeout == toolTipTimeout) - return; - - _toolTipTimeout = toolTipTimeout; - emit toolTipTimeoutChanged(_toolTipTimeout); -} - -void JaspTheme::setFont(QFont font) -{ - if (_font == font) - return; - - _font = font; - emit fontChanged(_font); -} - -void JaspTheme::setFontLink(QFont fontLink) -{ - if (_fontLink == fontLink) - return; - - _fontLink = fontLink; - emit fontLinkChanged(_fontLink); -} - - -void JaspTheme::setFontLabel(QFont fontLabel) -{ - if (_fontLabel == fontLabel) - return; - - _fontLabel = fontLabel; - emit fontLabelChanged(_fontLabel); -} - -void JaspTheme::setFontRibbon(QFont fontRibbon) -{ - if (_fontRibbon == fontRibbon) - return; - - _fontRibbon = fontRibbon; - emit fontRibbonChanged(_fontRibbon); -} - -void JaspTheme::setFontGroupTitle(QFont fontGroupTitle) -{ - if (_fontGroupTitle == fontGroupTitle) - return; - - _fontGroupTitle = fontGroupTitle; - emit fontGroupTitleChanged(_fontGroupTitle); -} - -void JaspTheme::setFontPrefOptionsGroupTitle(QFont fontPrefOptionsGroupTitle) -{ - if (_fontPrefOptionsGroupTitle == fontPrefOptionsGroupTitle) - return; - - _fontPrefOptionsGroupTitle = fontPrefOptionsGroupTitle; - emit fontPrefOptionsGroupTitleChanged(_fontPrefOptionsGroupTitle); -} - -void JaspTheme::setIconPath(QString iconPath) -{ - if (_iconPath == iconPath) - return; - - _iconPath = iconPath; - emit iconPathChanged(_iconPath); -} - -void JaspTheme::setThemeName(QString themeName) -{ - if (_themeName == themeName) - return; - - if(themeName != "") - { - //Log::log() << "Inserting theme with name " << themeName << " into _themes" << std::endl; - - if(_themes.count(_themeName) > 0 && _themes[_themeName] == this) - _themes.erase(_themeName); - - if(_themes.count(themeName) == 0) //If there is space now, then insert it. Otherwise there was already a theme there with this name and that means we might still be going down the derivatory descent - _themes[themeName] = this; - } - - _themeName = themeName; - emit themeNameChanged(_themeName); - - setIconPath("qrc:/icons/" + _themeName + "/"); - - if(_currentTheme == this) - emit currentThemeNameChanged(); -} - -void JaspTheme::setFontRCode(QFont fontRCode) -{ - if (_fontRCode == fontRCode) - return; - - _fontRCode = fontRCode; - emit fontRCodeChanged(_fontRCode); -} - -void JaspTheme::setFontCode(QFont fontCode) -{ - if (_fontCode == fontCode) - return; - - _fontCode = fontCode; - emit fontCodeChanged(_fontCode); -} - -void JaspTheme::setFontALTNavTag(QFont fontALTNavTag) -{ - if (_fontALTNavTag == fontALTNavTag) - return; - - _fontALTNavTag = fontALTNavTag; - emit fontALTNavTagChanged(_fontALTNavTag); -} - -void JaspTheme::setIsDark(bool isDark) -{ - if (_isDark == isDark) - return; - - _isDark = isDark; - emit isDarkChanged(_isDark); -} - -void JaspTheme::uiScaleHandler() -{ - _uiScale = PreferencesModelBase::preferences()->uiScale(); - emit uiScaleChanged(_uiScale); -} - -void JaspTheme::maxFlickVeloHandler() -{ - _maximumFlickVelocity = PreferencesModelBase::preferences()->maxFlickVelocity(); - emit maximumFlickVelocityChanged(); -} - -QString JaspTheme::currentIconPath() -{ - if(_currentTheme) - return _currentTheme->iconPath(); - return "qrc:/icons/"; -} - -void JaspTheme::setDarkeningColour(QColor darkeningColour) -{ - if (_darkeningColour == darkeningColour) - return; - - _darkeningColour = darkeningColour; - emit darkeningColourChanged(_darkeningColour); -} - -void JaspTheme::updateFontMetrics() -{ - if(currentTheme()) - _fontMetrics = QFontMetricsF(currentTheme()->font()); -} diff --git a/QMLComponents/jasptheme.h b/QMLComponents/jasptheme.h deleted file mode 100644 index 497a161b205..00000000000 --- a/QMLComponents/jasptheme.h +++ /dev/null @@ -1,748 +0,0 @@ -#ifndef JASPTHEME_H -#define JASPTHEME_H - -#include -#include -#include -#include - -#define theme_distanceType float -#define theme_sizeType float -#define theme_timeType int - -/// Basic qquickItem we use a theme solution and to easily change theme by simply changing the one referenced in the global environment -/// Currently only two are instantiated by Desktop during loadQml() -class JaspTheme : public QQuickItem -{ - Q_OBJECT - - Q_PROPERTY(float uiScale READ uiScale NOTIFY uiScaleChanged ) - Q_PROPERTY(float ribbonScaleHovered READ ribbonScaleHovered WRITE setRibbonScaleHovered NOTIFY ribbonScaleHoveredChanged ) - - //Colors (base): - Q_PROPERTY(QColor white READ white WRITE setWhite NOTIFY whiteChanged ) - Q_PROPERTY(QColor whiteBroken READ whiteBroken WRITE setWhiteBroken NOTIFY whiteBrokenChanged ) - Q_PROPERTY(QColor black READ black WRITE setBlack NOTIFY blackChanged ) - Q_PROPERTY(QColor gray READ gray WRITE setGray NOTIFY grayChanged ) - Q_PROPERTY(QColor grayDarker READ grayDarker WRITE setGrayDarker NOTIFY grayDarkerChanged ) - Q_PROPERTY(QColor grayLighter READ grayLighter WRITE setGrayLighter NOTIFY grayLighterChanged ) - Q_PROPERTY(QColor grayMuchLighter READ grayMuchLighter WRITE setGrayMuchLighter NOTIFY grayMuchLighterChanged ) - Q_PROPERTY(QColor grayVeryMuchLighter READ grayVeryMuchLighter WRITE setGrayVeryMuchLighter NOTIFY grayVeryMuchLighterChanged ) - Q_PROPERTY(QColor blue READ blue WRITE setBlue NOTIFY blueChanged ) - Q_PROPERTY(QColor blueDarker READ blueDarker WRITE setBlueDarker NOTIFY blueDarkerChanged ) - Q_PROPERTY(QColor blueLighter READ blueLighter WRITE setBlueLighter NOTIFY blueLighterChanged ) - Q_PROPERTY(QColor blueMuchLighter READ blueMuchLighter WRITE setBlueMuchLighter NOTIFY blueMuchLighterChanged ) - Q_PROPERTY(QColor red READ red WRITE setRed NOTIFY redChanged ) - Q_PROPERTY(QColor redDarker READ redDarker WRITE setRedDarker NOTIFY redDarkerChanged ) - Q_PROPERTY(QColor green READ green WRITE setGreen NOTIFY greenChanged ) - Q_PROPERTY(QColor yellowLight READ yellowLight WRITE setYellowLight NOTIFY yellowLightChanged ) - Q_PROPERTY(QColor rose READ rose WRITE setRose NOTIFY roseChanged ) - Q_PROPERTY(QColor roseLight READ roseLight WRITE setRoseLight NOTIFY roseLightChanged ) - Q_PROPERTY(QColor cyan READ cyan WRITE setCyan NOTIFY cyanChanged ) - Q_PROPERTY(QColor shadow READ shadow WRITE setShadow NOTIFY shadowChanged ) - Q_PROPERTY(QColor jaspBlue READ jaspBlue WRITE setJaspBlue NOTIFY jaspBlueChanged ) - Q_PROPERTY(QColor jaspGreen READ jaspGreen WRITE setJaspGreen NOTIFY jaspGreenChanged ) - - //Colors (ui): - Q_PROPERTY(QColor textEnabled READ textEnabled WRITE setTextEnabled NOTIFY textEnabledChanged ) - Q_PROPERTY(QColor textDisabled READ textDisabled WRITE setTextDisabled NOTIFY textDisabledChanged ) - Q_PROPERTY(QColor uiBackground READ uiBackground WRITE setUiBackground NOTIFY uiBackgroundChanged ) - Q_PROPERTY(QColor uiBorder READ uiBorder WRITE setUiBorder NOTIFY uiBorderChanged ) - Q_PROPERTY(QColor fileMenuColorBackground READ fileMenuColorBackground WRITE setFileMenuColorBackground NOTIFY fileMenuColorBackgroundChanged ) - Q_PROPERTY(QColor fileMenuLightBorder READ fileMenuLightBorder WRITE setFileMenuLightBorder NOTIFY fileMenuLightBorderChanged ) - - Q_PROPERTY(QColor buttonColor READ buttonColor WRITE setButtonColor NOTIFY buttonColorChanged ) - Q_PROPERTY(QColor buttonColorHovered READ buttonColorHovered WRITE setButtonColorHovered NOTIFY buttonColorHoveredChanged ) - Q_PROPERTY(QColor buttonColorPressed READ buttonColorPressed WRITE setButtonColorPressed NOTIFY buttonColorPressedChanged ) - Q_PROPERTY(QColor buttonBorderColor READ buttonBorderColor WRITE setButtonBorderColor NOTIFY buttonBorderColorChanged ) - Q_PROPERTY(QColor buttonBorderColorHovered READ buttonBorderColorHovered WRITE setButtonBorderColorHovered NOTIFY buttonBorderColorHoveredChanged ) - Q_PROPERTY(QColor buttonColorDisabled MEMBER _buttonColorDisabled NOTIFY buttonColorDisabledChanged ) - - Q_PROPERTY(QColor itemHighlight READ itemHighlight WRITE setItemHighlight NOTIFY itemHighlightChanged ) - Q_PROPERTY(QColor itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged ) - Q_PROPERTY(QColor itemSelectedColor READ itemSelectedColor WRITE setItemSelectedColor NOTIFY itemSelectedColorChanged ) - Q_PROPERTY(QColor itemSelectedNoFocusColor READ itemSelectedNoFocusColor WRITE setItemSelectedNoFocusColor NOTIFY itemSelectedNoFocusColorChanged ) - - Q_PROPERTY(QColor darkeningColour READ darkeningColour WRITE setDarkeningColour NOTIFY darkeningColourChanged ) - - //JASPControl colors mostly: - Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged ) - Q_PROPERTY(QColor focusBorderColor READ focusBorderColor WRITE setFocusBorderColor NOTIFY focusBorderColorChanged ) - Q_PROPERTY(QColor dependencyBorderColor READ dependencyBorderColor WRITE setDependencyBorderColor NOTIFY dependencyBorderColorChanged ) - Q_PROPERTY(QColor dependencySelectedColor READ dependencySelectedColor WRITE setDependencySelectedColor NOTIFY dependencySelectedColorChanged ) - Q_PROPERTY(QColor containsDragBorderColor READ containsDragBorderColor WRITE setContainsDragBorderColor NOTIFY containsDragBorderColorChanged ) - - Q_PROPERTY(QColor analysisBackgroundColor READ analysisBackgroundColor WRITE setAnalysisBackgroundColor NOTIFY analysisBackgroundColorChanged ) - Q_PROPERTY(QColor controlBackgroundColor READ controlBackgroundColor WRITE setControlBackgroundColor NOTIFY controlBackgroundColorChanged ) - Q_PROPERTY(QColor controlDisabledBackgroundColor READ controlDisabledBackgroundColor WRITE setControlDisabledBackgroundColor NOTIFY controlDisabledBackgroundColorChanged ) - Q_PROPERTY(QColor rowEvenColor READ rowEvenColor WRITE setRowEvenColor NOTIFY rowEvenColorChanged ) - Q_PROPERTY(QColor rowOnevenColor READ rowOnevenColor WRITE setRowOnevenColor NOTIFY rowOnevenColorChanged ) - Q_PROPERTY(QColor controlErrorBackgroundColor READ controlErrorBackgroundColor WRITE setControlErrorBackgroundColor NOTIFY controlErrorBackgroundColorChanged ) - Q_PROPERTY(QColor controlErrorTextColor READ controlErrorTextColor WRITE setControlErrorTextColor NOTIFY controlErrorTextColorChanged ) - Q_PROPERTY(QColor controlWarningBackgroundColor READ controlWarningBackgroundColor WRITE setControlWarningBackgroundColor NOTIFY controlWarningBackgroundColorChanged ) - Q_PROPERTY(QColor controlWarningTextColor READ controlWarningTextColor WRITE setControlWarningTextColor NOTIFY controlWarningTextColorChanged ) - - Q_PROPERTY(QColor buttonBackgroundColor READ buttonBackgroundColor WRITE setButtonBackgroundColor NOTIFY buttonBackgroundColorChanged ) - Q_PROPERTY(QColor tooltipBackgroundColor READ tooltipBackgroundColor WRITE setTooltipBackgroundColor NOTIFY tooltipBackgroundColorChanged ) - Q_PROPERTY(QColor debugBackgroundColor READ debugBackgroundColor WRITE setDebugBackgroundColor NOTIFY debugBackgroundColorChanged ) - Q_PROPERTY(QColor errorMessagesBackgroundColor READ errorMessagesBackgroundColor WRITE setErrorMessagesBackgroundColor NOTIFY errorMessagesBackgroundColorChanged ) - Q_PROPERTY(QColor sliderPartOn READ sliderPartOn WRITE setSliderPartOn NOTIFY sliderPartOnChanged ) - Q_PROPERTY(QColor sliderPartOff READ sliderPartOff WRITE setSliderPartOff NOTIFY sliderPartOffChanged ) - Q_PROPERTY(QColor altNavTagColor READ altNavTagColor WRITE setAltNavTagColor NOTIFY altNavTagColorChanged ) - - - //Distances: - Q_PROPERTY(theme_distanceType borderRadius READ borderRadius WRITE setBorderRadius NOTIFY borderRadiusChanged ) - Q_PROPERTY(theme_distanceType shadowRadius READ shadowRadius WRITE setShadowRadius NOTIFY shadowRadiusChanged ) - - Q_PROPERTY(theme_distanceType itemPadding READ itemPadding WRITE setItemPadding NOTIFY itemPaddingChanged ) - Q_PROPERTY(theme_distanceType jaspControlPadding READ jaspControlPadding WRITE setJaspControlPadding NOTIFY jaspControlPaddingChanged ) - Q_PROPERTY(theme_distanceType ribbonButtonPadding READ ribbonButtonPadding WRITE setRibbonButtonPadding NOTIFY ribbonButtonPaddingChanged ) - Q_PROPERTY(theme_distanceType groupContentPadding READ groupContentPadding WRITE setGroupContentPadding NOTIFY groupContentPaddingChanged ) - - Q_PROPERTY(theme_distanceType rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged ) - Q_PROPERTY(theme_distanceType rowGridSpacing READ rowGridSpacing WRITE setRowGridSpacing NOTIFY rowGridSpacingChanged ) - Q_PROPERTY(theme_distanceType rowGroupSpacing READ rowGroupSpacing WRITE setRowGroupSpacing NOTIFY rowGroupSpacingChanged ) - Q_PROPERTY(theme_distanceType columnGridSpacing READ columnGridSpacing WRITE setColumnGridSpacing NOTIFY columnGridSpacingChanged ) - Q_PROPERTY(theme_distanceType columnGroupSpacing READ columnGroupSpacing WRITE setColumnGroupSpacing NOTIFY columnGroupSpacingChanged ) - Q_PROPERTY(theme_distanceType indentationLength READ indentationLength WRITE setIndentationLength NOTIFY indentationLengthChanged ) - Q_PROPERTY(theme_distanceType labelSpacing READ labelSpacing WRITE setLabelSpacing NOTIFY labelSpacingChanged ) - Q_PROPERTY(theme_distanceType menuSpacing READ menuSpacing WRITE setMenuSpacing NOTIFY menuSpacingChanged ) - Q_PROPERTY(theme_distanceType menuPadding READ menuPadding WRITE setMenuPadding NOTIFY menuPaddingChanged ) - - Q_PROPERTY(theme_distanceType generalAnchorMargin READ generalAnchorMargin WRITE setGeneralAnchorMargin NOTIFY generalAnchorMarginChanged ) - Q_PROPERTY(theme_distanceType generalMenuMargin READ generalMenuMargin WRITE setGeneralMenuMargin NOTIFY generalMenuMarginChanged ) - Q_PROPERTY(theme_distanceType titleBottomMargin READ titleBottomMargin WRITE setTitleBottomMargin NOTIFY titleBottomMarginChanged ) - Q_PROPERTY(theme_distanceType contentMargin READ contentMargin WRITE setContentMargin NOTIFY contentMarginChanged ) - Q_PROPERTY(theme_distanceType subOptionOffset READ subOptionOffset WRITE setSubOptionOffset NOTIFY subOptionOffsetChanged ) - - //Sizes: - Q_PROPERTY(theme_sizeType minPanelWidth READ minPanelWidth WRITE setMinPanelWidth NOTIFY minPanelWidthChanged ) - Q_PROPERTY(theme_sizeType resultWidth READ resultWidth WRITE setResultWidth NOTIFY resultWidthChanged ) - Q_PROPERTY(theme_sizeType formWidth READ formWidth WRITE setFormWidth NOTIFY formWidthChanged ) - Q_PROPERTY(theme_sizeType iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged ) - Q_PROPERTY(theme_sizeType formMargin READ formMargin WRITE setFormMargin NOTIFY formMarginChanged ) - Q_PROPERTY(theme_sizeType sliderWidth READ sliderWidth WRITE setSliderWidth NOTIFY sliderWidthChanged ) - Q_PROPERTY(theme_sizeType sliderLength READ sliderLength WRITE setSliderLength NOTIFY sliderLengthChanged ) - Q_PROPERTY(theme_sizeType switchHeight READ switchHeight WRITE setSwitchHeight NOTIFY switchHeightChanged ) - Q_PROPERTY(theme_sizeType spinBoxHeight READ spinBoxHeight WRITE setSpinBoxHeight NOTIFY spinBoxHeightChanged ) - Q_PROPERTY(theme_sizeType spinBoxWidth READ spinBoxWidth WRITE setSpinBoxWidth NOTIFY spinBoxWidthChanged ) - Q_PROPERTY(theme_sizeType comboBoxHeight READ comboBoxHeight WRITE setComboBoxHeight NOTIFY comboBoxHeightChanged ) - Q_PROPERTY(theme_sizeType textFieldWidth READ textFieldWidth WRITE setTextFieldWidth NOTIFY textFieldWidthChanged ) - Q_PROPERTY(theme_sizeType textFieldHeight READ textFieldHeight WRITE setTextFieldHeight NOTIFY textFieldHeightChanged ) - Q_PROPERTY(theme_sizeType numericFieldWidth READ numericFieldWidth WRITE setNumericFieldWidth NOTIFY numericFieldWidthChanged ) - Q_PROPERTY(theme_sizeType splitHandleWidth READ splitHandleWidth WRITE setSplitHandleWidth NOTIFY splitHandleWidthChanged ) - Q_PROPERTY(theme_sizeType subMenuIconHeight READ subMenuIconHeight WRITE setSubMenuIconHeight NOTIFY subMenuIconHeightChanged ) - Q_PROPERTY(theme_sizeType ribbonButtonHeight READ ribbonButtonHeight WRITE setRibbonButtonHeight NOTIFY ribbonButtonHeightChanged ) - Q_PROPERTY(theme_sizeType variablesListTitle READ variablesListTitle WRITE setVariablesListTitle NOTIFY variablesListTitleChanged ) - Q_PROPERTY(theme_sizeType sliderHandleDiameter READ sliderHandleDiameter WRITE setSliderHandleDiameter NOTIFY sliderHandleDiameterChanged ) - Q_PROPERTY(theme_sizeType defaultTextAreaHeight READ defaultTextAreaHeight WRITE setDefaultTextAreaHeight NOTIFY defaultTextAreaHeightChanged ) - Q_PROPERTY(theme_sizeType formExpanderHeaderHeight READ formExpanderHeaderHeight WRITE setFormExpanderHeaderHeight NOTIFY formExpanderHeaderHeightChanged ) - Q_PROPERTY(theme_sizeType jaspControlHighlightWidth READ jaspControlHighlightWidth WRITE setJaspControlHighlightWidth NOTIFY jaspControlHighlightWidthChanged ) - Q_PROPERTY(theme_sizeType defaultVariablesFormHeight READ defaultVariablesFormHeight WRITE setDefaultVariablesFormHeight NOTIFY defaultVariablesFormHeightChanged ) - Q_PROPERTY(theme_sizeType defaultSingleItemListHeight READ defaultSingleItemListHeight WRITE setDefaultSingleItemListHeight NOTIFY defaultSingleItemListHeightChanged ) - Q_PROPERTY(theme_sizeType defaultRectangularButtonHeight READ defaultRectangularButtonHeight WRITE setDefaultRectangularButtonHeight NOTIFY defaultRectangularButtonHeightChanged ) - Q_PROPERTY(theme_sizeType smallDefaultVariablesFormHeight READ smallDefaultVariablesFormHeight WRITE setSmallDefaultVariablesFormHeight NOTIFY smallDefaultVariablesFormHeightChanged ) - Q_PROPERTY(theme_sizeType messageBoxButtonHeight READ messageBoxButtonHeight WRITE setMessageBoxButtonHeight NOTIFY messageBoxButtonHeightChanged ) - Q_PROPERTY(theme_sizeType scrollbarBoxWidthBig READ scrollbarBoxWidthBig WRITE setScrollbarBoxWidthBig NOTIFY scrollbarBoxWidthBigChanged ) - Q_PROPERTY(theme_sizeType scrollbarBoxWidth READ scrollbarBoxWidth WRITE setScrollbarBoxWidth NOTIFY scrollbarBoxWidthChanged ) - Q_PROPERTY(theme_sizeType menuItemHeight READ menuItemHeight WRITE setMenuItemHeight NOTIFY menuItemHeightChanged ) - Q_PROPERTY(theme_sizeType menuGroupTitleHeight READ menuGroupTitleHeight WRITE setMenuGroupTitleHeight NOTIFY menuGroupTitleHeightChanged ) - Q_PROPERTY(theme_sizeType menuHeaderHeight READ menuHeaderHeight WRITE setMenuHeaderHeight NOTIFY menuHeaderHeightChanged ) - - //Velocities: - Q_PROPERTY(float maximumFlickVelocity READ maximumFlickVelocity NOTIFY maximumFlickVelocityChanged ) - - //Times: https://www.youtube.com/watch?v=90WD_ats6eE - //typedef int int; - Q_PROPERTY(theme_timeType hoverTime READ hoverTime WRITE setHoverTime NOTIFY hoverTimeChanged ) - Q_PROPERTY(theme_timeType fileMenuSlideDuration READ fileMenuSlideDuration WRITE setFileMenuSlideDuration NOTIFY fileMenuSlideDurationChanged ) - Q_PROPERTY(theme_timeType toolTipDelay READ toolTipDelay WRITE setToolTipDelay NOTIFY toolTipDelayChanged ) - Q_PROPERTY(theme_timeType toolTipTimeout READ toolTipTimeout WRITE setToolTipTimeout NOTIFY toolTipTimeoutChanged ) - - Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged ) - Q_PROPERTY(QFont fontLink READ fontLink WRITE setFontLink NOTIFY fontLinkChanged ) - Q_PROPERTY(QFont fontLabel READ fontLabel WRITE setFontLabel NOTIFY fontLabelChanged ) - Q_PROPERTY(QFont fontRibbon READ fontRibbon WRITE setFontRibbon NOTIFY fontRibbonChanged ) - Q_PROPERTY(QFont fontGroupTitle READ fontGroupTitle WRITE setFontGroupTitle NOTIFY fontGroupTitleChanged ) - Q_PROPERTY(QFont fontPrefOptionsGroupTitle READ fontPrefOptionsGroupTitle WRITE setFontPrefOptionsGroupTitle NOTIFY fontPrefOptionsGroupTitleChanged ) - Q_PROPERTY(QFont fontALTNavTag READ fontALTNavTag WRITE setFontALTNavTag NOTIFY fontALTNavTagChanged ) - - - Q_PROPERTY(QFont fontRCode READ fontRCode WRITE setFontRCode NOTIFY fontRCodeChanged ) - Q_PROPERTY(QFont fontCode READ fontCode WRITE setFontCode NOTIFY fontCodeChanged ) - - //Iconfolder: - Q_PROPERTY(QString iconPath READ iconPath NOTIFY iconPathChanged ) - Q_PROPERTY(QString themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged ) - - Q_PROPERTY(bool isDark READ isDark WRITE setIsDark NOTIFY isDarkChanged ) - -public: - explicit JaspTheme(QQuickItem * item = nullptr); - ~JaspTheme(); - - static void setCurrentTheme(JaspTheme * theme); - static void setCurrentThemeFromName(QString name); - static void initializeUIScales(); - - static JaspTheme * currentTheme() { return _currentTheme; } - static QFontMetricsF & fontMetrics() { return _fontMetrics; } //For qml interface font used everywhere (in particular in datasetview though) - static const std::map & themes() { return _themes; } - - float uiScale() const { return _uiScale; } - float ribbonScaleHovered() const { return _ribbonScaleHovered; } - QColor white() const { return _white; } - QColor whiteBroken() const { return _whiteBroken; } - QColor black() const { return _black; } - QColor gray() const { return _gray; } - QColor grayDarker() const { return _grayDarker; } - QColor grayLighter() const { return _grayLighter; } - QColor grayMuchLighter() const { return _grayMuchLighter; } - QColor grayVeryMuchLighter() const { return _grayVeryMuchLighter; } - QColor blue() const { return _blue; } - QColor blueDarker() const { return _blueDarker; } - QColor blueLighter() const { return _blueLighter; } - QColor blueMuchLighter() const { return _blueMuchLighter; } - QColor red() const { return _red; } - QColor redDarker() const { return _redDarker; } - QColor green() const { return _green; } - QColor yellowLight() const { return _yellowLight; } - QColor rose() const { return _rose; } - QColor roseLight() const { return _roseLight; } - QColor cyan() const { return _cyan; } - QColor shadow() const { return _shadow; } - QColor jaspBlue() const { return _jaspBlue; } - QColor jaspGreen() const { return _jaspGreen; } - QColor textEnabled() const { return _textEnabled; } - QColor textDisabled() const { return _textDisabled; } - QColor uiBackground() const { return _uiBackground; } - QColor uiBorder() const { return _uiBorder; } - QColor fileMenuColorBackground() const { return _fileMenuColorBackground; } - QColor fileMenuLightBorder() const { return _fileMenuLightBorder; } - QColor buttonColor() const { return _buttonColor; } - QColor buttonColorHovered() const { return _buttonColorHovered; } - QColor buttonColorPressed() const { return _buttonColorPressed; } - QColor buttonBorderColor() const { return _buttonBorderColor; } - QColor buttonBorderColorHovered() const { return _buttonBorderColorHovered; } - QColor itemHighlight() const { return _itemHighlight; } - QColor itemHoverColor() const { return _itemHoverColor; } - QColor itemSelectedColor() const { return _itemSelectedColor; } - QColor itemSelectedNoFocusColor() const { return _itemSelectedNoFocusColor; } - QColor borderColor() const { return _borderColor; } - QColor focusBorderColor() const { return _focusBorderColor; } - QColor dependencyBorderColor() const { return _dependencyBorderColor; } - QColor dependencySelectedColor() const { return _dependencySelectedColor; } - QColor containsDragBorderColor() const { return _containsDragBorderColor; } - QColor analysisBackgroundColor() const { return _analysisBackgroundColor; } - QColor controlBackgroundColor() const { return _controlBackgroundColor; } - QColor controlDisabledBackgroundColor() const { return _controlDisabledBackgroundColor; } - QColor rowEvenColor() const { return _rowEvenColor; } - QColor rowOnevenColor() const { return _rowOnevenColor; } - QColor controlErrorBackgroundColor() const { return _controlErrorBackgroundColor; } - QColor controlErrorTextColor() const { return _controlErrorTextColor; } - QColor controlWarningBackgroundColor() const { return _controlWarningBackgroundColor; } - QColor controlWarningTextColor() const { return _controlWarningTextColor; } - QColor buttonBackgroundColor() const { return _buttonBackgroundColor; } - QColor tooltipBackgroundColor() const { return _tooltipBackgroundColor; } - QColor debugBackgroundColor() const { return _debugBackgroundColor; } - QColor errorMessagesBackgroundColor() const { return _errorMessagesBackgroundColor; } - QColor sliderPartOn() const { return _sliderPartOn; } - QColor sliderPartOff() const { return _sliderPartOff; } - QColor altNavTagColor() const { return _altNavTagColor; } - QColor darkeningColour() const { return _darkeningColour; } - theme_distanceType borderRadius() const { return _borderRadius * uiScale(); } - theme_distanceType shadowRadius() const { return _shadowRadius * uiScale(); } - theme_distanceType itemPadding() const { return _itemPadding * uiScale(); } - theme_distanceType jaspControlPadding() const { return _jaspControlPadding * uiScale(); } - theme_distanceType ribbonButtonPadding() const { return _ribbonButtonPadding * uiScale(); } - theme_distanceType groupContentPadding() const { return _groupContentPadding * uiScale(); } - theme_distanceType rowSpacing() const { return _rowSpacing * uiScale(); } - theme_distanceType rowGridSpacing() const { return _rowGridSpacing * uiScale(); } - theme_distanceType rowGroupSpacing() const { return _rowGroupSpacing * uiScale(); } - theme_distanceType columnGridSpacing() const { return _columnGridSpacing * uiScale(); } - theme_distanceType columnGroupSpacing() const { return _columnGroupSpacing * uiScale(); } - theme_distanceType indentationLength() const { return _indentationLength * uiScale(); } - theme_distanceType labelSpacing() const { return _labelSpacing * uiScale(); } - theme_distanceType menuSpacing() const { return _menuSpacing * uiScale(); } - theme_distanceType menuPadding() const { return _menuPadding * uiScale(); } - theme_distanceType generalAnchorMargin() const { return _generalAnchorMargin * uiScale(); } - theme_distanceType generalMenuMargin() const { return _generalMenuMargin * uiScale(); } - theme_distanceType titleBottomMargin() const { return _titleBottomMargin * uiScale(); } - theme_distanceType contentMargin() const { return _contentMargin * uiScale(); } - theme_distanceType subOptionOffset() const { return _subOptionOffset * uiScale(); } - theme_sizeType minPanelWidth() const { return _minPanelWidth * uiScale(); } - theme_sizeType resultWidth() const { return _resultWidth * uiScale(); } - theme_sizeType formWidth() const { return _formWidth * uiScale(); } - theme_sizeType iconSize() const { return _iconSize * uiScale(); } - theme_sizeType formMargin() const { return _formMargin * uiScale(); } - theme_sizeType formExpanderHeaderHeight() const { return _formExpanderHeaderHeight * uiScale(); } - theme_sizeType sliderWidth() const { return _sliderWidth * uiScale(); } - theme_sizeType sliderLength() const { return _sliderLength * uiScale(); } - theme_sizeType switchHeight() const { return _switchHeight * uiScale(); } - theme_sizeType spinBoxHeight() const { return _spinBoxHeight * uiScale(); } - theme_sizeType spinBoxWidth() const { return _spinBoxWidth * uiScale(); } - theme_sizeType comboBoxHeight() const { return _comboBoxHeight * uiScale(); } - theme_sizeType textFieldWidth() const { return _textFieldWidth * uiScale(); } - theme_sizeType textFieldHeight() const { return _textFieldHeight * uiScale(); } - theme_sizeType numericFieldWidth() const { return _numericFieldWidth * uiScale(); } - theme_sizeType splitHandleWidth() const { return _splitHandleWidth * uiScale(); } - theme_sizeType subMenuIconHeight() const { return _subMenuIconHeight * uiScale(); } - theme_sizeType ribbonButtonHeight() const { return _ribbonButtonHeight * uiScale(); } - theme_sizeType variablesListTitle() const { return _variablesListTitle * uiScale(); } - theme_sizeType sliderHandleDiameter() const { return _sliderHandleDiameter * uiScale(); } - theme_sizeType defaultTextAreaHeight() const { return _defaultTextAreaHeight * uiScale(); } - theme_sizeType jaspControlHighlightWidth() const { return _jaspControlHighlightWidth * uiScale(); } - theme_sizeType defaultVariablesFormHeight() const { return _defaultVariablesFormHeight * uiScale(); } - theme_sizeType defaultSingleItemListHeight() const { return _defaultSingleItemListHeight * uiScale(); } - theme_sizeType defaultRectangularButtonHeight() const { return _defaultRectangularButtonHeight * uiScale(); } - theme_sizeType smallDefaultVariablesFormHeight() const { return _smallDefaultVariablesFormHeight * uiScale(); } - theme_sizeType messageBoxButtonHeight() const { return _messageBoxButtonHeight * uiScale(); } - theme_sizeType scrollbarBoxWidthBig() const { return _scrollbarBoxWidthBig * uiScale(); } - theme_sizeType scrollbarBoxWidth() const { return _scrollbarBoxWidth * uiScale(); } - theme_sizeType menuItemHeight() const { return _menuItemHeight * uiScale(); } - theme_sizeType menuGroupTitleHeight() const { return _menuGroupTitleHeight * uiScale(); } - theme_sizeType menuHeaderHeight() const { return _menuHeaderHeight * uiScale(); } - float maximumFlickVelocity() const { return _maximumFlickVelocity; } - int hoverTime() const { return _hoverTime; } - int fileMenuSlideDuration() const { return _fileMenuSlideDuration; } - int toolTipDelay() const { return _toolTipDelay; } - int toolTipTimeout() const { return _toolTipTimeout; } - QFont font() const { return _font; } - QFont fontLink() const { return _fontLink; } - QFont fontLabel() const { return _fontLabel; } - QFont fontRibbon() const { return _fontRibbon; } - QFont fontGroupTitle() const { return _fontGroupTitle; } - QFont fontPrefOptionsGroupTitle() const { return _fontPrefOptionsGroupTitle; } - QFont fontRCode() const { return _fontRCode; } - QFont fontCode() const { return _fontCode; } - QFont fontALTNavTag() const { return _fontALTNavTag; } - QString iconPath() const { return _iconPath; } - QString themeName() const { return _themeName; } - static QString currentIconPath(); - bool isDark() const { return _isDark; } - -signals: - void currentThemeReady(JaspTheme * newTheme); - void uiScaleChanged(float uiScale); - void ribbonScaleHoveredChanged(float ribbonScaleHovered); - void whiteChanged(QColor white); - void whiteBrokenChanged(QColor whiteBroken); - void blackChanged(QColor black); - void grayChanged(QColor gray); - void grayDarkerChanged(QColor grayDarker); - void grayLighterChanged(QColor grayLighter); - void grayMuchLighterChanged(QColor grayMuchLighter); - void grayVeryMuchLighterChanged(QColor grayVeryMuchLighter); - void blueChanged(QColor blue); - void blueDarkerChanged(QColor blueDarker); - void blueLighterChanged(QColor blueLighter); - void blueMuchLighterChanged(QColor blueMuchLighter); - void redChanged(QColor red); - void redDarkerChanged(QColor redDarker); - void greenChanged(QColor green); - void yellowLightChanged(QColor yellowLight); - void roseChanged(QColor rose); - void roseLightChanged(QColor roseLight); - void cyanChanged(QColor cyan); - void shadowChanged(QColor shadow); - void jaspBlueChanged(QColor jaspBlue); - void jaspGreenChanged(QColor jaspGreen); - void textEnabledChanged(QColor textEnabled); - void textDisabledChanged(QColor textDisabled); - void uiBackgroundChanged(QColor uiBackground); - void uiBorderChanged(QColor uiBorder); - void fileMenuColorBackgroundChanged(QColor fileMenuColorBackground); - void fileMenuLightBorderChanged(QColor fileMenuLightBorder); - void buttonColorChanged(QColor buttonColor); - void buttonColorHoveredChanged(QColor buttonColorHovered); - void buttonColorPressedChanged(QColor buttonColorPressed); - void buttonColorDisabledChanged(QColor buttonColorPressed); - void buttonBorderColorChanged(QColor buttonBorderColor); - void buttonBorderColorHoveredChanged(QColor buttonBorderColorHovered); - void itemHighlightChanged(QColor itemHighlight); - void itemHoverColorChanged(QColor itemHoverColor); - void itemSelectedColorChanged(QColor itemSelectedColor); - void itemSelectedNoFocusColorChanged(QColor itemSelectedNoFocusColor); - void borderColorChanged(QColor borderColor); - void focusBorderColorChanged(QColor focusBorderColor); - void dependencyBorderColorChanged(QColor dependencyBorderColor); - void dependencySelectedColorChanged(QColor dependencySelectedColor); - void containsDragBorderColorChanged(QColor containsDragBorderColor); - void analysisBackgroundColorChanged(QColor analysisBackgroundColor); - void controlBackgroundColorChanged(QColor controlBackgroundColor); - void controlDisabledBackgroundColorChanged(QColor controlDisabledBackgroundColor); - void rowEvenColorChanged(QColor rowEvenColor); - void rowOnevenColorChanged(QColor rowOnevenColor); - void controlErrorBackgroundColorChanged(QColor controlErrorBackgroundColor); - void controlErrorTextColorChanged(QColor controlErrorTextColor); - void controlWarningBackgroundColorChanged(QColor controlWarningBackgroundColor); - void controlWarningTextColorChanged(QColor controlWarningTextColor); - void buttonBackgroundColorChanged(QColor buttonBackgroundColor); - void tooltipBackgroundColorChanged(QColor tooltipBackgroundColor); - void debugBackgroundColorChanged(QColor debugBackgroundColor); - void errorMessagesBackgroundColorChanged(QColor errorMessagesBackgroundColor); - void sliderPartOnChanged(QColor sliderPartOn); - void sliderPartOffChanged(QColor sliderPartOff); - void altNavTagColorChanged(QColor altNavTagColor); - void darkeningColourChanged(QColor darkeningColour); - void borderRadiusChanged(); - void shadowRadiusChanged(); - void itemPaddingChanged(); - void jaspControlPaddingChanged(); - void ribbonButtonPaddingChanged(); - void groupContentPaddingChanged(); - void rowSpacingChanged(); - void rowGridSpacingChanged(); - void rowGroupSpacingChanged(); - void columnGridSpacingChanged(); - void columnGroupSpacingChanged(); - void indentationLengthChanged(); - void labelSpacingChanged(); - void menuSpacingChanged(); - void menuPaddingChanged(); - void generalAnchorMarginChanged(); - void generalMenuMarginChanged(); - void titleBottomMarginChanged(); - void contentMarginChanged(); - void subOptionOffsetChanged(); - void minPanelWidthChanged(); - void resultWidthChanged(); - void formWidthChanged(); - void iconSizeChanged(); - void formMarginChanged(); - void formExpanderHeaderHeightChanged(); - void sliderWidthChanged(); - void sliderLengthChanged(); - void switchHeightChanged(); - void spinBoxHeightChanged(); - void spinBoxWidthChanged(); - void comboBoxHeightChanged(); - void textFieldWidthChanged(); - void textFieldHeightChanged(); - void numericFieldWidthChanged(); - void splitHandleWidthChanged(); - void subMenuIconHeightChanged(); - void ribbonButtonHeightChanged(); - void variablesListTitleChanged(); - void sliderHandleDiameterChanged(); - void defaultTextAreaHeightChanged(); - void jaspControlHighlightWidthChanged(); - void defaultVariablesFormHeightChanged(); - void defaultSingleItemListHeightChanged(); - void defaultRectangularButtonHeightChanged(); - void smallDefaultVariablesFormHeightChanged(); - void messageBoxButtonHeightChanged(); - void scrollbarBoxWidthBigChanged(); - void scrollbarBoxWidthChanged(); - void menuItemHeightChanged(); - void menuGroupTitleHeightChanged(); - void menuHeaderHeightChanged(); - void maximumFlickVelocityChanged(); - void hoverTimeChanged(theme_timeType hoverTime); - void fileMenuSlideDurationChanged(theme_timeType fileMenuSlideDuration); - void toolTipDelayChanged(theme_timeType toolTipDelay); - void toolTipTimeoutChanged(theme_timeType toolTipTimeout); - void fontChanged(QFont font); - void fontLinkChanged(QFont fontLink); - void fontLabelChanged(QFont fontLabel); - void fontRibbonChanged(QFont fontRibbon); - void fontGroupTitleChanged(QFont fontGroupTitle); - void fontPrefOptionsGroupTitleChanged(QFont fontPrefOptionsGroupTitle); - void fontRCodeChanged(QFont fontRCode); - void fontCodeChanged(QFont fontCode); - void fontALTNavTagChanged(QFont fontALTNavTag); - void iconPathChanged(QString iconPath); - void themeNameChanged(QString themeName); - void currentThemeNameChanged(); - void isDarkChanged(bool isDark); - -public slots: - void setRibbonScaleHovered(float ribbonScaleHovered); - void setWhite(QColor white); - void setWhiteBroken(QColor whiteBroken); - void setBlack(QColor black); - void setGray(QColor gray); - void setGrayDarker(QColor grayDarker); - void setGrayLighter(QColor grayLighter); - void setGrayMuchLighter(QColor grayMuchLighter); - void setGrayVeryMuchLighter(QColor grayVeryMuchLighter); - void setBlue(QColor blue); - void setBlueDarker(QColor blueDarker); - void setBlueLighter(QColor blueLighter); - void setBlueMuchLighter(QColor blueMuchLighter); - void setRed(QColor red); - void setRedDarker(QColor redDarker); - void setGreen(QColor green); - void setYellowLight(QColor yellowLight); - void setRose(QColor rose); - void setRoseLight(QColor roseLight); - void setCyan(QColor cyan); - void setShadow(QColor shadow); - void setJaspBlue(QColor jaspBlue); - void setJaspGreen(QColor jaspGreen); - void setTextEnabled(QColor textEnabled); - void setTextDisabled(QColor textDisabled); - void setUiBackground(QColor uiBackground); - void setUiBorder(QColor uiBorder); - void setFileMenuColorBackground(QColor fileMenuColorBackground); - void setFileMenuLightBorder(QColor fileMenuLightBorder); - void setButtonColor(QColor buttonColor); - void setButtonColorHovered(QColor buttonColorHovered); - void setButtonColorPressed(QColor buttonColorPressed); - void setButtonBorderColor(QColor buttonBorderColor); - void setButtonBorderColorHovered(QColor buttonBorderColorHovered); - void setItemHighlight(QColor itemHighlight); - void setItemHoverColor(QColor itemHoverColor); - void setItemSelectedColor(QColor itemSelectedColor); - void setItemSelectedNoFocusColor(QColor itemSelectedNoFocusColor); - void setBorderColor(QColor borderColor); - void setFocusBorderColor(QColor focusBorderColor); - void setDependencyBorderColor(QColor dependencyBorderColor); - void setDependencySelectedColor(QColor dependencySelectedColor); - void setContainsDragBorderColor(QColor containsDragBorderColor); - void setAnalysisBackgroundColor(QColor analysisBackgroundColor); - void setControlBackgroundColor(QColor controlBackgroundColor); - void setControlDisabledBackgroundColor(QColor controlDisabledBackgroundColor); - void setRowEvenColor(QColor rowEvenColor); - void setRowOnevenColor(QColor rowOnevenColor); - void setControlErrorBackgroundColor(QColor controlErrorBackgroundColor); - void setControlErrorTextColor(QColor controlErrorTextColor); - void setControlWarningBackgroundColor(QColor controlWarningBackgroundColor); - void setControlWarningTextColor(QColor controlWarningTextColor); - void setButtonBackgroundColor(QColor buttonBackgroundColor); - void setTooltipBackgroundColor(QColor tooltipBackgroundColor); - void setDebugBackgroundColor(QColor debugBackgroundColor); - void setErrorMessagesBackgroundColor(QColor errorMessagesBackgroundColor); - void setSliderPartOn(QColor sliderPartOn); - void setSliderPartOff(QColor sliderPartOff); - void setAltNavTagColor(QColor altNavTagColor); - void setDarkeningColour(QColor darkeningColour); - void setBorderRadius(theme_distanceType borderRadius); - void setShadowRadius(theme_distanceType shadowRadius); - void setItemPadding(theme_distanceType itemPadding); - void setJaspControlPadding(theme_distanceType jaspControlPadding); - void setRibbonButtonPadding(theme_distanceType ribbonButtonPadding); - void setGroupContentPadding(theme_distanceType groupContentPadding); - void setRowSpacing(theme_distanceType rowSpacing); - void setRowGridSpacing(theme_distanceType rowGridSpacing); - void setRowGroupSpacing(theme_distanceType rowGroupSpacing); - void setColumnGridSpacing(theme_distanceType columnGridSpacing); - void setColumnGroupSpacing(theme_distanceType columnGroupSpacing); - void setIndentationLength(theme_distanceType indentationLength); - void setLabelSpacing(theme_distanceType labelSpacing); - void setMenuSpacing(theme_distanceType menuSpacing); - void setMenuPadding(theme_distanceType menuPadding); - void setGeneralAnchorMargin(theme_distanceType generalAnchorMargin); - void setGeneralMenuMargin(theme_distanceType generalMenuMargin); - void setTitleBottomMargin(theme_distanceType titleBottomMargin); - void setContentMargin(theme_distanceType contentMargin); - void setSubOptionOffset(theme_distanceType subOptionOffset); - void setMinPanelWidth(theme_sizeType minPanelWidth); - void setResultWidth(theme_sizeType resultWidth); - void setFormWidth(theme_sizeType formWidth); - void setIconSize(theme_sizeType iconSize); - void setFormMargin(theme_sizeType formMargin); - void setFormExpanderHeaderHeight(theme_sizeType formExpanderHeaderHeight); - void setSliderWidth(theme_sizeType sliderWidth); - void setSliderLength(theme_sizeType sliderLength); - void setSwitchHeight(theme_sizeType switchHeight); - void setSpinBoxHeight(theme_sizeType spinBoxHeight); - void setSpinBoxWidth(theme_sizeType spinBoxWidth); - void setComboBoxHeight(theme_sizeType comboBoxHeight); - void setTextFieldWidth(theme_sizeType textFieldWidth); - void setTextFieldHeight(theme_sizeType textFieldHeight); - void setNumericFieldWidth(theme_sizeType numericFieldWidth); - void setSplitHandleWidth(theme_sizeType splitHandleWidth); - void setSubMenuIconHeight(theme_sizeType subMenuIconHeight); - void setRibbonButtonHeight(theme_sizeType ribbonButtonHeight); - void setVariablesListTitle(theme_sizeType variablesListTitle); - void setSliderHandleDiameter(theme_sizeType sliderHandleDiameter); - void setDefaultTextAreaHeight(theme_sizeType defaultTextAreaHeight); - void setJaspControlHighlightWidth(theme_sizeType jaspControlHighlightWidth); - void setDefaultVariablesFormHeight(theme_sizeType defaultVariablesFormHeight); - void setDefaultSingleItemListHeight(theme_sizeType defaultSingleItemListHeight); - void setDefaultRectangularButtonHeight(theme_sizeType defaultRectangularButtonHeight); - void setSmallDefaultVariablesFormHeight(theme_sizeType smallDefaultVariablesFormHeight); - void setMessageBoxButtonHeight(theme_sizeType messageBoxButtonHeight); - void setScrollbarBoxWidthBig(theme_sizeType scrollbarBoxWidthBig); - void setScrollbarBoxWidth(theme_sizeType scrollbarBoxWidth); - void setMenuItemHeight(theme_sizeType menuItemHeight); - void setMenuGroupTitleHeight(theme_sizeType menuGroupTitleHeight); - void setMenuHeaderHeight(theme_sizeType menuHeaderHeight); - void setHoverTime(theme_timeType hoverTime); - void setFileMenuSlideDuration(theme_timeType fileMenuSlideDuration); - void setToolTipDelay(theme_timeType toolTipDelay); - void setToolTipTimeout(theme_timeType toolTipTimeout); - void setFont(QFont font); - void setFontLink(QFont fontLink); - void setFontLabel(QFont fontLabel); - void setFontRibbon(QFont fontRibbon); - void setFontGroupTitle(QFont fontGroupTitle); - void setFontPrefOptionsGroupTitle(QFont fontPrefOptionsGroupTitle); - void setIconPath(QString iconPath); - void setThemeName(QString themeName); - void setFontRCode(QFont fontRCode); - void setFontCode(QFont fontCode); - void setFontALTNavTag(QFont fontALTNavTag); - void setIsDark(bool isDark); - void uiScaleHandler(); - void maxFlickVeloHandler(); - -private: - void connectSizeDistancesToUiScaleChanged(); - -private slots: - void updateFontMetrics(); - -private: - static JaspTheme * _currentTheme; - - float _ribbonScaleHovered, - _uiScale = 1, ///< default for when in R, otherwise ignored - _maximumFlickVelocity = 801; ///< default for when in R, otherwise ignored - - QColor _white, - _whiteBroken, - _black, - _gray, - _grayDarker, - _grayLighter, - _grayMuchLighter, - _grayVeryMuchLighter, - _blue, - _blueDarker, - _blueLighter, - _blueMuchLighter, - _red, - _redDarker, - _green, - _yellowLight, - _rose, - _roseLight, - _cyan, - _shadow, - _jaspBlue, - _jaspGreen, - _textEnabled, - _textDisabled, - _uiBackground, - _uiBorder, - _fileMenuColorBackground, - _fileMenuLightBorder, - _buttonColor, - _buttonColorHovered, - _buttonColorPressed, - _buttonColorDisabled, - _buttonBorderColor, - _buttonBorderColorHovered, - _itemHighlight, - _itemHoverColor, - _itemSelectedColor, - _itemSelectedNoFocusColor, - _borderColor, - _focusBorderColor, - _dependencyBorderColor, - _dependencySelectedColor, - _containsDragBorderColor, - _analysisBackgroundColor, - _controlBackgroundColor, - _controlDisabledBackgroundColor, - _rowEvenColor, - _rowOnevenColor, - _controlErrorBackgroundColor, - _controlErrorTextColor, - _controlWarningBackgroundColor, - _controlWarningTextColor, - _buttonBackgroundColor, - _tooltipBackgroundColor, - _debugBackgroundColor, - _errorMessagesBackgroundColor, - _sliderPartOn, - _sliderPartOff, - _darkeningColour, - _altNavTagColor; - - theme_distanceType _borderRadius, - _shadowRadius, - _itemPadding, - _jaspControlPadding, - _ribbonButtonPadding, - _groupContentPadding, - _rowSpacing, - _rowGridSpacing, - _rowGroupSpacing, - _columnGridSpacing, - _columnGroupSpacing, - _indentationLength, - _labelSpacing, - _menuSpacing, - _menuPadding, - _generalAnchorMargin, - _generalMenuMargin, - _titleBottomMargin, - _contentMargin, - _subOptionOffset; - - theme_sizeType _minPanelWidth, - _resultWidth, - _formWidth, - _iconSize, - _formMargin, - _formExpanderHeaderHeight, - _sliderWidth, - _sliderLength, - _switchHeight, - _spinBoxHeight, - _spinBoxWidth, - _comboBoxHeight, - _textFieldWidth, - _textFieldHeight, - _numericFieldWidth, - _splitHandleWidth, - _subMenuIconHeight, - _ribbonButtonHeight, - _variablesListTitle, - _sliderHandleDiameter, - _defaultTextAreaHeight, - _jaspControlHighlightWidth, - _defaultVariablesFormHeight, - _defaultSingleItemListHeight, - _defaultRectangularButtonHeight, - _smallDefaultVariablesFormHeight, - _messageBoxButtonHeight, - _scrollbarBoxWidthBig, - _scrollbarBoxWidth, - _menuItemHeight, - _menuGroupTitleHeight, - _menuHeaderHeight; - - //Times: https://www.youtube.com/watch?v=90WDats6eE - theme_timeType _hoverTime = 400, - _fileMenuSlideDuration = 150, - _toolTipDelay = 500, - _toolTipTimeout =60000; - - QFont _font, - _fontLink, - _fontLabel, - _fontRibbon, - _fontRCode, - _fontCode, - _fontGroupTitle, - _fontPrefOptionsGroupTitle, - _fontALTNavTag; - - QString _iconPath, - _themeName; - - bool _isDark = false; - - static QFontMetricsF _fontMetrics; - static std::map _themes; -}; - - - - -#endif // JASPTHEME_H diff --git a/QMLComponents/models/interactionmodel.cpp b/QMLComponents/models/interactionmodel.cpp deleted file mode 100644 index f9edd5dd94f..00000000000 --- a/QMLComponents/models/interactionmodel.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "interactionmodel.h" -#include - -void InteractionModel::addFixedFactors(const Terms &terms, bool combineWithExistingTerms) -{ - _fixedFactors.add(terms); - - if (combineWithExistingTerms) - { - Terms existingTerms = _interactionTerms; - - Terms newTerms = _interactionTerms; - newTerms.discardWhatDoesContainTheseComponents(_randomFactors); - newTerms.discardWhatDoesContainTheseComponents(_covariates); - existingTerms.add(newTerms.ffCombinations(terms)); - _interactionTerms.set(existingTerms); - } - else - _interactionTerms.add(terms); -} - -void InteractionModel::addRandomFactors(const Terms &terms) -{ - _randomFactors.add(terms); - _interactionTerms.add(terms); -} - -void InteractionModel::addCovariates(const Terms &terms) -{ - _covariates.add(terms); - _interactionTerms.add(terms); -} - -void InteractionModel::clearInteractions() -{ - _covariates.clear(); - _fixedFactors.clear(); - _randomFactors.clear(); - _interactionTerms.clear(); - _interactionTerms.removeParent(); -} - -void InteractionModel::removeInteractionTerms(const Terms& terms) -{ - _fixedFactors.remove(terms); - _randomFactors.remove(terms); - _covariates.remove(terms); - if (_mustContainLowerTerms) - _interactionTerms.discardWhatDoesContainTheseTerms(terms); - else - _interactionTerms.remove(terms); -} - -QSet InteractionModel::changeComponentName(const std::string& oldName, const std::string& newName) -{ - _fixedFactors.replaceVariableName(oldName, newName); - _randomFactors.replaceVariableName(oldName, newName); - _covariates.replaceVariableName(oldName, newName); - - return _interactionTerms.replaceVariableName(oldName, newName); -} diff --git a/QMLComponents/models/interactionmodel.h b/QMLComponents/models/interactionmodel.h deleted file mode 100644 index defe2fe365f..00000000000 --- a/QMLComponents/models/interactionmodel.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef INTERACTIONMODEL_H -#define INTERACTIONMODEL_H - -#include "terms.h" - -class InteractionModel -{ -public: - InteractionModel() {} - - void addInteractionTerms(const Terms &terms) { _interactionTerms.add(terms); } - void addFixedFactors(const Terms &terms, bool combineWithExistingTerms = true); - void addRandomFactors(const Terms &terms); - void addCovariates(const Terms &terms); - void removeInteractionTerms(const Terms& terms); - void clearInteractions(); - QSet changeComponentName(const std::string& oldName, const std::string& newName); - - const Terms& interactionTerms() const { return _interactionTerms; } - -protected: - Terms _covariates; - Terms _fixedFactors; - Terms _randomFactors; - - Terms _interactionTerms; - bool _mustContainLowerTerms = true; -}; - -#endif // INTERACTIONMODEL_H diff --git a/QMLComponents/models/listmodel.cpp b/QMLComponents/models/listmodel.cpp deleted file mode 100644 index 82330dfc7b4..00000000000 --- a/QMLComponents/models/listmodel.cpp +++ /dev/null @@ -1,746 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodel.h" -#include "controls/jasplistcontrol.h" -#include "analysisform.h" -#include "boundcontrols/boundcontrolterms.h" -#include "controls/rowcontrols.h" -#include "controls/sourceitem.h" -#include "log.h" - -ListModel::ListModel(JASPListControl* listView) - : QAbstractTableModel(listView) - , _listView(listView) -{ - // Connect all apecific signals to a general signal - connect(this, &ListModel::modelReset, this, &ListModel::termsChanged); - connect(this, &ListModel::rowsRemoved, this, &ListModel::termsChanged); - connect(this, &ListModel::rowsMoved, this, &ListModel::termsChanged); - connect(this, &ListModel::rowsInserted, this, &ListModel::termsChanged); - connect(this, &ListModel::dataChanged, this, &ListModel::dataChangedHandler); - connect(this, &ListModel::namesChanged, this, &ListModel::termsChanged); - connect(this, &ListModel::columnTypeChanged, this, &ListModel::termsChanged); -} - -QHash ListModel::roleNames() const -{ - static QHash roles = QAbstractTableModel::roleNames(); - static bool setMe = true; - - if(setMe) - { - roles[TypeRole] = "type"; - roles[SelectedRole] = "selected"; - roles[SelectableRole] = "selectable"; - roles[ColumnTypeRole] = "columnType"; - roles[ColumnTypeIconRole] = "columnTypeIcon"; - roles[ColumnTypeDisabledIconRole] = "columnTypeDisabledIcon"; - roles[NameRole] = "name"; - roles[RowComponentRole] = "rowComponent"; - roles[ValueRole] = "value"; - roles[VirtualRole] = "virtual"; - roles[DeletableRole] = "deletable"; - - setMe = false; - } - - return roles; -} - -void ListModel::refresh() -{ - beginResetModel(); - endResetModel(); -} - -void ListModel::addControlError(const QString &error) const -{ - _listView->addControlError(error); -} - -void ListModel::initTerms(const Terms &terms, const RowControlsValues& allValuesMap, bool) -{ - _initTerms(terms, allValuesMap, true); -} - -void ListModel::_initTerms(const Terms &terms, const RowControlsValues& allValuesMap, bool initRowControls) -{ - beginResetModel(); - if (initRowControls) - { - _rowControlsMap.clear(); - _rowControlsValues = allValuesMap; - } - _setTerms(terms); - endResetModel(); - - if (initRowControls) _connectAllSourcesControls(); -} - -void ListModel::_connectAllSourcesControls() -{ - for (SourceItem* sourceItem : listView()->sourceItems()) - _connectSourceControls(sourceItem); -} - -void ListModel::_connectSourceControls(SourceItem* sourceItem) -{ - // Connect option changes from controls in sourceModel that influence the terms of this model: - // either the source uses direclty a control in sourceModel (controlName()), or the source uses - // a conditional expression. - ListModel* sourceModel = sourceItem->sourceListModel(); - if (!sourceModel) - return; - - const Terms& terms = sourceModel->terms(); - if (terms.size() == 0) - return; - - for (const QString & controlName : sourceItem->usedControls()) - for (const Term & term : terms) - { - JASPControl * control = sourceModel->getRowControl(term.asQString(), controlName); - if (control) - { - BoundControl * boundControl = control->boundControl(); - if (boundControl && !_rowControlsConnected.contains(boundControl)) - { - connect(control, &JASPControl::boundValueChanged, this, &ListModel::sourceTermsReset); - _rowControlsConnected.push_back(boundControl); - } - } - else - Log::log() << "Cannot find control " << controlName << " in model " << name() << std::endl; - } -} - -Terms ListModel::getSourceTerms() -{ - Terms termsAvailable; - - listView()->applyToAllSources([&](SourceItem *sourceItem, const Terms& terms) - { - _connectSourceControls(sourceItem); - termsAvailable.add(terms); - }); - - return termsAvailable; -} - -ListModel *ListModel::getSourceModelOfTerm(const Term &term) -{ - ListModel* result = nullptr; - - listView()->applyToAllSources([&](SourceItem *sourceItem, const Terms& terms) - { - if (terms.contains(term)) - result = sourceItem->sourceListModel(); - }); - - return result; -} - -void ListModel::setRowComponent(QQmlComponent* rowComponent) -{ - _rowComponent = rowComponent; -} - -void ListModel::setUpRowControls() -{ - if (_rowComponent == nullptr) - return; - - QStringList keys; - int row = 0; - for (const Term& term : terms()) - { - const QString& key = term.asQString(); - keys.append(key); - if (!_rowControlsMap.contains(key)) - { - bool hasOptions = _rowControlsValues.contains(key); - RowControls* rowControls = new RowControls(this, _rowComponent, _rowControlsValues[key]); - _rowControlsMap[key] = rowControls; - rowControls->init(row, term, !hasOptions); - } - else - _rowControlsMap[key]->setContext(row, key); - row++; - } - - for (const QString& key : _rowControlsMap.keys()) - if (!keys.contains(key)) - // If some row controls are not used anymore, if they use some sources, they must be disconnected from these sources - // If a source changes and emits a signal, these controls should not be activated (cf. https://github.com/jasp-stats/jasp-test-release/issues/1786) - _rowControlsMap[key]->disconnectControls(); -} - -ListModel::RowControlsValues ListModel::getTermsWithComponentValues() const -{ - RowControlsValues result; - - for (const Term& term : _terms) - { - QMap componentValues; - RowControls* rowControls = _rowControlsMap.value(term.asQString()); - if (rowControls) - { - const QMap& controlsMap = rowControls->getJASPControlsMap(); - QMapIterator it(controlsMap); - while (it.hasNext()) - { - it.next(); - JASPControl* control = it.value(); - BoundControl* boundControl = control->boundControl(); - if (boundControl) - componentValues[it.key()] = boundControl->boundValue(); - } - } - - result[term.asQString()] = componentValues; - } - - return result; -} - -JASPControl *ListModel::getRowControl(const QString &key, const QString &name) const -{ - JASPControl* control = nullptr; - - RowControls* rowControls = _rowControlsMap.value(key); - if (rowControls) - { - const QMap& controls = rowControls->getJASPControlsMap(); - if (controls.contains(name)) - control = controls[name]; - } - - return control; -} - -bool ListModel::addRowControl(const QString &key, JASPControl *control) -{ - return _rowControlsMap.contains(key) ? _rowControlsMap[key]->addJASPControl(control) : false; -} - -QStringList ListModel::termsTypes() -{ - QSet types; - - for (const Term& term : terms()) - { - columnType type = columnType(requestInfo(VariableInfo::VariableType, term.asQString()).toInt()); - if (type != columnType::unknown) - types.insert(tq(columnTypeToString(type))); - } - - return types.values(); -} - -int ListModel::searchTermWith(QString searchString) -{ - int result = -1; - const Terms& myTerms = terms(); - int startIndex = 0; - if (_selectedItems.length() > 0) - { - startIndex = _selectedItems.first(); - if (searchString.length() == 1) - startIndex++; - } - - if (searchString.length() > 0) - { - QString searchStringLower = searchString.toLower(); - for (size_t i = 0; i < myTerms.size(); i++) - { - size_t index = (size_t(startIndex) + i) % myTerms.size(); - const Term& term = myTerms.at(index); - if (term.asQString().toLower().startsWith(searchStringLower)) - { - result = int(index); - break; - } - } - } - - return result; -} - -void ListModel::_addSelectedItemType(int _index) -{ - QString type = data(index(_index, 0), ListModel::ColumnTypeRole).toString(); - if (!type.isEmpty()) - _selectedItemsTypes.insert(type); -} - -void ListModel::selectItem(int _index, bool _select) -{ - bool changed = false; - if (_select) - { - if (data(index(_index, 0), ListModel::SelectableRole).toBool()) - { - int i = 0; - for (; i < _selectedItems.length(); i++) - { - if (_selectedItems[i] == _index) - break; - else if (_selectedItems[i] > _index) - { - _selectedItems.insert(i, _index); - _addSelectedItemType(_index); - changed = true; - break; - } - } - if (i == _selectedItems.length()) - { - _selectedItems.append(_index); - _addSelectedItemType(_index); - changed = true; - } - } - } - else - { - if (_selectedItems.removeAll(_index) > 0) - { - _selectedItemsTypes.clear(); - for (int i : _selectedItems) - { - QString type = data(index(i, 0), ListModel::ColumnTypeRole).toString(); - if (!type.isEmpty()) - _selectedItemsTypes.insert(type); - } - changed = true; - } - } - - if (changed) - { - emit dataChanged(index(_index, 0), index(_index, 0), { ListModel::SelectedRole }); - emit selectedItemsChanged(); - } -} - -void ListModel::clearSelectedItems(bool emitSelectedChange) -{ - QList selected = _selectedItems; - - _selectedItems.clear(); - _selectedItemsTypes.clear(); - - for (int i : selected) - emit dataChanged(index(i,0), index(i,0), { ListModel::SelectedRole }); - - if (selected.length() > 0 && emitSelectedChange) - emit selectedItemsChanged(); -} - -void ListModel::setSelectedItem(int _index) -{ - if (_selectedItems.size() == 1 && _selectedItems[0] == _index) return; - - clearSelectedItems(false); - selectItem(_index, true); -} - -void ListModel::selectAllItems() -{ - int nbTerms = rowCount(); - if (nbTerms == 0) return; - - _selectedItems.clear(); - _selectedItemsTypes.clear(); - - for (int i = 0; i < nbTerms; i++) - { - if (data(index(i, 0), ListModel::SelectableRole).toBool()) - { - _selectedItems.append(i); - _addSelectedItemType(i); - } - } - - emit dataChanged(index(0, 0), index(nbTerms - 1, 0), { ListModel::SelectedRole }); - emit selectedItemsChanged(); -} - -void ListModel::sourceTermsReset() -{ - _initTerms(getSourceTerms(), RowControlsValues(), false); -} - -int ListModel::rowCount(const QModelIndex &) const -{ - return int(terms().size()); -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - const Terms& myTerms = terms(); - size_t row_t = size_t(row); - if (row_t >= myTerms.size()) - return QVariant(); - - switch (role) - { - case Qt::DisplayRole: - case ListModel::NameRole: return QVariant(myTerms.at(row_t).asQString()); - case ListModel::SelectableRole: return !myTerms.at(row_t).asQString().isEmpty(); - case ListModel::SelectedRole: return _selectedItems.contains(row); - case ListModel::RowComponentRole: - { - QString term = myTerms.at(row_t).asQString(); - return _rowControlsMap.contains(term) ? QVariant::fromValue(_rowControlsMap[term]->getRowObject()) : QVariant(); - } - case ListModel::TypeRole: return listView()->containsVariables() ? "variable" : ""; - case ListModel::ColumnTypeRole: - case ListModel::ColumnTypeIconRole: - case ListModel::ColumnTypeDisabledIconRole: - { - const Term& term = myTerms.at(row_t); - if (!listView()->containsVariables() || term.size() != 1) return ""; - if (role == ListModel::ColumnTypeRole) return requestInfo(VariableInfo::VariableTypeName, term.asQString()); - else if (role == ListModel::ColumnTypeIconRole) return requestInfo(VariableInfo::VariableTypeIcon, term.asQString()); - else if (role == ListModel::ColumnTypeDisabledIconRole) return requestInfo(VariableInfo::VariableTypeDisabledIcon, term.asQString()); - break; - } - } - - return QVariant(); -} - -const QString &ListModel::name() const -{ - return _listView->name(); -} - -Terms ListModel::filterTerms(const Terms& terms, const QStringList& filters) -{ - if (filters.empty()) return terms; - - QStringList values = terms.asQList(); // Use QStringList instead of Terms type because Terms eliminates automatically double values and that can generate mistakes expecially when indexes are used with the discard predicate. - - const static QString typeIs = "type="; - const static QString controlIs = "control="; - const static QString discardIs = "discardIndex="; - - QString useTheseVariableTypes, useThisControl, discardIndexes; - - for (const QString& filter : filters) - { - if (filter.startsWith(typeIs)) useTheseVariableTypes = filter.right(filter.length() - typeIs.length()); - if (filter.startsWith(controlIs)) useThisControl = filter.right(filter.length() - controlIs.length()); - if (filter.startsWith(discardIs)) discardIndexes = filter.right(filter.length() - discardIs.length()); - } - - if (!useThisControl.isEmpty()) - { - QStringList controlValues; - for (const QString& value : values) - { - RowControls* rowControls = _rowControlsMap.value(value); - if (rowControls) - { - JASPControl* control = rowControls->getJASPControl(useThisControl); - - if (control) controlValues.append(control->property("value").toString()); - else Log::log() << "Could not find control " << useThisControl << " in list view " << name() << std::endl; - } - } - values = controlValues; - } - - if (!discardIndexes.isEmpty()) - { - std::vector discarded(values.size(), false ); - QStringList indexes = discardIndexes.split("|"); - for (const QString& index : indexes) - { - QString cleanIndex = index; - if (index.contains('-')) - { - bool lowOk = false, highOk = false; - int low = index.first(index.indexOf('-')).toInt(&lowOk); - int high = index.sliced(index.indexOf('-') + 1).toInt(&highOk); - if (lowOk && highOk && low >= 0 && high > low) - { - for (int i = low; i <= high; i++) - if (i < discarded.size()) - discarded[i] = true; - } - } - else - { - bool ok = false; - int i = index.toInt(&ok); - if (ok && i >= 0 && i < discarded.size()) - discarded[i] = true; - } - } - - QStringList selectedValues; - for (int i = 0; i < discarded.size(); i++) - { - if (!discarded[i]) - selectedValues.append(values.at(i)); - } - values = selectedValues; - } - - if (!useTheseVariableTypes.isEmpty()) - { - QStringList typesStr = useTheseVariableTypes.split("|"); - QList types; - - for (const QString& typeStr : typesStr) - { - columnType type = columnTypeFromString(fq(typeStr), columnType::unknown); - if (type != columnType::unknown) - types.push_back(type); - } - - QStringList rightValues; - for (const QString& value : values) - { - columnType type = columnType(requestInfo(VariableInfo::VariableType, value).toInt()); - if (types.contains(type)) - rightValues.append(value); - } - values = rightValues; - } - - if (filters.contains("levels")) - { - QStringList allLabels; - for (const QString& value : values) - { - QStringList labels = requestInfo(VariableInfo::Labels, value).toStringList(); - if (labels.size() > 0) allLabels.append(labels); - else allLabels.append(value); - } - - values = allLabels; - } - - - return values; -} - -Terms ListModel::termsEx(const QStringList &filters) -{ - return filterTerms(terms(), filters); -} - -void ListModel::sourceNamesChanged(QMap map) -{ - QMap changedNamesMap; - QSet changedIndexes; - - QMapIterator it(map); - while (it.hasNext()) - { - it.next(); - const QString& oldName = it.key(), newName = it.value(); - QSet indexes = _terms.replaceVariableName(oldName.toStdString(), newName.toStdString()); - if (indexes.size() > 0) - { - changedNamesMap[oldName] = newName; - changedIndexes += indexes; - } - } - - for (int i : changedIndexes) - { - QModelIndex ind = index(i, 0); - emit dataChanged(ind, ind); - } - - if (changedNamesMap.size() > 0) - emit namesChanged(changedNamesMap); -} - -int ListModel::sourceColumnTypeChanged(QString name) -{ - int i = terms().indexOf(name); - if (i >= 0) - { - QModelIndex ind = index(i, 0); - - //keep selected item types up to date - if(_selectedItems.contains(i)) - { - _selectedItemsTypes.clear(); - for(int item : _selectedItems) - _addSelectedItemType(item); - emit selectedItemsTypesChanged(); - } - - emit dataChanged(ind, ind, {ListModel::ColumnTypeRole, ListModel::ColumnTypeIconRole, ListModel::ColumnTypeDisabledIconRole}); - emit columnTypeChanged(name); - } - - return i; -} - -bool ListModel::sourceLabelsChanged(QString columnName, QMap changedLabels) -{ - bool change = false; - if (_columnsUsedForLabels.contains(columnName)) - { - if (changedLabels.size() == 0) - { - // The changed labels are not specified. Requery the source. - sourceTermsReset(); - change = true; - } - else - { - QMap newChangedValues; - QMapIterator it(changedLabels); - while (it.hasNext()) - { - it.next(); - if (terms().contains(it.key())) - { - change = true; - newChangedValues[it.key()] = it.value(); - } - } - sourceNamesChanged(newChangedValues); - } - } - else - { - change = terms().contains(columnName); - if (change) - emit labelsChanged(columnName, changedLabels); - } - - return change; -} - -bool ListModel::sourceLabelsReordered(QString columnName) -{ - bool change = false; - if (_columnsUsedForLabels.contains(columnName)) - { - sourceTermsReset(); - change = true; - } - else - { - change = terms().contains(columnName); - if (change) - emit labelsReordered(columnName); - } - - return change; -} - -void ListModel::sourceColumnsChanged(QStringList columns) -{ - QStringList changedColumns; - - for (const QString& column : columns) - { - if (_columnsUsedForLabels.contains(column)) - sourceLabelsChanged(column); - else if (terms().contains(column)) - changedColumns.push_back(column); - } - - if (changedColumns.size() > 0) - { - emit columnsChanged(changedColumns); - - if (listView()->isBound()) - listView()->form()->refreshAnalysis(); - } -} - -void ListModel::dataChangedHandler(const QModelIndex &, const QModelIndex &, const QVector &roles) -{ - if (roles.isEmpty() || roles.size() > 1 || roles[0] != ListModel::SelectedRole) - emit termsChanged(); -} - -void ListModel::_setTerms(const Terms &terms, const Terms& parentTerms) -{ - _terms.removeParent(); - _setTerms(terms); - _terms.setSortParent(parentTerms); -} - -void ListModel::_setTerms(const std::vector &terms) -{ - _terms.set(terms); - setUpRowControls(); -} - -void ListModel::_setTerms(const Terms &terms) -{ - _terms.set(terms); - setUpRowControls(); -} - -void ListModel::_removeTerms(const Terms &terms) -{ - _terms.remove(terms); - setUpRowControls(); -} - -void ListModel::_removeTerm(int index) -{ - _terms.remove(size_t(index)); - setUpRowControls(); -} - -void ListModel::_removeTerm(const Term &term) -{ - _terms.remove(term); - setUpRowControls(); -} - -void ListModel::_removeLastTerm() -{ - if (_terms.size() > 0) - _terms.remove(_terms.size() - 1); -} - -void ListModel::_addTerms(const Terms &terms) -{ - _terms.add(terms); - setUpRowControls(); -} - -void ListModel::_addTerm(const QString &term, bool isUnique) -{ - _terms.add(term, isUnique); - setUpRowControls(); -} - -void ListModel::_replaceTerm(int index, const Term &term) -{ - _terms.replace(index, term); - setUpRowControls(); -} diff --git a/QMLComponents/models/listmodel.h b/QMLComponents/models/listmodel.h deleted file mode 100644 index af5c09b5dfe..00000000000 --- a/QMLComponents/models/listmodel.h +++ /dev/null @@ -1,153 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODEL_H -#define LISTMODEL_H - -#include -#include - -#include "common.h" -#include "terms.h" -#include -#include "variableinfo.h" - -class JASPListControl; -class RowControls; -class JASPControl; -class BoundControl; -class SourceItem; - -class ListModel : public QAbstractTableModel, public VariableInfoConsumer -{ - Q_OBJECT - -public: - enum ListModelRoles - { - NameRole = Qt::UserRole + 1, - TypeRole, - SelectedRole, - SelectableRole, - ColumnTypeRole, - ColumnTypeIconRole, - ColumnTypeDisabledIconRole, - RowComponentRole, - ValueRole, - VirtualRole, - DeletableRole - }; - typedef QMap RowControlMap; - typedef QMap > RowControlsValues; - typedef QMapIterator > RowControlsValuesIterator; - - ListModel(JASPListControl* listView); - - QHash roleNames() const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 1; } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - JASPListControl* listView() const { return _listView; } - const QString & name() const; - Terms termsEx(const QStringList& what); - const Terms & terms() const { return _terms; } - virtual Terms filterTerms(const Terms& terms, const QStringList& filters); - bool needsSource() const { return _needsSource; } - void setNeedsSource(bool needs) { _needsSource = needs; } - virtual QString getItemType(const Term& term) const { return _itemType; } - void setItemType(QString type) { _itemType = type; } - void addControlError(const QString& error) const; - virtual void refresh(); - virtual void initTerms(const Terms &terms, const RowControlsValues& allValuesMap = RowControlsValues(), bool reInit = false); - Terms getSourceTerms(); - ListModel* getSourceModelOfTerm(const Term& term); - void setColumnsUsedForLabels(const QStringList& columns) { _columnsUsedForLabels = columns; } - void setRowComponent(QQmlComponent* rowComponents); - virtual void setUpRowControls(); - const RowControlMap & getAllRowControls() const { return _rowControlsMap; } - RowControlsValues getTermsWithComponentValues() const; - RowControls* getRowControls(const QString& key) const { return _rowControlsMap.value(key); } - virtual JASPControl * getRowControl(const QString& key, const QString& name) const; - virtual bool addRowControl(const QString& key, JASPControl* control); - QStringList termsTypes(); - - Q_INVOKABLE int searchTermWith(QString searchString); - Q_INVOKABLE void selectItem(int _index, bool _select); - Q_INVOKABLE void clearSelectedItems(bool emitSelectedChange = true); - Q_INVOKABLE void setSelectedItem(int _index); - Q_INVOKABLE void selectAllItems(); - Q_INVOKABLE QList selectedItems() { return _selectedItems; } - Q_INVOKABLE QList selectedItemsTypes() { return QList(_selectedItemsTypes.begin(), _selectedItemsTypes.end()); } - - -signals: - void termsChanged(); // Used to signal all kinds of changes in the model. Do not call it directly - void namesChanged(QMap map); - void columnTypeChanged(QString name); - void labelsChanged(QString columnName, QMap = {}); - void labelsReordered(QString columnName); - void columnsChanged(QStringList columns); - void selectedItemsChanged(); - void oneTermChanged(const QString& oldName, const QString& newName); - void selectedItemsTypesChanged(); - -public slots: - virtual void sourceTermsReset(); - virtual void sourceNamesChanged(QMap map); - virtual int sourceColumnTypeChanged(QString colName); - virtual bool sourceLabelsChanged(QString columnName, QMap changedLabels = {}); - virtual bool sourceLabelsReordered(QString columnName); - virtual void sourceColumnsChanged(QStringList columns); - - void dataChangedHandler(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); - -protected: - void _setTerms(const Terms& terms); - void _setTerms(const Terms& terms, const Terms& parentTerms); - void _setTerms(const std::vector& terms); - void _removeTerms(const Terms& terms); - void _removeTerm(int index); - void _removeTerm(const Term& term); - void _removeLastTerm(); - void _addTerms(const Terms& terms); - void _addTerm(const QString& term, bool isUnique = true); - void _replaceTerm(int index, const Term& term); - void _connectAllSourcesControls(); - - QString _itemType; - bool _needsSource = true; - QMap _rowControlsMap; - QQmlComponent * _rowComponent = nullptr; - RowControlsValues _rowControlsValues; - QList _rowControlsConnected; - QList _selectedItems; - QSet _selectedItemsTypes; - QStringList _columnsUsedForLabels; - -private: - void _addSelectedItemType(int _index); - void _initTerms(const Terms &terms, const RowControlsValues& allValuesMap, bool initRowControls = true); - void _connectSourceControls(SourceItem* sourceItem); - - JASPListControl* _listView = nullptr; - Terms _terms; - -}; - -#endif // LISTMODEL_H diff --git a/QMLComponents/models/listmodelassignedinterface.cpp b/QMLComponents/models/listmodelassignedinterface.cpp deleted file mode 100644 index 8940cc4f816..00000000000 --- a/QMLComponents/models/listmodelassignedinterface.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelassignedinterface.h" -#include "controls/variableslistbase.h" -#include "analysisform.h" - -ListModelAssignedInterface::ListModelAssignedInterface(JASPListControl* listView) - : ListModelDraggable(listView) - , _availableModel(nullptr) -{ - _needsSource = false; -} - -void ListModelAssignedInterface::refresh() -{ - bool doRefresh = true; - QList toRemove; - for (int i = 0; i < rowCount(); i++) - { - QString term = data(index(i, 0)).toString(); - if (!isAllowed(term)) - toRemove.push_back(i); - } - - if (toRemove.count() > 0) - { - VariablesListBase* qmlListView = dynamic_cast(listView()); - if (qmlListView) - { - qmlListView->moveItems(toRemove, _availableModel); - doRefresh = false; - } - } - - if (doRefresh) - ListModelDraggable::refresh(); -} - -void ListModelAssignedInterface::setAvailableModel(ListModelAvailableInterface *source) -{ - _availableModel = source; -} - -int ListModelAssignedInterface::sourceColumnTypeChanged(QString name) -{ - int index = ListModelDraggable::sourceColumnTypeChanged(name); - VariablesListBase* qmlListView = dynamic_cast(listView()); - - if (qmlListView && index >= 0 && index < int(terms().size())) - { - if (!isAllowed(terms().at(size_t(index)))) - { - QList indexes = {index}; - qmlListView->moveItems(indexes, _availableModel); - ListModelDraggable::refresh(); - } - // Force the analysis to be rerun - emit qmlListView->boundValueChanged(qmlListView); - } - - return index; -} - -bool ListModelAssignedInterface::sourceLabelsChanged(QString columnName, QMap changedLabels) -{ - bool change = ListModelDraggable::sourceLabelsChanged(columnName, changedLabels); - - if (change && listView() && listView()->form()) - listView()->form()->refreshAnalysis(); - - return change; -} - -bool ListModelAssignedInterface::sourceLabelsReordered(QString columnName) -{ - bool change = ListModelDraggable::sourceLabelsReordered(columnName); - - if (change && listView() && listView()->form()) - listView()->form()->refreshAnalysis(); - - return change; -} - -bool ListModelAssignedInterface::checkAllowedTerms(Terms& terms) -{ - if (!_availableModel) return true; - - Terms notAllowedTerms, allowedTerms; - for (const Term& term : terms) - { - if (isAllowed(term)) - allowedTerms.add(term); - else - notAllowedTerms.add(term); - } - if (notAllowedTerms.size() == 0) return true; - - terms.set(allowedTerms); - if (!_availableModel->copyTermsWhenDropped()) - _availableModel->addTerms(notAllowedTerms); - - QString notAllowedTermsStr = notAllowedTerms.asQList().join(", "); - if (notAllowedTerms.size() == 1) - listView()->addControlWarningTemporary(tr("This variable has been removed, because it is not allowed: %1").arg(notAllowedTermsStr)); - else - listView()->addControlWarningTemporary(tr("These variables have been removed, because they are not allowed: %1").arg(notAllowedTermsStr)); - - return false; -} diff --git a/QMLComponents/models/listmodelassignedinterface.h b/QMLComponents/models/listmodelassignedinterface.h deleted file mode 100644 index 7984ab88b11..00000000000 --- a/QMLComponents/models/listmodelassignedinterface.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELASSIGNEDINTERFACE_H -#define LISTMODELASSIGNEDINTERFACE_H - -#include "listmodeldraggable.h" -#include "listmodelavailableinterface.h" - -class ListModelAssignedInterface : public ListModelDraggable -{ - Q_OBJECT -public: - ListModelAssignedInterface(JASPListControl* listView); - - void refresh() override; - - virtual void setAvailableModel(ListModelAvailableInterface *availableModel); - ListModelAvailableInterface* availableModel() const { return _availableModel; } - bool checkAllowedTerms(Terms& terms); - -public slots: - virtual void availableTermsResetHandler(Terms termsAdded, Terms termsRemoved) {} - int sourceColumnTypeChanged(QString name) override; - bool sourceLabelsChanged(QString columnName, QMap changedLabels) override; - bool sourceLabelsReordered(QString columnName) override; - -protected: - ListModelAvailableInterface* _availableModel = nullptr; -}; - -#endif // LISTMODELASSIGNEDINTERFACE_H diff --git a/QMLComponents/models/listmodelavailableinterface.cpp b/QMLComponents/models/listmodelavailableinterface.cpp deleted file mode 100644 index ed8aef178aa..00000000000 --- a/QMLComponents/models/listmodelavailableinterface.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelavailableinterface.h" -#include "listmodelassignedinterface.h" -#include "controls/jasplistcontrol.h" -#include "log.h" - -void ListModelAvailableInterface::initTerms(const Terms &terms, const RowControlsValues&, bool) -{ - beginResetModel(); - - _allTerms = _allSortedTerms = terms; - _setTerms(terms, _allSortedTerms); - - if (currentSortType() != SortType::None) - Sortable::sortItems(); - - removeTermsInAssignedList(); - endResetModel(); -} - -void ListModelAvailableInterface::sortItems(SortType sortType) -{ - beginResetModel(); - - switch(sortType) - { - case SortType::None: - { - Terms allowed, forbidden; - - for (const Term &term : _allTerms) - { - if ( ! isAllowed(term)) forbidden.add(term); - else allowed.add(term); - } - - _allTerms.clear(); - _allTerms.add(allowed); - _allTerms.add(forbidden); - _allSortedTerms = _allTerms; - break; - } - - case SortType::SortByName: - { - QList sortedTerms = _allSortedTerms.asQList(); - std::sort(sortedTerms.begin(), sortedTerms.end(), - [&](const QString& a, const QString& b) { - return a.compare(b, Qt::CaseInsensitive) < 0; - }); - _allSortedTerms = Terms(sortedTerms); - break; - } - - case SortType::SortByType: - { - QList termsList = _allSortedTerms.asQList(); - QList > termsTypeList; - - for (const QString& term : termsList) - termsTypeList.push_back(QPair(term, requestInfo(VariableInfo::VariableType, term).toInt())); - - std::sort(termsTypeList.begin(), termsTypeList.end(), - [&](const QPair& a, const QPair& b) { - return a.second - b.second > 0; - }); - - QList sortedTerms; - - for (const auto& term : termsTypeList) - sortedTerms.push_back(term.first); - - _allSortedTerms = Terms(sortedTerms); - break; - } - - default: - Log::log() << "Unimplemented sort in ListModelAvailableInterface::sortItems!"; - break; - } - - Terms orgTerms = terms(); - _setTerms(orgTerms); // This will reorder the terms - - endResetModel(); -} - -void ListModelAvailableInterface::sourceTermsReset() -{ - resetTermsFromSources(); -} - -void ListModelAvailableInterface::sourceNamesChanged(QMap map) -{ - ListModelDraggable::sourceNamesChanged(map); - - // Not only the terms must be changed, but also the allTerms: allTerms keeps all terms that an - // available model can have: this is its own terms and the terms assigned in its assigned models. - QMap allTermsChangedMap; - QMapIterator it(map); - - while (it.hasNext()) - { - it.next(); - const QString& oldName = it.key(), newName = it.value(); - - QSet allIndexes = _allTerms.replaceVariableName(oldName.toStdString(), newName.toStdString()); - - if (allIndexes.size() > 0) - allTermsChangedMap[oldName] = newName; - } - - if (allTermsChangedMap.size() > 0) - emit namesChanged(allTermsChangedMap); -} - -void ListModelAvailableInterface::sourceColumnsChanged(QStringList columns) -{ - ListModelDraggable::sourceColumnsChanged(columns); - - QStringList changedColumns; - - for (const QString& column : columns) - { - if (_allTerms.contains(column)) - changedColumns.push_back(column); - } - - if (changedColumns.size() > 0) - emit columnsChanged(changedColumns); -} - -int ListModelAvailableInterface::sourceColumnTypeChanged(QString name) -{ - int index = ListModelDraggable::sourceColumnTypeChanged(name); - - if (index == -1 && _allTerms.contains(name)) - emit columnTypeChanged(name); - - return index; -} - -bool ListModelAvailableInterface::sourceLabelsChanged(QString columnName, QMap changedLabels) -{ - bool change = ListModelDraggable::sourceLabelsChanged(columnName, changedLabels); - - if (!change && _allTerms.contains(columnName)) - emit labelsChanged(columnName, changedLabels); - - return change; -} - -bool ListModelAvailableInterface::sourceLabelsReordered(QString columnName) -{ - bool change = ListModelDraggable::sourceLabelsReordered(columnName); - - if (!change && _allTerms.contains(columnName)) - emit labelsReordered(columnName); - - return change; -} - -void ListModelAvailableInterface::removeTermsInAssignedList() -{ - beginResetModel(); - - Terms newTerms = _allSortedTerms; - - for (ListModelAssignedInterface* modelAssign : assignedModel()) - { - Terms assignedTerms = modelAssign->terms(); - if (assignedTerms.discardWhatIsntTheseTerms(_allSortedTerms)) - modelAssign->initTerms(assignedTerms, RowControlsValues(), true); // initTerms call removeTermsInAssignedList - if (!modelAssign->copyTermsWhenDropped()) - newTerms.remove(assignedTerms); - } - - _setTerms(newTerms, _allSortedTerms); - - endResetModel(); -} - -void ListModelAvailableInterface::addAssignedModel(ListModelAssignedInterface *assignedModel) -{ - _assignedModels.push_back(assignedModel); - - connect(assignedModel, &ListModelAssignedInterface::destroyed, this, &ListModelAvailableInterface::removeAssignedModel ); - connect(this, &ListModelAvailableInterface::availableTermsReset, assignedModel, &ListModelAssignedInterface::availableTermsResetHandler ); - connect(this, &ListModelAvailableInterface::namesChanged, assignedModel, &ListModelAssignedInterface::sourceNamesChanged ); - connect(this, &ListModelAvailableInterface::columnsChanged, assignedModel, &ListModelAssignedInterface::sourceColumnsChanged ); - connect(this, &ListModelAvailableInterface::columnTypeChanged, assignedModel, &ListModelAssignedInterface::sourceColumnTypeChanged ); - connect(this, &ListModelAvailableInterface::labelsChanged, assignedModel, &ListModelAssignedInterface::sourceLabelsChanged ); - connect(this, &ListModelAvailableInterface::labelsReordered, assignedModel, &ListModelAssignedInterface::sourceLabelsReordered ); - connect(listView(), &JASPListControl::containsVariablesChanged, assignedModel->listView(), &JASPListControl::setContainsVariables ); - connect(listView(), &JASPListControl::containsInteractionsChanged, assignedModel->listView(), &JASPListControl::setContainsInteractions ); -} - -void ListModelAvailableInterface::removeAssignedModel(ListModelDraggable* assignedModel) -{ - _assignedModels.removeAll(qobject_cast(assignedModel)); -} - diff --git a/QMLComponents/models/listmodelavailableinterface.h b/QMLComponents/models/listmodelavailableinterface.h deleted file mode 100644 index 6bc9e445300..00000000000 --- a/QMLComponents/models/listmodelavailableinterface.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELAVAILABLEINTERFACE_H -#define LISTMODELAVAILABLEINTERFACE_H - -#include "listmodeldraggable.h" -#include "terms.h" -#include "variableinfo.h" -#include "sortmenumodel.h" -#include "sortable.h" - -class ListModelAssignedInterface; - -class ListModelAvailableInterface: public ListModelDraggable, public Sortable -{ - Q_OBJECT -public: - ListModelAvailableInterface(JASPListControl* listView) - : ListModelDraggable(listView) {} - - virtual const Terms& allTerms() const { return _allSortedTerms; } - void initTerms(const Terms &terms, const RowControlsValues& _rowControlsValues = RowControlsValues(), bool reInit = false) override; - virtual void resetTermsFromSources(bool updateAssigned = true) = 0; - virtual void removeTermsInAssignedList(); - - void sortItems(SortType sortType) override; - - void addAssignedModel(ListModelAssignedInterface* model); - const QList& assignedModel() const { return _assignedModels; } - -signals: - void availableTermsReset(Terms termsAdded, Terms termsRemoved); - -public slots: - void sourceTermsReset() override; - void sourceNamesChanged(QMap map) override; - void sourceColumnsChanged(QStringList columns) override; - int sourceColumnTypeChanged(QString name) override; - bool sourceLabelsChanged(QString columnName, QMap = {}) override; - bool sourceLabelsReordered(QString columnName) override; - void removeAssignedModel(ListModelDraggable* model); - void clearAssignedModels() { _assignedModels.clear(); } - -protected: - Terms _allTerms; - Terms _allSortedTerms; - - QList _assignedModels; -}; - -#endif // LISTMODELTERMSAVAILABLEINTERFACE_H diff --git a/QMLComponents/models/listmodelcustomcontrasts.cpp b/QMLComponents/models/listmodelcustomcontrasts.cpp deleted file mode 100644 index 407ca654859..00000000000 --- a/QMLComponents/models/listmodelcustomcontrasts.cpp +++ /dev/null @@ -1,409 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "log.h" -#include "qutils.h" -#include "listmodelcustomcontrasts.h" -#include "analysisform.h" -#include "r_functionwhitelist.h" -#include "controls/tableviewbase.h" -#include "listmodelfactorlevels.h" - -ListModelCustomContrasts::ListModelCustomContrasts(TableViewBase *parent) : ListModelTableViewBase(parent) -{ - _keepRowsOnReset = false; - - _tableTerms.colNames.push_back(getDefaultColName(0)); - _tableTerms.values.push_back({}); - _loadColumnInfo(); - - _needsSource = _colName.isEmpty(); - - parent->setProperty("parseDefaultValue", false); - - connect(this, &ListModelCustomContrasts::variableCountChanged, _tableView, &TableViewBase::variableCountChanged); - connect(listView(), SIGNAL(scaleFactorChanged()), this, SLOT(scaleFactorChanged())); - connect(VariableInfo::info(), &VariableInfo::labelsChanged, this, &ListModelCustomContrasts::sourceLabelsChanged); - connect(VariableInfo::info(), &VariableInfo::labelsReordered, this, &ListModelCustomContrasts::sourceLabelsReordered); - connect(VariableInfo::info(), &VariableInfo::columnsChanged, this, &ListModelCustomContrasts::sourceColumnsChanged); - connect(infoProviderModel(), &QAbstractItemModel::modelReset , this, &ListModelCustomContrasts::sourceTermsReset); -} - -void ListModelCustomContrasts::sourceTermsReset() -{ - _resetValuesEtc(); -} - -QStringList ListModelCustomContrasts::_getVariables() -{ - if (!_colName.isEmpty()) - return Term::readTerm(_colName).components(); - else - return getSourceTerms().asQList(); -} - -void ListModelCustomContrasts::getVariablesAndLabels(QStringList& variables, QVector >& allLabels) -{ - variables = _getVariables(); - - // First set all combinations of all labels in values - for (const QString& newVariable : variables) - { - QList labels; - if (_factors.contains(newVariable)) - labels = _factors[newVariable]; - else - { - columnType colType = columnType(requestInfo(VariableInfo::VariableType, newVariable).toInt()); - if (colType == columnType::scale) - { - if (_scaleFactor == 0) - labels = {"0"}; - else - { - labels.push_back(QString::number(-_scaleFactor)); - labels.push_back("0"); - labels.push_back(QString::number(_scaleFactor)); - } - } - else - labels = requestInfo(VariableInfo::Labels, newVariable).toStringList(); - } - - QVector > copyAllLabels = allLabels; - int len = copyAllLabels.length() > 0 ? copyAllLabels[0].length() : 1; - allLabels.clear(); - - for (const auto & copyValue : copyAllLabels) - { - QVector oneRow; - for (int i = 0; i < labels.size(); i++) - oneRow.append(copyValue); - allLabels.push_back(oneRow); - } - - QVector lastRow; - for (const QString& label : labels) - lastRow.insert(lastRow.length(), len, label); - allLabels.push_back(lastRow); - } - -} - -void ListModelCustomContrasts::_resetValuesEtc() -{ - QStringList newVariables; - QVector > newValues; - - getVariablesAndLabels(newVariables, newValues); - - beginResetModel(); - - int nbContrast = int(columnCount()) - _tableTerms.variables.size(); - - // Maps the new variables with the old ones (if they existed) - QMap variablesMap; - for (int i = 0; i < newVariables.length(); i++) - variablesMap[i] = _tableTerms.variables.indexOf(newVariables.at(i)); - - int newMaxRows = newValues.length() > 0 ? newValues[0].length() : 0; - - // Make a mapping between the new rows and the old ones - QMap rowMapping; - - for (int row = 0; row < newMaxRows; row++) - { - // For this, for each row, we first build a boolean matrix that tells where the labels in the new values are found in the old values. - QVector > allBools; - - for (int col = 0; col < newVariables.length(); col++) - { - if (variablesMap[col] >= 0 && variablesMap[col] < _tableTerms.values.length()) - { - QVector bools; - QVariant label = newValues[col][row]; - const QVector& oldValues = _tableTerms.values[variablesMap[col]]; - for (int oldRow = 0; oldRow < oldValues.length(); oldRow++) - bools.push_back(oldValues.at(oldRow) == label); - - allBools.push_back(bools); - } - } - - int bestFitRow = -1; - int bestFit = -1; - - // From the boolean matrix, find the row where the new labels are found the most. - for (int oldRow = 0; oldRow < rowCount(); oldRow++) - { - int max = 0; - for (int oldCol = 0; oldCol < allBools.length(); oldCol++) - { - if (allBools[oldCol].length() > oldRow && allBools[oldCol][oldRow]) - { - max++; - if (max > bestFit) - { - bestFitRow = oldRow; - bestFit = max; - } - } - } - } - - rowMapping[row] = bestFitRow; - } - - if (nbContrast == 0) - { - // No contrast yet: fill contrasts with default values. - QVector contrasts; - for (int i = 0; i < _tableView->initialColumnCount(); i++) - { - for (int row = 0; row < newMaxRows; row++) - contrasts.push_back(_tableView->defaultValue()); - newValues.push_back(contrasts); - } - } - else - { - // For each contrast, set the value corresponding to the rowMapping - for (int i = 0; i < nbContrast; i++) - { - QVector contrasts; - int oldContrastIndex = _tableTerms.variables.length() + i; - - if (_tableTerms.values.length() <= oldContrastIndex) - { - Log::log() << "ListModelCustomContrasts::sourceTermsChanged: Not the same amount of contrasts!!!" << std::endl; - continue; - } - - for (int row = 0; row < newMaxRows; row++) - contrasts.push_back(rowMapping[row] >= 0 ? _tableTerms.values[oldContrastIndex][rowMapping[row]] : _tableView->defaultValue()); - - newValues.push_back(contrasts); - } - } - - _tableTerms.clear(); - - _tableTerms.variables = newVariables; - _tableTerms.values = newValues; - size_t colCount = size_t(_tableTerms.values.length()); - size_t rowCount = _tableTerms.values.length() > 0 ? size_t(_tableTerms.values[0].length()) : 0; - - for (size_t rowNb = 0; rowNb < rowCount; rowNb++) - _tableTerms.rowNames.push_back(getDefaultRowName(rowNb)); - - for (size_t colNb = 0; colNb < colCount; colNb++) - _tableTerms.colNames.push_back(getDefaultColName(colNb)); - - endResetModel(); - - emit columnCountChanged(); - emit rowCountChanged(); - emit variableCountChanged(); -} - - -QString ListModelCustomContrasts::getDefaultColName(size_t index) const -{ - int indexi = int(index); - - if (indexi < _tableTerms.variables.size()) - return _tableTerms.variables.at(indexi); - else - return tr("Contrast %1").arg(indexi - _tableTerms.variables.size() + 1); -} - -void ListModelCustomContrasts::reset() -{ - if (_tableTerms.values.length() <= _tableTerms.variables.length() + _tableView->initialColumnCount()) - return; - - beginResetModel(); - - _tableTerms.values.erase(_tableTerms.values.begin() + _tableTerms.variables.length() + _tableView->initialColumnCount(), _tableTerms.values.end()); - _tableTerms.colNames.erase(_tableTerms.colNames.begin() + _tableTerms.values.length(), _tableTerms.colNames.end()); - - endResetModel(); - - emit columnCountChanged(); -} - -void ListModelCustomContrasts::setup() -{ - QString factorsSourceName = _tableView->property("factorsSource").toString(); - if (!factorsSourceName.isEmpty()) - { - ListModelFactorLevels* factorsSourceModel = dynamic_cast(_tableView->form()->getModel(factorsSourceName)); - if (factorsSourceModel) - { - _setFactorsSource(factorsSourceModel); - connect(factorsSourceModel, &ListModelFactorLevels::termsChanged, this, &ListModelCustomContrasts::factorsSourceChanged); - } - } -} - -QString ListModelCustomContrasts::getItemInputType(const QModelIndex &index) const -{ - if (index.column() >= _tableTerms.variables.length()) - { - if (_tableView->itemType() == JASPControl::ItemType::Double) return "double"; - else return "formula"; - } - else return "string"; -} - -int ListModelCustomContrasts::getMaximumColumnWidthInCharacters(size_t) const -{ - return 5; -} - -bool ListModelCustomContrasts::sourceLabelsChanged(QString columnName, QMap changedLabels) -{ - bool doRefresh = false; - - if (changedLabels.size() == 0) _resetValuesEtc(); - else - { - QMapIterator it(changedLabels); - while (it.hasNext()) - { - it.next(); - if (_labelChanged(columnName, it.key(), it.value())) doRefresh = true; - } - } - if (doRefresh) refresh(); - - return true; -} - -bool ListModelCustomContrasts::_labelChanged(const QString& columnName, const QString& originalLabel, const QString& newLabel) -{ - bool isChanged = false; - int col = _tableTerms.variables.indexOf(columnName); - - if (col >= 0 && col < _tableTerms.values.length()) - { - for (int row = 0; row < _tableTerms.values[col].length(); row++) - { - if (_tableTerms.values[col][row].toString() == originalLabel) - { - _tableTerms.values[col][row] = newLabel; - isChanged = true; - } - } - } - - return isChanged; -} - -void ListModelCustomContrasts::_setFactorsSource(ListModelFactorLevels *factorsSourceModel) -{ - _factorsSourceModel = factorsSourceModel; - - _setFactors(); -} - -void ListModelCustomContrasts::_setFactors() -{ - _factors.clear(); - - if (_factorsSourceModel) - { - std::vector > > factors = _factorsSourceModel->getFactors(); - for (const auto& factor : factors) - { - QList levels; - for (const std::string& level : factor.second) - levels.push_back(QString::fromStdString(level)); - _factors[QString::fromStdString(factor.first)] = levels; - } - } - -} - -void ListModelCustomContrasts::_loadColumnInfo() -{ - setColName( _tableView->property("colName").toString()); -} - -bool ListModelCustomContrasts::sourceLabelsReordered(QString ) -{ - _resetValuesEtc(); - return true; -} - -void ListModelCustomContrasts::sourceColumnsChanged(QStringList columns) -{ - bool doReset = false; - for (const QString& col : columns) - if (_tableTerms.variables.contains(col)) doReset = true; - - if (doReset) _resetValuesEtc(); -} - -void ListModelCustomContrasts::scaleFactorChanged() -{ - double oldScaleFactor = _scaleFactor; - _scaleFactor = listView()->property("scaleFactor").toDouble(); - - QVector scaleVariables; - for (const QString& variable : _tableTerms.variables) - { - if (requestInfo(VariableInfo::VariableType, variable).toInt() == int(columnType::scale)) - scaleVariables.push_back(variable); - } - - if (scaleVariables.length() > 0) - { - if (oldScaleFactor == 0 || _scaleFactor == 0) // this will decrease or increase the number of rows - _resetValuesEtc(); - else - { - beginResetModel(); - for (const QString& scaleVariable : scaleVariables) - { - _labelChanged(scaleVariable, QString::number(-oldScaleFactor), QString::number(-_scaleFactor)); - _labelChanged(scaleVariable, QString::number(oldScaleFactor), QString::number(_scaleFactor)); - } - endResetModel(); - } - } - -} - -void ListModelCustomContrasts::setColName(QString colName) -{ - if (_colName == colName) - return; - - _colName = colName; - - emit colNameChanged(_colName); - - _resetValuesEtc(); -} - -void ListModelCustomContrasts::factorsSourceChanged() -{ - _setFactors(); - _resetValuesEtc(); -} diff --git a/QMLComponents/models/listmodelcustomcontrasts.h b/QMLComponents/models/listmodelcustomcontrasts.h deleted file mode 100644 index 0c5cab84944..00000000000 --- a/QMLComponents/models/listmodelcustomcontrasts.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELCUSTOMCONTRASTS_H -#define LISTMODELCUSTOMCONTRASTS_H - -#include "listmodeltableviewbase.h" - -class ListModelFactorLevels; - -class ListModelCustomContrasts : public ListModelTableViewBase -{ - Q_OBJECT - Q_PROPERTY(QString colName READ colName WRITE setColName NOTIFY colNameChanged ) - -public: - explicit ListModelCustomContrasts(TableViewBase * parent); - - int getMaximumColumnWidthInCharacters(size_t columnIndex) const override; - - QString getDefaultColName(size_t index) const override; - QString getDefaultRowName(size_t index) const override { return QString::number(index + 1); } - - void reset() override; - void setup() override; - bool isEditable(const QModelIndex& index) const override { return index.column() >= _tableTerms.variables.length(); } - QString getItemInputType(const QModelIndex& index) const override; - QString colName() const { return _colName; } - - void getVariablesAndLabels(QStringList& variables, QVector >& allLabels); - -public slots: - void sourceTermsReset() override; - bool sourceLabelsChanged(QString columnName, QMap = {}) override; - bool sourceLabelsReordered(QString columnName) override; - void sourceColumnsChanged(QStringList columns) override; - void scaleFactorChanged(); - void setColName(QString colName); - void factorsSourceChanged(); - -signals: - void colNameChanged(QString colName); - -protected: - int _variableCount = 0; - double _scaleFactor = 1; - ListModelFactorLevels* _factorsSourceModel; - QString _colName; - QMap > _factors; - - -private: - void _resetValuesEtc(); - bool _labelChanged(const QString& columnName, const QString& originalLabel, const QString& newLabel); - void _setFactorsSource(ListModelFactorLevels* factorsSourceModel); - void _setFactors(); - void _loadColumnInfo(); - QStringList _getVariables(); - - -}; - -#endif // LISTMODELCUSTOMCONTRASTS_H diff --git a/QMLComponents/models/listmodeldraggable.cpp b/QMLComponents/models/listmodeldraggable.cpp deleted file mode 100644 index fc31e6139b8..00000000000 --- a/QMLComponents/models/listmodeldraggable.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodeldraggable.h" -#include "analysisform.h" -#include "controls/jasplistcontrol.h" - -ListModelDraggable::ListModelDraggable(JASPListControl* listView) - : ListModel(listView) - , _copyTermsWhenDropped(false) -{ -} - -ListModelDraggable::~ListModelDraggable() -{ - emit destroyed(this); -} - -Terms ListModelDraggable::termsFromIndexes(const QList &indexes) const -{ - Terms result; - const Terms& myTerms = terms(); - for (int index : indexes) - { - size_t index_t = size_t(index); - if (index_t < myTerms.size()) - { - const Term& term = myTerms.at(index_t); - result.add(term); - } - } - - return result; -} - -void ListModelDraggable::removeTerms(const QList &indices) -{ - beginResetModel(); - - Terms termsToRemove; - - for (int index : indices) - if (index < rowCount()) - termsToRemove.add(terms().at(size_t(index))); - - _removeTerms(termsToRemove); - - endResetModel(); -} - - -void ListModelDraggable::moveTerms(const QList &indexes, int dropItemIndex) -{ - JASPControl::DropMode _dropMode = dropMode(); - if (indexes.length() == 0 || _dropMode == JASPControl::DropMode::DropNone) - return; - - beginResetModel(); - Terms terms = termsFromIndexes(indexes); - removeTerms(indexes); // Remove first before adding: we cannot add terms that already exist - for (int index : indexes) - { - if (index < dropItemIndex) - dropItemIndex--; - } - Terms removedTerms = addTerms(terms, dropItemIndex); - if (removedTerms.size() > 0) - { - addTerms(removedTerms); - } - - endResetModel(); -} - -Terms ListModelDraggable::addTerms(const Terms& terms, int dropItemIndex, const RowControlsValues&) -{ - if (terms.size() > 0) - { - beginResetModel(); - _addTerms(terms); - endResetModel(); - } - - return Terms(); -} - -Terms ListModelDraggable::canAddTerms(const Terms& terms) const -{ - Terms result; - for (const Term &term : terms) - { - if (isAllowed(term)) - result.add(term); - } - - return result; -} - -bool ListModelDraggable::isAllowed(const Term &term) const -{ - if (!listView()->allowAnalysisOwnComputedColumns()) - { - if (listView()->form()->isOwnComputedColumn(term.asString())) - return false; - } - - const QSet& variableTypesAllowed = listView()->variableTypesAllowed(); - - if (variableTypesAllowed.empty() || term.size() > 1) - return true; - - columnType variableType = (columnType)requestInfo(VariableInfo::VariableType, term.asQString()).toInt(); - - return variableTypesAllowed.contains(variableType); -} diff --git a/QMLComponents/models/listmodeldraggable.h b/QMLComponents/models/listmodeldraggable.h deleted file mode 100644 index d94853beb62..00000000000 --- a/QMLComponents/models/listmodeldraggable.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELDRAGGABLE_H -#define LISTMODELDRAGGABLE_H - -#include "listmodel.h" -#include "controls/jaspcontrol.h" - -class RowControls; - -class ListModelDraggable : public ListModel -{ - Q_OBJECT - -public: - ListModelDraggable(JASPListControl* listView); - ~ListModelDraggable(); - - bool copyTermsWhenDropped() const { return _copyTermsWhenDropped; } - JASPControl::DropMode dropMode() const { return _dropMode; } - - void setDropMode(JASPControl::DropMode dropMode) { _dropMode = dropMode; } - void setCopyTermsWhenDropped(bool copy) { _copyTermsWhenDropped = copy; } - - virtual Terms termsFromIndexes(const QList &indexes) const; - virtual Terms canAddTerms(const Terms& terms) const; - virtual Terms addTerms(const Terms& terms, int dropItemIndex = -1, const RowControlsValues& rowValues = RowControlsValues()); - virtual void removeTerms(const QList& indexes); - virtual void moveTerms(const QList& indexes, int dropItemIndex = -1); - -signals: - void destroyed(ListModelDraggable * me); - -protected: - bool _copyTermsWhenDropped; - JASPControl::DropMode _dropMode = JASPControl::DropMode::DropNone; - - bool isAllowed(const Term &term) const; -}; - -#endif // LISTMODELDRAGGABLE_H diff --git a/QMLComponents/models/listmodelfactorlevels.cpp b/QMLComponents/models/listmodelfactorlevels.cpp deleted file mode 100644 index 92470a62b4c..00000000000 --- a/QMLComponents/models/listmodelfactorlevels.cpp +++ /dev/null @@ -1,342 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelfactorlevels.h" -#include "qutils.h" -#include "log.h" -#include "controls/factorlevellistbase.h" - -using namespace std; - -ListModelFactorLevels::FactorLevelItem ListModelFactorLevels::FactorLevelItem::dummyFactor("", true, false); - -ListModelFactorLevels::ListModelFactorLevels(JASPListControl* listView) - : ListModel(listView) -{ - _factorLevelList = qobject_cast(listView); - _needsSource = false; - _itemType = "fixedFactors"; -} - -int ListModelFactorLevels::rowCount(const QModelIndex &) const -{ - return _items.length(); -} - -QVariant ListModelFactorLevels::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - - if (row < 0 || row >= _items.length()) - { - Log::log() << "Unknown row " << row << " in ListModelFactorLevels. Length is " << _items.length() << std::endl; - return QVariant(); - } - - const FactorLevelItem& item = _items.at(row); - - if (role == Qt::DisplayRole || role == ListModelFactorLevels::NameRole) - return item.value; - else if (role == ListModelFactorLevels::TypeRole) - return item.isLevel ? "level" : "factor"; - else if (role == ListModelFactorLevels::VirtualRole) - return item.isVirtual; - else if (role == ListModelFactorLevels::DeletableRole) - return _isDeletable(item); - - return ListModel::data(index, role); -} - -void ListModelFactorLevels::initFactors(const vector > > &factors) -{ - beginResetModel(); - - _items.clear(); - for (const pair > &factor : factors) - { - _items.append(FactorLevelItem(tq(factor.first), false, false)); - - int levelIndex = 1; - for (const string& level : factor.second) - { - _items.append(FactorLevelItem(tq(level), false, true)); - levelIndex++; - } - - // Append a virtual level - _items.append(FactorLevelItem(_factorLevelList->levelPlaceHolder(), true, true)); - } - - // Append a virtual factor - _items.append(FactorLevelItem(_factorLevelList->factorPlaceHolder(), true, false)); - - _setAllLevelsCombinations(); - - endResetModel(); - -} - -vector > > ListModelFactorLevels::getFactors() const -{ - vector > > result; - string currentFactorName; - vector currentLevels; - for (const FactorLevelItem& factor: _items) - { - if (!factor.isVirtual && !factor.isLevel) - { - currentFactorName = factor.value.toStdString(); - currentLevels.clear(); - } - else if (!factor.isVirtual && factor.isLevel) - { - currentLevels.push_back(factor.value.toStdString()); - } - else if (factor.isVirtual && factor.isLevel) - { - result.push_back(make_pair(currentFactorName, currentLevels)); - currentLevels.clear(); - } - } - - return result; -} - -const Terms &ListModelFactorLevels::getLevels() const -{ - return _allLevelsCombinations; -} - -void ListModelFactorLevels::_setAllLevelsCombinations() -{ - vector > allLevelsCombinations; - _setTerms(_getAllFactors()); // _terms get only the factors - - vector > allLevels; - vector currentLevels; - for (const FactorLevelItem& factor: _items) - { - if (factor.isLevel && !factor.isVirtual) - currentLevels.push_back(factor.value.toStdString()); - else if (!currentLevels.empty()) - { - allLevels.push_back(currentLevels); - currentLevels.clear(); - } - } - - for (const string& level : allLevels[0]) - { - vector levelVector {level}; - allLevelsCombinations.push_back(levelVector); - } - - for (uint i = 1; i < allLevels.size(); i++) - { - const vector& levels = allLevels[i]; - vector > previousLevelCombinations = allLevelsCombinations; // Copy it - allLevelsCombinations.clear(); - - for (uint j = 0; j < previousLevelCombinations.size(); j++) - { - for (uint k = 0; k < levels.size(); k++) - { - vector previousLevels = previousLevelCombinations[j]; - previousLevels.push_back(levels[k]); - allLevelsCombinations.push_back(previousLevels); - } - } - } - - _allLevelsCombinations.set(allLevelsCombinations, false); -} - -QStringList ListModelFactorLevels::_getAllFactors() const -{ - QStringList result; - - for (const FactorLevelItem& factor: _items) - { - if (!factor.isVirtual && !factor.isLevel) - result.push_back(factor.value); - } - - return result; -} - -void ListModelFactorLevels::itemChanged(int row, QVariant value) -{ - if (row < 0 || row >= _items.length()) return; - - FactorLevelItem& item = _items[row]; - QString val = value.toString(), - oldVal = item.value; - bool updateRow = true; - - if (val.isEmpty()) - // Try to remove the row. If it is not possible, refresh the row - updateRow = !_removeItem(row); - else - { - if (!item.isVirtual && item.value == val) return; - - // Check first that the value is unique - item.value = _giveUniqueValue(item, val); - - if (item.isVirtual) - { - // If the item was virtual, then it is not anymore - item.isVirtual = false; - - if (item.isLevel) - { - // It the changed item was a virtual level, add after this one a virtual level. - beginInsertRows(QModelIndex(), row+1, row+1); - _items.insert(row + 1, FactorLevelItem(_factorLevelList->levelPlaceHolder(), true, true)); - endInsertRows(); - } - else - { - // If the changed item was a virtual factor, add the minimm number of levels, add a virtual level, and add also a virtual factor. - beginInsertRows(QModelIndex(), _items.length(), _items.length() + _factorLevelList->minLevels() + 1); - - for (int i = 0; i < _factorLevelList->minLevels(); i++) - _items.push_back(FactorLevelItem(_factorLevelList->getLevelName(i + 1), false, true)); - - _items.push_back(FactorLevelItem(_factorLevelList->levelPlaceHolder(), true, true)); // Virtual level - _items.push_back(FactorLevelItem(_factorLevelList->factorPlaceHolder(), true, false)); // Virtual factor - - endInsertRows(); - } - } - else - emit namesChanged({ {oldVal, item.value} }); - - _setAllLevelsCombinations(); - } - - if (updateRow) - { - QModelIndex modelIndex = index(row, 0); - emit dataChanged(modelIndex, modelIndex); - } -} - -bool ListModelFactorLevels::_removeItem(int row) -{ - if (row < 0 || row >= _items.length()) return false; - - const FactorLevelItem& item = _items[row]; - if (!_isDeletable(item)) return false; - - int nbRowsToRemove = 1; - if (!item.isLevel) - { - // For a factor, remove the factor and all its levels - while (row + nbRowsToRemove < _items.length()) - { - if (_items.at(row + nbRowsToRemove).isLevel) nbRowsToRemove++; - else break; - } - } - - beginRemoveRows(QModelIndex(), row, row + nbRowsToRemove - 1); - for (int i = 0; i < nbRowsToRemove; i++) - _items.removeAt(row); - _setAllLevelsCombinations(); - endRemoveRows(); - - return true; -} - -void ListModelFactorLevels::itemRemoved(int row) -{ - _removeItem(row); -} - -QString ListModelFactorLevels::_giveUniqueValue(const FactorLevelItem &item, const QString value) const -{ - QString result = value; - QStringList otherValues; - - if (item.isLevel) - { - // Get all other levels that are in the same factor as item - const FactorLevelItem& factor = _getFactor(item); - int indexFactor = _items.indexOf(factor); - for (int index = indexFactor + 1; index < _items.length(); index++) - { - const FactorLevelItem& level = _items[index]; - if (!level.isLevel || level.isVirtual) break; - if (level != item) otherValues.push_back(level.value); - } - } - else - { - // Get all other factors - for (const FactorLevelItem& factor: _items) - { - if (!factor.isVirtual && !factor.isLevel && factor != item) - otherValues.push_back(factor.value); - } - - } - - // If the value is not unique, append '(1)' to it. But if ' (1)' exists also, append '(2)' instead. And so on... - int i = 1; - bool isUnique = false; - while (!isUnique) - { - isUnique = true; - for (const QString& anotherValue : otherValues) - if (result == anotherValue) isUnique = false; - if (!isUnique) result = value + tq(" (") + QString::number(i) + tq(")"); - i++; - } - return result; -} - -bool ListModelFactorLevels::_isDeletable(const ListModelFactorLevels::FactorLevelItem &item) const -{ - if (item.isVirtual) - return false; - else if (item.isLevel) - return (_items.indexOf(item) - _items.indexOf(_getFactor(item))) > _factorLevelList->minLevels(); - else - { - int count = 0; - for (const FactorLevelItem& _factor : _items) - { - if (!_factor.isLevel) count++; - if (_factor == item) break; - } - return count > _factorLevelList->minFactors(); - } -} - -ListModelFactorLevels::FactorLevelItem &ListModelFactorLevels::_getFactor(const FactorLevelItem &item) const -{ - FactorLevelItem& factor = FactorLevelItem::dummyFactor; - for (const FactorLevelItem& oneItem : _items) - { - if (!oneItem.isLevel) factor = oneItem; - if (oneItem == item) break; - } - - return factor; -} diff --git a/QMLComponents/models/listmodelfactorlevels.h b/QMLComponents/models/listmodelfactorlevels.h deleted file mode 100644 index 78568c4d8ec..00000000000 --- a/QMLComponents/models/listmodelfactorlevels.h +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELFACTORLEVELS_H -#define LISTMODELFACTORLEVELS_H - -#include "listmodel.h" - -class FactorLevelListBase; - -class ListModelFactorLevels : public ListModel -{ - Q_OBJECT -public: - - ListModelFactorLevels(JASPListControl* listView); - - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - void initFactors(const std::vector > > &factors); - std::vector > > getFactors() const; - const Terms& getLevels() const; - - -public slots: - void itemChanged(int row, QVariant value); - void itemRemoved(int row); - -protected: - FactorLevelListBase* _factorLevelList = nullptr; - - struct FactorLevelItem - { - QString value; - bool isVirtual; - bool isLevel; - - FactorLevelItem(const QString& _value, bool _isVirtual, bool _isLevel) : - value(_value), isVirtual(_isVirtual), isLevel(_isLevel) {} - - FactorLevelItem(const FactorLevelItem& item) : value(item.value), isVirtual(item.isVirtual), isLevel(item.isLevel) {} - - bool operator==(const FactorLevelItem& item) const - { - return item.isLevel == isLevel - && item.isVirtual == isVirtual - && item.value == value; - } - bool operator!=(const FactorLevelItem& item) const - { - return !(item == *this); - } - - static FactorLevelItem dummyFactor; - }; - - QList _items; - Terms _allLevelsCombinations; - - QStringList _getAllFactors() const; - QString _giveUniqueValue(const FactorLevelItem& item, const QString value) const; - bool _isDeletable(const FactorLevelItem& item) const; - FactorLevelItem& _getFactor(const FactorLevelItem& item) const; - void _setAllLevelsCombinations(); - bool _removeItem(int row); -}; - -#endif // LISTMODELFACTORLEVELS_H diff --git a/QMLComponents/models/listmodelfactorsform.cpp b/QMLComponents/models/listmodelfactorsform.cpp deleted file mode 100644 index 755417d946f..00000000000 --- a/QMLComponents/models/listmodelfactorsform.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelfactorsform.h" -#include "qutils.h" -#include "controls/variableslistbase.h" -#include "log.h" -#include "controls/jaspcontrol.h" -#include "analysisform.h" -#include "controls/factorsformbase.h" - -using namespace std; - -ListModelFactorsForm::ListModelFactorsForm(JASPListControl* listView) - : ListModel(listView) -{ - _factorsForm = qobject_cast(listView); - _needsSource = false; -} - -QHash ListModelFactorsForm::roleNames() const -{ - QHash roles; - roles[FactorNameRole] = "factorName"; - roles[FactorTitleRole] = "factorTitle"; - return roles; -} - -QVariant ListModelFactorsForm::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - - - if (row >= _factors.length()) - { - Log::log() << "Unknown row " << row << " in ListModelFactorsForm" << std::endl; - return QVariant(); - } - - Factor* factor = _factors[row]; - - if (role == Qt::DisplayRole || role == ListModelFactorsForm::FactorNameRole) return factor->name; - else if (role == ListModelFactorsForm::FactorTitleRole) return factor->title; - - return ListModel::data(index, role); -} - -void ListModelFactorsForm::initFactors(const FactorVec &factors) -{ - beginResetModel(); - - _factors.clear(); - ListModelAvailableInterface* availableModel = qobject_cast(_factorsForm->availableVariablesList()->model()); - if (availableModel) availableModel->clearAssignedModels(); - - Terms newTerms; - - int index = 0; - for (const auto &factorTuple : factors) - { - QString name = tq(get<0>(factorTuple)); - QString title = tq(get<1>(factorTuple)); - std::vector terms = get<2>(factorTuple); - Factor* factor = new Factor(name, title, terms); - _factors.push_back(factor); - newTerms.add(Terms(terms)); - index++; - } - - _setTerms(newTerms); - endResetModel(); -} - -int ListModelFactorsForm::countVariables() const -{ - int count = 0; - for (Factor* factor : _factors) - count += factor->listView ? factor->listView->count() : factor->initTerms.size(); - - return count; -} - - -Terms ListModelFactorsForm::filterTerms(const Terms& terms, const QStringList& filters) -{ - Terms result; - - if (filters.contains("title")) - for (Factor* factor : _factors) - result.add(factor->title); - else - result = terms; - - return ListModel::filterTerms(result, filters); -} - -ListModelFactorsForm::FactorVec ListModelFactorsForm::getFactors() -{ - ListModelFactorsForm::FactorVec result; - - for (Factor* factor : _factors) - { - JASPListControl* listView = factor->listView; - result.push_back(make_tuple(fq(factor->name), fq(factor->title), listView ? listView->model()->terms().asVector() : factor->initTerms)); - } - - return result; -} - -void ListModelFactorsForm::addFactor() -{ - beginInsertRows(QModelIndex(), _factors.size(), _factors.size()); - - QString index = QString::number(_factors.size() + 1); - QString name = tq("Factor") + index; - QString title = tq("Factor ") + index; - Factor* factor = new Factor(name, title); - _factors.push_back(factor); - - endInsertRows(); - -} - -void ListModelFactorsForm::removeFactor() -{ - if (_factors.size() > 1) - { - JASPListControl* listView = _factors[_factors.size() - 1]->listView; - - if (listView) - { - beginRemoveRows(QModelIndex(), _factors.size() - 1, _factors.size() - 1); - - const Terms& lastTerms = listView->model()->terms(); - _removeTerms(lastTerms); - _factors.removeLast(); - - endRemoveRows(); - } - else - Log::log() << "No list View found when removing factor" << std::endl; - - } -} - -void ListModelFactorsForm::titleChangedSlot(int row, QString title) -{ - if (row < 0 && row >= _factors.length()) - return; - - if (_factors[row]->title == title) - return; - - _factors[row]->title = title; - - emit dataChanged(index(row, 0), index(row,0)); -} - -void ListModelFactorsForm::resetModelTerms() -{ - Terms allTerms; - - for (Factor* factor : _factors) - { - JASPListControl* listView = factor->listView; - allTerms.add(listView ? listView->model()->terms() : Terms(factor->initTerms)); - } - - _setTerms(allTerms); - - emit dataChanged(index(0,0), index(_factors.length() - 1, 0)); -} - -void ListModelFactorsForm::factorAdded(int index, VariablesListBase* listView) -{ - if (index >= _factors.length()) - { - Log::log() << "Factor added with wrong index: " << index << ". Max index: " << _factors.length() << std::endl; - return; - } - - Factor* factor = _factors[index]; - factor->listView = listView; - Terms terms(factor->initTerms); - ListModelDraggable* model = listView->draggableModel(); - model->setCopyTermsWhenDropped(true); - model->initTerms(terms); -} diff --git a/QMLComponents/models/listmodelfactorsform.h b/QMLComponents/models/listmodelfactorsform.h deleted file mode 100644 index 1ca4f6c2015..00000000000 --- a/QMLComponents/models/listmodelfactorsform.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELFACTORSFORM_H -#define LISTMODELFACTORSFORM_H - -#include "listmodel.h" - -class JASPListControl; -class VariablesListBase; -class FactorsFormBase; - -class ListModelFactorsForm : public ListModel -{ - Q_OBJECT - Q_PROPERTY(int count READ count) - -public: - enum ListModelFactorsFormRoles { - FactorNameRole = Qt::UserRole + 1, - FactorTitleRole - }; - typedef std::vector > > FactorVec; - - ListModelFactorsForm(JASPListControl* listView); - - QHash roleNames() const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override { return count(); } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - Terms filterTerms(const Terms& terms, const QStringList& what) override; - void initFactors(const FactorVec &factors); - int count() const { return int(_factors.size()); } - int countVariables() const; - FactorVec getFactors(); - - void addFactor(); - void removeFactor(); - void factorAdded(int, VariablesListBase* listView); - -public slots: - void titleChangedSlot(int index, QString title); - void resetModelTerms(); - -signals: - void addListView(JASPListControl* listView); - -protected: - struct Factor - { - QString name; - QString title; - JASPListControl* listView; - std::vector initTerms; - Factor(const QString& _name, const QString& _title, std::vector _initTerms = std::vector()) : - name(_name), title(_title), listView(nullptr), initTerms(_initTerms) {} - }; - - QVector _factors; - FactorsFormBase* _factorsForm = nullptr; - -}; - -#endif // LISTMODELFACTORSFORM_H diff --git a/QMLComponents/models/listmodelfiltereddataentry.cpp b/QMLComponents/models/listmodelfiltereddataentry.cpp deleted file mode 100644 index 2860b96680c..00000000000 --- a/QMLComponents/models/listmodelfiltereddataentry.cpp +++ /dev/null @@ -1,392 +0,0 @@ -#include "listmodelfiltereddataentry.h" -#include "analysisform.h" -#include "controls/tableviewbase.h" -#include "qutils.h" -#include "log.h" -#include "controls/jaspcontrol.h" - -ListModelFilteredDataEntry::ListModelFilteredDataEntry(TableViewBase * parent) - : ListModelTableViewBase(parent) -{ - _keepRowsOnReset = false; - setAcceptedRowsTrue(); - - connect(this, &ListModelFilteredDataEntry::filterChanged, this, &ListModelFilteredDataEntry::runFilter ); - connect(_tableView, SIGNAL(filterSignal(QString)), this, SLOT(setFilter(QString)) ); - connect(_tableView, SIGNAL(colNameSignal(QString)), this, SLOT(setColName(QString)) ); - connect(_tableView, SIGNAL(extraColSignal(QString)), this, SLOT(setExtraCol(QString)) ); - -} - -void ListModelFilteredDataEntry::dataSetChangedHandler() -{ - setAcceptedRowsTrue(); - runFilter(_tableTerms.filter); -} - -void ListModelFilteredDataEntry::setFilter(QString filter) -{ - if (_tableTerms.filter == filter) - return; - - _tableTerms.filter = filter; - emit filterChanged(_tableTerms.filter); -} - -void ListModelFilteredDataEntry::runFilter(QString filter) -{ - //std::cout << "ListModelFilteredDataEntry::runFilter(" << filter.toStdString() << ")" << std::endl; - - if (getDataSetRowCount() > 0) - runRScript( "filterResult <- {" + filter + "};" "\n" - "if(!is.logical(filterResult)) filterResult <- rep(TRUE, rowcount);" "\n" - "return(paste0(sep=' ', collapse='', as.character(filterResult)));" "\n" - ); -} - -size_t ListModelFilteredDataEntry::getDataSetRowCount() const -{ - return requestInfo(VariableInfo::DataSetRowCount).toUInt(); -} - -void ListModelFilteredDataEntry::rScriptDoneHandler(const QString & result) -{ - Log::log() << "ListModelFilteredDataEntry::rScriptDoneHandler: " << result << std::endl; - - QStringList values = result.split(' '); - - size_t dataSetRows = getDataSetRowCount(); - - auto newRows = std::vector(dataSetRows, true); - - if (dataSetRows == 0) - return; - - size_t i = 0; - for (const QString & value : values) - if (value == "TRUE" || value == "FALSE") - { - if(i < dataSetRows) - newRows[i] = value == "TRUE"; - i++; - } - - - setAcceptedRows(i == dataSetRows ? newRows : std::vector(dataSetRows, true)); -} - -void ListModelFilteredDataEntry::setAcceptedRows(std::vector newRows) -{ - //std::cout << "setAcceptedRows(# newRows == " << newRows.size() << ")" << std::endl; - bool changed = newRows.size() != _acceptedRows.size(); - - if (changed) - _acceptedRows = newRows; - else - for (size_t i=0; i<_acceptedRows.size(); i++) - if (_acceptedRows[i] != newRows[i]) - { - _acceptedRows[i] = newRows[i]; - changed = true; - } - - if (changed) - { - emit acceptedRowsChanged(); - fillTable(); - } -} - -void ListModelFilteredDataEntry::itemChanged(int column, int row, QVariant value, QString) -{ - if (column != _editableColumn) - return; - - //std::cout << "ListModelFilteredDataEntry::itemChanged(" << column << ", " << row << ", " << value << ")" << std::endl; - - //If changing this function also take a look at it's counterpart in ListModelTableViewBase - if (column > -1 && column < columnCount() && row > -1 && row < _tableTerms.rowNames.length()) - { - if (_tableTerms.values[0][row] != value) - { - bool gotLarger = _tableTerms.values[0][row].toString().size() != value.toString().size(); - _tableTerms.values[0][row] = value.toDouble(); - _enteredValues[_filteredRowToData[size_t(row)]] = value.toDouble(); - - emit dataChanged(index(row, column), index(row, column), { Qt::DisplayRole }); - - if (gotLarger) - emit headerDataChanged(Qt::Orientation::Horizontal, column, column); - - - } - } -} - -Qt::ItemFlags ListModelFilteredDataEntry::flags(const QModelIndex & index) const -{ - - return Qt::ItemIsEnabled | (index.column() == _editableColumn ? (Qt::ItemIsSelectable | Qt::ItemIsEditable) : Qt::NoItemFlags ); -} - - -void ListModelFilteredDataEntry::sourceTermsReset() -{ - //std::cout << "ListModelFilteredDataEntry::sourceTermsChanged(Terms *, Terms *)" << std::endl; - - Terms sourceTerms = getSourceTerms(); - QString colName = (_editableColumn >= 0 && _editableColumn < _tableTerms.colNames.size()) ? _tableTerms.colNames[_editableColumn] : ""; - _dataColumns = sourceTerms.asQList(); - _tableTerms.colNames = _dataColumns; - - if (_tableTerms.extraCol != "" && !_tableTerms.colNames.contains(_tableTerms.extraCol)) - _tableTerms.colNames.push_back(_tableTerms.extraCol); - - if (!colName.isEmpty()) - { - _editableColumn = _tableTerms.colNames.size(); - if (!_tableTerms.colNames.contains(colName)) - _tableTerms.colNames.push_back(colName); - } - else - _editableColumn = -1; - - fillTable(); -} - -void ListModelFilteredDataEntry::initialValuesChanged() -{ - _initialValues.clear(); - if (_tableView->initialValuesControl()) - { - const Terms& terms = _tableView->initialValuesControl()->model()->terms(); - if (terms.size() > 0) - { - QList values = requestInfo(VariableInfo::DoubleValues, terms[0].asQString()).toList(); - for (const QVariant& value : values) - _initialValues.push_back(value.toDouble()); - } - } - fillTable(); -} - -void ListModelFilteredDataEntry::initTableTerms(const TableTerms& terms) -{ - //std::cout << "ListModelFilteredDataEntry::initValues(OptionsTable * bindHere)" << std::endl; - - if (terms.values.size() > 1) - Log::log() << "Too many values in ListModelFilteredDataEntry" << std::endl; - - if (terms.values.size() == 0) - { - fillTable(); - return; - } - - _tableTerms = terms; - setFilter(_tableTerms.filter); - setColName(_tableTerms.colName); - setExtraCol(_tableTerms.extraCol); - - _acceptedRows = std::vector(getDataSetRowCount(), false); - - _enteredValues.clear(); - - _dataColumns = _tableTerms.colNames; - - if (_tableTerms.extraCol != "" && !_tableTerms.colNames.contains(_tableTerms.extraCol)) - _tableTerms.colNames.push_back(_tableTerms.extraCol); - - _editableColumn = _tableTerms.colName.isEmpty() ? -1 : _tableTerms.colNames.size(); - - if (!_tableTerms.colName.isEmpty() && !_tableTerms.colNames.contains(_tableTerms.colName)) - _tableTerms.colNames.push_back(_tableTerms.colName); - - int valIndex = 0; - for (int rowIndex : _tableTerms.rowIndices) - { - size_t row = static_cast(rowIndex) - 1; - if (valIndex < _tableTerms.values[0].size()) - _enteredValues[row] = _tableTerms.values[0][valIndex].toDouble(); - else - _tableTerms.values[0].push_back(_tableView->defaultValue()); - _acceptedRows[row] = true; - valIndex++; - } - - fillTable(); -} - -void ListModelFilteredDataEntry::fillTable() -{ - beginResetModel(); - - _filteredRowToData.clear(); - _tableTerms.rowNames.clear(); - _tableTerms.values.clear(); - - size_t dataRows = getDataSetRowCount(); - - if (_acceptedRows.size() != dataRows) - _acceptedRows = std::vector(dataRows, true); - - - _tableTerms.values.push_back({}); - - for (size_t row=0; rowdefaultValue(); - if (_enteredValues.count(row) > 0) val = _enteredValues[row]; - else if (_initialValues.size() > row) val = _initialValues[row]; - - _tableTerms.values[0].push_back(val); - _tableTerms.rowNames.push_back(tq(std::to_string(row + 1))); - - } - - _editableColumn = _tableTerms.colName.isEmpty() ? -1 : (columnCount() - 1); - endResetModel(); - - emit columnCountChanged(); - emit rowCountChanged(); -} - -QVariant ListModelFilteredDataEntry::data(const QModelIndex &index, int role) const -{ - int column = index.column(), - row = index.row(); - - if(row < 0 || row > _tableTerms.rowNames.size()) - return QVariant(); - - if (role != Qt::DisplayRole) - return ListModelTableViewBase::data(index, role); - - if(column == _editableColumn) - return QVariant(_tableTerms.values[0][row]); - - if(getDataSetRowCount() == 0 || column > _tableTerms.colNames.size() || column < 0) - return QVariant(); - - std::string colName = _tableTerms.colNames[column].toStdString(); - size_t rowData = _filteredRowToData[static_cast(row)]; - return requestInfo(VariableInfo::DataSetValue, tq(colName), rowData); -} - - -int ListModelFilteredDataEntry::getMaximumColumnWidthInCharacters(size_t column) const -{ - int colIndex = int(column); - - if (colIndex == _editableColumn) - return ListModelTableViewBase::getMaximumColumnWidthInCharacters(0); - - - - if (colIndex < _tableTerms.colNames.size() && colIndex >= 0) - { - QString colName = _tableTerms.colNames[colIndex]; - return requestInfo(VariableInfo::MaxWidth, colName).toInt(); - } - - - return 6; -} - -void ListModelFilteredDataEntry::setColName(QString colName) -{ - if (_tableTerms.colName == colName) - return; - - if (_tableTerms.colName.isEmpty()) - { - if (!_tableTerms.colNames.contains(colName)) - _tableTerms.colNames.push_back(colName); - _editableColumn = _tableTerms.colNames.size() - 1; - } - else if (colName.isEmpty()) - { - if (_tableTerms.colNames.size() > 0) _tableTerms.colNames.pop_back(); - _editableColumn = -1; - } - else if (_tableTerms.colNames.size() > _editableColumn) - { - if (_editableColumn >= 0) - _tableTerms.colNames[_editableColumn] = colName; - else - Log::log() << "Warning: editableColumn is negative!" << std::endl; - } - - _tableTerms.colName = colName; - emit colNameChanged(_tableTerms.colName); - refresh(); - - if (_editableColumn >= 0) - emit headerDataChanged(Qt::Horizontal, _editableColumn, _editableColumn); - -} - -void ListModelFilteredDataEntry::setExtraCol(QString extraCol) -{ - if (_tableTerms.extraCol == extraCol) - return; - - //std::cout << "ListModelFilteredDataEntry::setExtraCol("<< extraCol.toStdString() <<")" << std::endl; - - QString oldExtraCol = _tableTerms.extraCol; - - _tableTerms.extraCol = extraCol; - - - beginResetModel(); - if (extraCol == "" && _tableTerms.colNames.size() > _editableColumn && _editableColumn > 0 && _tableTerms.colNames[_editableColumn - 1] == oldExtraCol) - { - //std::cout << "Leegmaken!" << std::endl; - - _tableTerms.colNames.erase(_tableTerms.colNames.begin() + _editableColumn - 1); - _editableColumn--; - - //emit headerDataChanged(Qt::Horizontal, _editableColumn, _colNames.size() + 1); - //emit dataChanged(index(0, _editableColumn), index(static_cast(getDataSetRowCount()), _colNames.size() + 1)); - - } - else if (oldExtraCol == "" && _tableTerms.colNames.size() > 0) - { - //std::cout << "Volmaken!" << std::endl; - - if (_editableColumn >= 0 && !_tableTerms.colName.isEmpty()) - { - _tableTerms.colNames[_editableColumn] = extraCol; - _editableColumn++; - _tableTerms.colNames.push_back(_tableTerms.colName); - } - else if (!_tableTerms.colNames.contains(extraCol)) - _tableTerms.colNames.push_back(extraCol); - - - //emit headerDataChanged(Qt::Horizontal, _editableColumn - 1, _colNames.size()); - //emit dataChanged(index(0, _editableColumn - 1), index(static_cast(getDataSetRowCount()), _colNames.size())); - - } - else if (oldExtraCol != "" && extraCol != "" && _tableTerms.colNames.size() > 0) - { - _tableTerms.colNames[_tableTerms.colNames.size() - 1] = extraCol; - //emit headerDataChanged(Qt::Horizontal, _editableColumn - 1, _editableColumn - 1); - //emit dataChanged(index(0, _editableColumn - 1), index(static_cast(getDataSetRowCount()), _editableColumn - 1)); - } - - endResetModel(); - - emit columnCountChanged(); - emit extraColChanged(_tableTerms.extraCol); -} - -void ListModelFilteredDataEntry::refreshModel() -{ - ListModel::refresh(); - - runFilter(_tableTerms.filter); -} diff --git a/QMLComponents/models/listmodelfiltereddataentry.h b/QMLComponents/models/listmodelfiltereddataentry.h deleted file mode 100644 index af4821679da..00000000000 --- a/QMLComponents/models/listmodelfiltereddataentry.h +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - - -#ifndef LISTMODELFILTEREDDATAENTRY_H -#define LISTMODELFILTEREDDATAENTRY_H - -#include "listmodeltableviewbase.h" - -class ListModelFilteredDataEntry : public ListModelTableViewBase -{ - Q_OBJECT - Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged ) - Q_PROPERTY(QString colName READ colName WRITE setColName NOTIFY colNameChanged ) - Q_PROPERTY(QString extraCol READ extraCol WRITE setExtraCol NOTIFY extraColChanged ) - -public: - explicit ListModelFilteredDataEntry(TableViewBase * parent); - - QVariant data( const QModelIndex &index, int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags( const QModelIndex &index) const override; - void rScriptDoneHandler(const QString & result) override; - const QString& filter() const { return _tableTerms.filter; } - const QString& colName() const { return _tableTerms.colName; } - const QString extraCol() const { return _tableTerms.extraCol; } - const std::vector& filteredRowToData() const { return _filteredRowToData; } - const QStringList& dataColumns() const { return _dataColumns; } - void initTableTerms(const TableTerms& terms) override; - int getMaximumColumnWidthInCharacters(size_t columnIndex) const override; - bool isEditable(const QModelIndex& index) const override { return index.column() >= columnCount(); } - void itemChanged(int column, int row, QVariant value, QString type) override; - - void refreshModel() override; - - bool areColumnNamesVariables() const override { return true; } - -public slots: - void sourceTermsReset() override; - void initialValuesChanged() override; - void setFilter(QString filter); - void setColName(QString colName); - void setExtraCol(QString extraCol); - -signals: - void filterChanged(QString filter); - void acceptedRowsChanged(); - void colNameChanged(QString colName); - void extraColChanged(QString extraCol); - -private slots: - void dataSetChangedHandler(); - void runFilter(QString filter); - -private: - void setAcceptedRows(std::vector newRows); - void setAcceptedRowsTrue() { setAcceptedRows(std::vector(getDataSetRowCount(), true)); } - size_t getDataSetRowCount() const; - void fillTable(); - - std::vector _acceptedRows; - std::vector _filteredRowToData; - std::map _enteredValues; - std::vector _initialValues; - int _editableColumn = 0; - QStringList _dataColumns, - _extraColsStr; -}; - -#endif // LISTMODELFILTEREDDATAENTRY_H diff --git a/QMLComponents/models/listmodelgridinput.cpp b/QMLComponents/models/listmodelgridinput.cpp deleted file mode 100644 index 8e486d4a360..00000000000 --- a/QMLComponents/models/listmodelgridinput.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelgridinput.h" -#include "controls/tableviewbase.h" - -ListModelGridInput::ListModelGridInput(TableViewBase *parent) : ListModelTableViewBase(parent) -{ - -} - -void ListModelGridInput::setup() -{ - ListModelTableViewBase::setup(); - _readSource(); -} - -void ListModelGridInput::initTableTerms(const ListModelTableViewBase::TableTerms &terms) -{ - _rowCount = 0; - for (const auto & column : terms.values) - if (column.length() > _rowCount) _rowCount = column.length(); - - ListModelTableViewBase::initTableTerms(terms); -} - -void ListModelGridInput::sourceTermsReset() -{ - _readSource(); -} - -void ListModelGridInput::_readSource() -{ - Terms terms = getSourceTerms(); - int nbColumns = _tableView->minColumn(), - nbRows = _tableView->minRow(); - - for (const Term& term : terms) - { - const QStringList& row = term.components(); - if (row.length() > nbColumns) nbColumns = row.length(); - } - if (int(terms.size()) > nbRows) nbRows = int(terms.size()); - if (_tableView->maxRow() >= 0 && nbRows > _tableView->maxRow()) nbRows = _tableView->maxRow(); - if (_tableView->maxColumn() >= 0 && nbColumns > _tableView->maxColumn()) nbColumns = _tableView->maxColumn(); - - if (nbRows == _rowCount && nbColumns == _tableTerms.colNames.length()) - { - // Apparently only some valuee has been changed. Just emit a dataChanged in this case - for (int colNb = 0; colNb < nbColumns; colNb++) - { - QVector column; - for (int rowNb = 0; rowNb < nbRows; rowNb++) - { - const Term& term = int(terms.size()) > rowNb ? terms.at(size_t(rowNb)) : Term(QStringList()); - const QStringList& rowValues = term.components(); - QVariant value = rowValues.length() > colNb ? rowValues.at(colNb) : _tableView->defaultValue(); - if (value != _tableTerms.values[colNb][rowNb]) - { - _tableTerms.values[colNb][rowNb] = value; - QModelIndex ind = index(rowNb, colNb); - emit dataChanged(ind, ind, {Qt::DisplayRole}); - } - } - } - } - else - { - beginResetModel(); - - _tableTerms.clear(); - - for (int colNb = 0; colNb < nbColumns; colNb++) - { - QVector column; - for (size_t rowNb = 0; rowNb < size_t(nbRows); rowNb++) - { - const Term& term = terms.size() > rowNb ? terms.at(rowNb) : Term(QStringList()); - const QStringList& rowValues = term.components(); - column.append(rowValues.length() > colNb ? rowValues.at(colNb) : _tableView->defaultValue()); - } - _tableTerms.values.append(column); - _tableTerms.colNames.append(QString::number(colNb)); - } - - for (int i = 0; i < _rowCount; i++) - _tableTerms.rowNames.append(_tableView->rowNames().count() > i ? _tableView->rowNames()[i] : QString::number(i)); - _rowCount = nbRows; - - endResetModel(); - } -} diff --git a/QMLComponents/models/listmodelgridinput.h b/QMLComponents/models/listmodelgridinput.h deleted file mode 100644 index 050475d6c4d..00000000000 --- a/QMLComponents/models/listmodelgridinput.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELGRIDINPUT_H -#define LISTMODELGRIDINPUT_H - -#include "listmodeltableviewbase.h" - -class ListModelGridInput : public ListModelTableViewBase -{ - Q_OBJECT - -public: - explicit ListModelGridInput(TableViewBase * parent); - - int rowCount( const QModelIndex & = QModelIndex()) const override { return _rowCount; } - int columnCount(const QModelIndex & = QModelIndex()) const override { return _tableTerms.values.length(); } - - void setup() override; - void initTableTerms(const TableTerms& terms) override; - - void sourceTermsReset() override; - -private: - void _readSource(); - - int _rowCount = 0; - -}; - -#endif // LISTMODELGRIDINPUT_H diff --git a/QMLComponents/models/listmodelinputvalue.cpp b/QMLComponents/models/listmodelinputvalue.cpp deleted file mode 100644 index 992384088ed..00000000000 --- a/QMLComponents/models/listmodelinputvalue.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelinputvalue.h" -#include "qutils.h" -#include "log.h" - -ListModelInputValue::ListModelInputValue(JASPListControl* listView, int minRows) - : ListModel(listView), _minRows(minRows) -{ - _needsSource = false; -} - - -int ListModelInputValue::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return ListModel::rowCount() + (_addVirtual ? 1 : 0); -} - -QVariant ListModelInputValue::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - size_t rowU = size_t(row); - - if (row >= rowCount()) - { - Log::log() << "Unknown row " << row << " in ListModelFactors. Length is " << rowCount() << std::endl; - return QVariant(); - } - - QString value; - if (role == Qt::DisplayRole || role == ListModelInputValue::NameRole) - { - QString value; - if (rowU < terms().size()) - value = terms().at(rowU).asQString(); - else if (_addVirtual) - value = _placeholder; - return value; - } - else if (role == ListModelInputValue::TypeRole) - { - bool isVirtual = (_addVirtual && rowU == terms().size()); - QStringList listValues; - if (isVirtual) - listValues.push_back(tq("virtual")); - - if (row >= _minRows && !isVirtual) - listValues.push_back(tq("deletable")); - value = listValues.join(','); - return value; - } - else - return ListModel::data(index, role); -} - - -QString ListModelInputValue::_changeLastNumber(const QString &val) -{ - QString result = val; - int index = val.length() - 1; - for (; index >= 0 ; index--) - { - if (!val.at(index).isDigit()) - break; - } - index++; - - int num = -1; - if (index >= 0 && index < val.length()) - { - bool ok = false; - num = val.right(val.length() - index).toInt(&ok); - if (!ok) - num = -1; - } - - if (num >= 0) - return result.left(index).append(QString::number(num + 1)); - else - return result.append(QString::number(1)); -} - -QString ListModelInputValue::_makeUnique(const QString &val, int row) -{ - QString result = val; - QList values = terms().asQList(); - bool isUnique = true; - do - { - int i = 0; - isUnique = true; - for (const QString& value : values) - { - if (i != row) - { - if (value == result) - { - isUnique = false; - result = _changeLastNumber(result); - } - } - i++; - } - } while (!isUnique); - - return result; -} - - -void ListModelInputValue::itemChanged(int row, QVariant value) -{ - if (row < 0) - return; - if (row >= rowCount()) - { - Log::log() << "Index " << row << " in ListModelFactors is greater than the maximum " << rowCount() << std::endl; - return; - } - - QString val = value.toString(); - size_t rowU = size_t(row); - - bool isVirtual = (_addVirtual && rowU == terms().size()); - if (isVirtual) - { - if (val.isEmpty()) - return; - beginResetModel(); - _addTerm(_makeUnique(val)); - endResetModel(); - } - else - { - if (val.isEmpty() && row < _minRows) - val = "1"; - - if (val.isEmpty()) - { - beginRemoveRows(QModelIndex(), row, row); - _removeTerm(row); - endRemoveRows(); - } - else - { - beginResetModel(); - val = _makeUnique(val, row); - QList values = terms().asQList(); - values[row] = val; - _setTerms(values); - endResetModel(); - } - } - -} - -void ListModelInputValue::itemRemoved(int row) -{ - beginRemoveRows(QModelIndex(), row, row); - _removeTerm(row); - endRemoveRows(); -} diff --git a/QMLComponents/models/listmodelinputvalue.h b/QMLComponents/models/listmodelinputvalue.h deleted file mode 100644 index 29cf44f77ec..00000000000 --- a/QMLComponents/models/listmodelinputvalue.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELINPUTVALUE_H -#define LISTMODELINPUTVALUE_H - -#include "listmodel.h" - -class ListModelInputValue : public ListModel -{ - Q_OBJECT -public: - - ListModelInputValue(JASPListControl* listView, int minRows = 0); - - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - void setAddVirtual(bool addVirtual, QString placeholder = "") { _addVirtual = addVirtual; _placeholder = placeholder; } - -public slots: - void itemChanged(int row, QVariant value); - void itemRemoved(int row); - -protected: - QString _makeUnique(const QString& val, int row = -1); - QString _changeLastNumber(const QString& val); - - bool _addVirtual = true; - int _minRows = 0; - QString _placeholder = tr("New Value"); - -}; - -#endif // LISTMODELINPUTVALUE_H diff --git a/QMLComponents/models/listmodelinteractionassigned.cpp b/QMLComponents/models/listmodelinteractionassigned.cpp deleted file mode 100644 index 4aa0fc5baae..00000000000 --- a/QMLComponents/models/listmodelinteractionassigned.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelinteractionassigned.h" -#include "qutils.h" -#include "listmodeltermsavailable.h" -#include "listmodeltermsassigned.h" -#include "controls/jasplistcontrol.h" - -using namespace std; - -ListModelInteractionAssigned::ListModelInteractionAssigned(JASPListControl* listView, bool mustContainLowerTerms, bool addInteractionsByDefault) - : ListModelAssignedInterface(listView), InteractionModel () -{ - _copyTermsWhenDropped = true; - _mustContainLowerTerms = mustContainLowerTerms; - _addInteractionsByDefault = addInteractionsByDefault; -} - -void ListModelInteractionAssigned::initTerms(const Terms &terms, const RowControlsValues& allValuesMap, bool reInit) -{ - // Initialization of the terms can be a re-initialization: in this case the interaction terms can be lost - // So the interaction terms must be kept, and if their components are in the new terms, then add this interaction. - Terms newTerms = terms; - - if (reInit) - { - Terms oldInteractions = interactionTerms(); - for (const Term& oldInteraction : oldInteractions) - { - if (oldInteraction.size() > 1) - { - bool add = true; - for (const QString& comp : oldInteraction.components()) - { - if (!terms.contains(Term(comp))) - add = false; - } - if (add) - newTerms.add(oldInteraction); - } - } - } - clearInteractions(); - _addTerms(newTerms, false); - ListModelAssignedInterface::initTerms(interactionTerms(), allValuesMap, reInit); -} - -Terms ListModelInteractionAssigned::filterTerms(const Terms& terms, const QStringList& filters) -{ - Terms result; - if (filters.contains("noInteraction")) - { - result.add(_fixedFactors); - result.add(_randomFactors); - result.add(_covariates); - } - else - result = terms; - - return ListModelAssignedInterface::filterTerms(result, filters); -} - -void ListModelInteractionAssigned::removeTerms(const QList &indices) -{ - Terms toRemove; - - for (int i : indices) - { - int index = i; - if (index < rowCount()) - toRemove.add(terms().at(size_t(index))); - } - - removeInteractionTerms(toRemove); - - setTerms(); -} - -Terms ListModelInteractionAssigned::termsFromIndexes(const QList &indexes) const -{ - Terms result; - for (int i : indexes) - { - int index = i; - if (index < rowCount()) - result.add(terms().at(size_t(index))); - } - - return result; -} - -void ListModelInteractionAssigned::_addTerms(const Terms& terms, bool combineWithExistingTerms) -{ - Terms fixedFactors; - Terms randomFactors; - Terms covariates; - Terms others; - for (const Term& term : terms) - { - QString itemType = getItemType(term); - if (itemType == "fixedFactors") - { - if (!_fixedFactors.contains(term)) - fixedFactors.add(term); - } - else if (itemType == "randomFactors") - { - if (!_randomFactors.contains(term)) - randomFactors.add(term); - } - else if (itemType == "covariates") - { - if (!_covariates.contains(term)) - covariates.add(term); - } - else - { - if (!_interactionTerms.contains(term)) - others.add(term); - } - } - - if (fixedFactors.size() > 0) - addFixedFactors(fixedFactors, combineWithExistingTerms); - - if (randomFactors.size() > 0) - addRandomFactors(randomFactors); - - if (covariates.size() > 0) - addCovariates(covariates); - - if (others.size() > 0) - addInteractionTerms(others); - -} - -void ListModelInteractionAssigned::availableTermsResetHandler(Terms termsAdded, Terms termsRemoved) -{ - if (termsAdded.size() > 0 && listView()->addAvailableVariablesToAssigned()) - { - _addTerms(termsAdded, _addInteractionsByDefault); - setTerms(); - } - - if (termsRemoved.size() > 0) - { - removeInteractionTerms(termsRemoved); - setTerms(); - } -} - -QString ListModelInteractionAssigned::getItemType(const Term &term) const -{ - QString type; - ListModelTermsAvailable* _source = dynamic_cast(availableModel()); - if (_source) - { - ListModel* model = _source->getSourceModelOfTerm(term); - if (model) - { - type = model->getItemType(term); - if (type.isEmpty() || type == "variables") - type = model->name(); - } - } - - return type; -} - -Terms ListModelInteractionAssigned::canAddTerms(const Terms& terms) const -{ - Q_UNUSED(terms); - - return terms; -} - - -Terms ListModelInteractionAssigned::addTerms(const Terms& terms, int , const RowControlsValues&) -{ - if (terms.size() == 0) - return Terms(); - - Terms dropped; - dropped.setSortParent(availableModel()->allTerms()); - dropped.set(terms); - - Terms newTerms = dropped.combineTerms(JASPControl::CombinationType::CombinationCross); - - _addTerms(newTerms, false); - setTerms(); - - return Terms(); -} - -void ListModelInteractionAssigned::moveTerms(const QList &indexes, int dropItemIndex) -{ - JASPControl::DropMode _dropMode = dropMode(); - if (indexes.length() == 0 || _dropMode == JASPControl::DropMode::DropNone) - return; - - beginResetModel(); - Terms termsToMove = termsFromIndexes(indexes); - if (dropItemIndex == -1) - dropItemIndex = int(terms().size()); - for (int index : indexes) - { - if (index < dropItemIndex) - dropItemIndex--; - } - - Terms newTerms = _interactionTerms; - newTerms.remove(termsToMove); - newTerms.insert(dropItemIndex, termsToMove); - _interactionTerms = newTerms; - _setTerms(newTerms); - - endResetModel(); -} - -void ListModelInteractionAssigned::setTerms() -{ - beginResetModel(); - - _setTerms(interactionTerms()); - - endResetModel(); -} - -void ListModelInteractionAssigned::sourceNamesChanged(QMap map) -{ - // In an interaction model, if a name is changed, maybe a part of the interaction term has to be changed. - QSet allChangedTermsIndex; - Terms oldInteractionTerms = interactionTerms(); - QMapIterator it(map); - - while (it.hasNext()) - { - it.next(); - const QString& oldName = it.key(), newName = it.value(); - - // changeComponentName changes all interaction terms that have at least one of its components that much be changed. - QSet indexes = changeComponentName(oldName.toStdString(), newName.toStdString()); - allChangedTermsIndex += indexes; - } - - // If this model is a source of another model, the namesChanged signal must be also emitted, but with all interaction terms that have been changed. - QMap allTermsChangedMap; - const Terms& newInteractionTerms = interactionTerms(); - for (int index : allChangedTermsIndex) - allTermsChangedMap[oldInteractionTerms.at(size_t(index)).asQString()] = newInteractionTerms.at(size_t(index)).asQString(); - - if (allTermsChangedMap.size() > 0) - emit namesChanged(allTermsChangedMap); - - // setTerms will re-initialize the terms of this model, and will also provoke the re-initialization of the models that depend on this model. - // So setTerms must be called after the namesChanged is emitted, so that the other models which depend on this model can change first the names of their terms. - setTerms(); -} diff --git a/QMLComponents/models/listmodelinteractionassigned.h b/QMLComponents/models/listmodelinteractionassigned.h deleted file mode 100644 index a1f101db9cf..00000000000 --- a/QMLComponents/models/listmodelinteractionassigned.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELINTERACTIONASSIGNED_H -#define LISTMODELINTERACTIONASSIGNED_H - -#include "listmodelassignedinterface.h" -#include "listmodelavailableinterface.h" -#include "interactionmodel.h" - -class ListModelInteractionAssigned : public ListModelAssignedInterface, public InteractionModel -{ - Q_OBJECT - -public: - ListModelInteractionAssigned(JASPListControl* listView, bool mustContainLowerTerms, bool addInteractionsByDefault); - - void initTerms(const Terms &terms, const RowControlsValues& = RowControlsValues(), bool reInit = false) override; - Terms termsFromIndexes(const QList &indexes) const override; - Terms canAddTerms(const Terms& terms) const override; - Terms addTerms(const Terms& terms, int dropItemIndex = -1, const RowControlsValues& rowValues = RowControlsValues()) override; - void moveTerms(const QList& indexes, int dropItemIndex = -1) override; - void removeTerms(const QList &indices) override; - QString getItemType(const Term &term) const override; - Terms filterTerms(const Terms& terms, const QStringList& filters) override; - -public slots: - void availableTermsResetHandler(Terms termsToAdd, Terms termsToRemove) override; - void sourceNamesChanged(QMap map) override; - -protected: - void _addTerms(const Terms& terms, bool combineWithExistingTerms); - - void setTerms(); - - bool _addInteractionsByDefault; -}; - - -#endif // LISTMODELINTERACTIONASSIGNED_H diff --git a/QMLComponents/models/listmodelinteractionavailable.cpp b/QMLComponents/models/listmodelinteractionavailable.cpp deleted file mode 100644 index df9af2759f1..00000000000 --- a/QMLComponents/models/listmodelinteractionavailable.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelinteractionavailable.h" -#include "listmodeltermsassigned.h" -#include "analysisform.h" -#include "controls/jasplistcontrol.h" -#include "controls/sourceitem.h" - -ListModelInteractionAvailable::ListModelInteractionAvailable(JASPListControl* listView) - : ListModelAvailableInterface(listView), InteractionModel () -{ -} - -void ListModelInteractionAvailable::resetTermsFromSources(bool updateAssigned) -{ - beginResetModel(); - Terms termsAvailable; - clearInteractions(); - Terms fixedFactors; - Terms randomFactors; - Terms covariates; - - listView()->applyToAllSources([&](SourceItem *sourceItem, const Terms& terms) - { - ListModel* sourceModel = sourceItem->sourceListModel(); - for (const Term& term : terms) - { - QString itemType = sourceModel ? sourceModel->getItemType(term) : ""; - if (itemType.isEmpty() || itemType == "variables") - itemType = sourceModel->name(); - - if (itemType == "fixedFactors") - fixedFactors.add(term); - else if (itemType == "randomFactors") - randomFactors.add(term); - else if (itemType == "covariates") - covariates.add(term); - } - }); - - if (fixedFactors.size() > 0) - addFixedFactors(fixedFactors); - - if (randomFactors.size() > 0) - addRandomFactors(randomFactors); - - if (covariates.size() > 0) - addCovariates(covariates); - - const Terms& interactions = interactionTerms(); - Terms removedTerms, addedTerms; - - for (const Term& term : _allTerms) - if (!interactions.contains(term)) - removedTerms.add(term); - - for (const Term& term : interactions) - if (!_allTerms.contains(term)) - addedTerms.add(term); - - _allTerms.set(interactions); - _setTerms(interactions, _allTerms); - - removeTermsInAssignedList(); - - endResetModel(); - - if (updateAssigned) - emit availableTermsReset(addedTerms, removedTerms); - -} - diff --git a/QMLComponents/models/listmodelinteractionavailable.h b/QMLComponents/models/listmodelinteractionavailable.h deleted file mode 100644 index 803113a1805..00000000000 --- a/QMLComponents/models/listmodelinteractionavailable.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELINTERACTIONAVAILABLE_H -#define LISTMODELINTERACTIONAVAILABLE_H - -#include "listmodelavailableinterface.h" -#include "interactionmodel.h" -#include "common.h" - -class ListModelInteractionAvailable : public ListModelAvailableInterface, public InteractionModel -{ - Q_OBJECT -public: - ListModelInteractionAvailable(JASPListControl* listView); - - void resetTermsFromSources(bool updateAssigned = true) override; -}; - -#endif // LISTMODELINTERACTIONAVAILABLE_H diff --git a/QMLComponents/models/listmodeljagsdatainput.cpp b/QMLComponents/models/listmodeljagsdatainput.cpp deleted file mode 100644 index 2dbdfb01224..00000000000 --- a/QMLComponents/models/listmodeljagsdatainput.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "log.h" -#include "qutils.h" -#include "listmodeljagsdatainput.h" -#include "analysisform.h" -#include "r_functionwhitelist.h" -#include "controls/tableviewbase.h" - -ListModelJAGSDataInput::ListModelJAGSDataInput(TableViewBase *parent) : ListModelTableViewBase(parent) -{ - _needsSource = false; - _keepRowsOnReset = false; - _tableTerms.colNames.push_back(getDefaultColName(0)); - _tableTerms.values.push_back({}); - _tableTerms.colNames.push_back(getDefaultColName(1)); - _tableTerms.values.push_back({}); - - parent->setProperty("parseDefaultValue", false); -} - -void ListModelJAGSDataInput::sourceTermsReset() -{ - beginResetModel(); - - Terms sourceTerms = getSourceTerms(); - if (_tableTerms.values.length() > 0) - { - QMap mapping; - const QVector & firstCol = _tableTerms.values[0], - & secondCol = _tableTerms.values[1]; - int row = 0; - - for (const QVariant& key : firstCol) - { - mapping[key.toString()] = secondCol[row]; - row++; - } - - _tableTerms.values.clear(); - _tableTerms.rowNames.clear(); - size_t rowCount = sourceTerms.size(); - - for (size_t row = 1; row <= rowCount; row++) - _tableTerms.rowNames.push_back(getDefaultRowName(row)); - - QList firstColumnValues = sourceTerms.asQList(); - QVector firstColumn, - secondColumn; - - for (const QString& firstValue : firstColumnValues) - { - firstColumn.push_back(firstValue); - QVariant secondValue = mapping.contains(firstValue) ? mapping[firstValue] : _tableView->defaultValue(); - secondColumn.push_back(secondValue); - } - - _tableTerms.values.push_back(firstColumn); - _tableTerms.values.push_back(secondColumn); - } - - endResetModel(); - - emit columnCountChanged(); - emit rowCountChanged(); -} - - -QString ListModelJAGSDataInput::getDefaultColName(size_t index) const -{ - if(index == 0) - return "Parameter"; - return "R Code"; -} - -bool ListModelJAGSDataInput::isEditable(const QModelIndex &index) const -{ - return index.column() >= 1 || _tableView->property("isFirstColEditable").toBool(); -} - -int ListModelJAGSDataInput::getMaximumColumnWidthInCharacters(size_t columnIndex) const -{ - return columnIndex == 0 ? 6 : 25; -} diff --git a/QMLComponents/models/listmodeljagsdatainput.h b/QMLComponents/models/listmodeljagsdatainput.h deleted file mode 100644 index 2270755963b..00000000000 --- a/QMLComponents/models/listmodeljagsdatainput.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef ListModelJAGSDataInput_H -#define ListModelJAGSDataInput_H - -#include "listmodeltableviewbase.h" - - -class ListModelJAGSDataInput : public ListModelTableViewBase -{ - Q_OBJECT - -public: - explicit ListModelJAGSDataInput(TableViewBase * parent); - - int getMaximumColumnWidthInCharacters(size_t columnIndex) const override; - - QString getDefaultColName(size_t index) const override; - bool isEditable(const QModelIndex& index) const override; - QString getItemInputType(const QModelIndex&index ) const override { return isRCodeColumn(index.column()) ? "formulaArray" : "string"; } - bool isRCodeColumn(int col) const override { return col == 1; } - -public slots: - void sourceTermsReset() override; - -}; - -#endif // ListModelJAGSDataInput_H - diff --git a/QMLComponents/models/listmodellabelvalueterms.cpp b/QMLComponents/models/listmodellabelvalueterms.cpp deleted file mode 100644 index 38afce58ab6..00000000000 --- a/QMLComponents/models/listmodellabelvalueterms.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodellabelvalueterms.h" -#include "log.h" -#include "controls/sourceitem.h" - -ListModelLabelValueTerms::ListModelLabelValueTerms(JASPListControl* listView, const JASPListControl::LabelValueMap& values) - : ListModelAvailableInterface(listView) -{ - _setLabelValues(values); -} - -QVariant ListModelLabelValueTerms::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - const Terms& myTerms = terms(); - size_t row_t = size_t(row); - - if (row < 0 || row_t >= myTerms.size()) - return QVariant(); - - if (role == ListModel::ValueRole) - { - QString label = myTerms.at(row_t).asQString(); - if (_labelToValueMap.contains(label)) - return _labelToValueMap[label]; - else - return label; - } - - return ListModelAvailableInterface::data(index, role); -} - -void ListModelLabelValueTerms::resetTermsFromSources(bool ) -{ - beginResetModel(); - - setLabelValuesFromSource(); - - endResetModel(); - - _connectAllSourcesControls(); -} - - -std::vector ListModelLabelValueTerms::getValues() -{ - std::vector values; - const Terms& terms = this->terms(); - for (const Term& term : terms) - { - QString label = term.asQString(); - QString value = _labelToValueMap.contains(label) ? _labelToValueMap[label] : label; - values.push_back(value.toStdString()); - } - - return values; -} - -QString ListModelLabelValueTerms::getValue(const QString &label) const -{ - return _labelToValueMap.contains(label) ? _labelToValueMap[label] : label; -} - -QString ListModelLabelValueTerms::getLabel(const QString &value) const -{ - return _valueToLabelMap.contains(value) ? _valueToLabelMap[value] : value; -} - -int ListModelLabelValueTerms::getIndexOfValue(const QString &value) const -{ - return terms().indexOf(getLabel(value)); -} - -int ListModelLabelValueTerms::getIndexOfLabel(const QString &label) const -{ - return terms().indexOf(label); -} - -void ListModelLabelValueTerms::_setLabelValues(const JASPListControl::LabelValueMap &labelvalues) -{ - _valueToLabelMap.clear(); - _labelToValueMap.clear(); - Terms newTerms; - - for (const auto& labelValue :labelvalues) - { - const QString& label = labelValue.first; - const QString& value = labelValue.second; - newTerms.add(Term::readTerm(label)); // The string can be an interaction between different variables (eg: a * b) - _valueToLabelMap[value] = label; - _labelToValueMap[label] = value; - } - - _setTerms(newTerms); -} - -void ListModelLabelValueTerms::setLabelValuesFromSource() -{ - JASPListControl::LabelValueMap labelValuePairs; - - if (listView()->addEmptyValue()) - labelValuePairs.push_back(std::make_pair(listView()->placeholderText(), "")); - - listView()->applyToAllSources([&](SourceItem *sourceItem, const Terms& terms) - { - ListModelLabelValueTerms* labelValueSourceModel = qobject_cast(sourceItem->sourceListModel()); - for (const Term& term : terms) - { - QString label = term.asQString(); - QString value = labelValueSourceModel ? labelValueSourceModel->getValue(label) : label; - labelValuePairs.push_back(std::make_pair(label, value)); - } - }); - - _setLabelValues(labelValuePairs); -} - -void ListModelLabelValueTerms::sourceNamesChanged(QMap map) -{ - QMap changedNamesMap; - QSet changedIndexes; - - QMapIterator it(map); - while (it.hasNext()) - { - it.next(); - const QString& oldName = it.key(), newName = it.value(); - Terms newTerms = terms(); - QSet indexes = newTerms.replaceVariableName(oldName.toStdString(), newName.toStdString()); - if (indexes.size() > 0) - { - _setTerms(newTerms); - QString oldValue = _labelToValueMap[oldName]; - _labelToValueMap.remove(oldName); - _valueToLabelMap.remove(oldValue); - QString newValue = oldValue; - listView()->applyToAllSources([&](SourceItem *sourceItem, const Terms& terms) - { - ListModelLabelValueTerms* labelValueSourceModel = qobject_cast(sourceItem->sourceListModel()); - if (terms.contains(newName) && labelValueSourceModel) - newValue = labelValueSourceModel->getValue(newName); - }); - _labelToValueMap[newName] = newValue; - _valueToLabelMap[newValue] = newName; - changedIndexes += indexes; - changedNamesMap[oldName] = newName; - } - } - - for (int i : changedIndexes) - { - QModelIndex ind = index(i, 0); - emit dataChanged(ind, ind); - } - - if (changedNamesMap.size() > 0) - emit namesChanged(changedNamesMap); -} - diff --git a/QMLComponents/models/listmodellabelvalueterms.h b/QMLComponents/models/listmodellabelvalueterms.h deleted file mode 100644 index 064bd94e6b1..00000000000 --- a/QMLComponents/models/listmodellabelvalueterms.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (C) 2013-2020 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELLABELVALUETERMS_H -#define LISTMODELLABELVALUETERMS_H - -#include "controls/jasplistcontrol.h" -#include "listmodelavailableinterface.h" - -class ListModelLabelValueTerms : public ListModelAvailableInterface -{ - Q_OBJECT -public: - ListModelLabelValueTerms(JASPListControl* listView, const JASPListControl::LabelValueMap& values = JASPListControl::LabelValueMap()); - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - void resetTermsFromSources(bool updateAssigned = true) override; - - std::vector getValues(); - QString getValue(const QString& label) const; - QString getLabel(const QString& value) const; - int getIndexOfValue(const QString& value) const; - int getIndexOfLabel(const QString& label) const; - - void setLabelValuesFromSource(); - -public slots: - void sourceNamesChanged(QMap map) override; - -protected: - void _setLabelValues(const JASPListControl::LabelValueMap& values); - - QMap _valueToLabelMap; - QMap _labelToValueMap; - -}; - -#endif // LISTMODELLABELVALUETERMS_H diff --git a/QMLComponents/models/listmodellayersassigned.cpp b/QMLComponents/models/listmodellayersassigned.cpp deleted file mode 100644 index 06eda56a25f..00000000000 --- a/QMLComponents/models/listmodellayersassigned.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodellayersassigned.h" -#include "boundcontrols/boundcontrollayers.h" -#include "qutils.h" - -using namespace std; - - -ListModelLayersAssigned::ListModelLayersAssigned(JASPListControl* listView) - : ListModelAssignedInterface(listView) -{ -} - -void ListModelLayersAssigned::initLayers(const std::vector >& allVariables) -{ - beginResetModel(); - - for (const std::vector& variables : allVariables) - { - QList layer; - for (const std::string& variable : variables) - layer.push_back(QString::fromStdString(variable)); - _variables.push_back(layer); - } - - _setTerms(); - - if (availableModel() != nullptr) - { - if (!_copyTermsWhenDropped) - availableModel()->removeTermsInAssignedList(); - } - - endResetModel(); -} - -std::vector > > ListModelLayersAssigned::getLayers() const -{ - std::vector > > layers; - - int layerNr = 0; - for (const QList& variables : _variables) - { - std::vector layer; - for (const QString& variable : variables) - layer.push_back(variable.toStdString()); - layers.push_back(make_pair(tr("Layer %1").arg(layerNr).toStdString(), layer)); - } - - return layers; -} - -int ListModelLayersAssigned::_getLayer(int index, int& indexInLayer, bool inclusive) const -{ - int layer = 0; - int layerIndex = 0; // Layer 1 - indexInLayer = -1; - - if (inclusive) index--; - while ((layer < _variables.length()) && (layerIndex + _variables[layer].length() < index)) - { - layerIndex += _variables[layer].length() + 1; - layer++; - } - - if (inclusive) index++; - if (layer < _variables.length()) - indexInLayer = index - layerIndex - 1; - - return layer; -} - -void ListModelLayersAssigned::_setTerms() -{ - Terms newTerms; - int layer = 1; - for (const QList& variables : _variables) - { - newTerms.add(tr("Layer %1").arg(layer)); - for (const QString& variable : variables) - newTerms.add(variable); - layer++; - } - - newTerms.add(tr("Layer %1").arg(layer)); - - ListModel::_setTerms(newTerms); -} - -Terms ListModelLayersAssigned::termsFromIndexes(const QList &indexes) const -{ - Terms terms; - - for (int index : indexes) - { - int indexInLayer = -1; - int layer = _getLayer(index, indexInLayer); - if (layer < _variables.length()) - { - if (indexInLayer >= 0 && indexInLayer < _variables[layer].length()) - terms.add(Term(_variables[layer][indexInLayer])); - } - } - - return terms; -} - -Terms ListModelLayersAssigned::addTerms(const Terms& terms, int dropItemIndex, const RowControlsValues&) -{ - Terms result; - beginResetModel(); - - int layer = _variables.length(); - int indexInLayer = 0; - if (dropItemIndex >= 0) - layer = _getLayer(dropItemIndex, indexInLayer, true); - - if (layer >= _variables.length()) - { - _variables.push_back(QList()); - layer = _variables.length() - 1; - indexInLayer = 0; - } - - if (indexInLayer < 0) - indexInLayer = 0; - - for (const Term& term : terms) - _variables[layer].insert(indexInLayer, term.asQString()); - - _setTerms(); - - endResetModel(); - - return result; -} - -void ListModelLayersAssigned::moveTerms(const QList &indexes, int dropItemIndex) -{ - beginResetModel(); - - int layerDrop = _variables.length(); - int indexInLayerDrop = 0; - if (dropItemIndex >= 0) - layerDrop = _getLayer(dropItemIndex, indexInLayerDrop, true); - - if (layerDrop >= _variables.length()) - { - _variables.push_back(QList()); - layerDrop = _variables.length() - 1; - indexInLayerDrop = 0; - } - - if (indexInLayerDrop < 0) - indexInLayerDrop = 0; - - QList movedVariables; - QList sortedIndexes = indexes; - std::sort(sortedIndexes.begin(), sortedIndexes.end(), std::greater()); - // Store first the variables that must be moved, before removing them in the _variables list: - // removing the items in the _variables list will change the indexes - for (int index : sortedIndexes) - { - int indexInLayer = 0; - int layer = _getLayer(index, indexInLayer); - - if (layer < _variables.length() && indexInLayer >= 0 && indexInLayer < _variables[layer].length()) - movedVariables.push_back(_variables[layer][indexInLayer]); - } - - for (int index : sortedIndexes) - { - int indexInLayer = 0; - int layer = _getLayer(index, indexInLayer); - - if (layer < _variables.length() && indexInLayer >= 0 && indexInLayer < _variables[layer].length()) - { - if (layer == layerDrop && indexInLayer < indexInLayerDrop) - indexInLayerDrop--; - _variables[layer].removeAt(indexInLayer); - } - } - - for (const QString& variable : movedVariables) - _variables[layerDrop].insert(indexInLayerDrop, variable); - - for (int i = _variables.length() - 1; i >= 0; i--) - { - if (_variables[i].length() == 0) - _variables.removeAt(i); - } - - _setTerms(); - - endResetModel(); -} - -void ListModelLayersAssigned::removeTerms(const QList &indexes) -{ - beginResetModel(); - - QList sortedIndexes = indexes; - std::sort(sortedIndexes.begin(), sortedIndexes.end(), std::greater()); - - - for (int index : sortedIndexes) - { - int layer = _variables.length(); - int indexInLayer = 0; - - layer = _getLayer(index, indexInLayer); - if (layer >= 0 && layer < _variables.length() && indexInLayer >= 0 && indexInLayer < _variables[layer].length()) - _variables[layer].removeAt(indexInLayer); - - } - - for (int i = _variables.length() - 1; i >= 0; i--) - { - if (_variables[i].length() == 0) - _variables.removeAt(i); - } - - _setTerms(); - - endResetModel(); -} - -QVariant ListModelLayersAssigned::data(const QModelIndex &index, int role) const -{ - if ( ! index.isValid()) - return QVariant(); - - QVariant result; - - int indexInLayer = -1; - int layer = _getLayer(index.row(), indexInLayer); - - if (role == ListModel::SelectableRole) - { - result = (indexInLayer >= 0); - } - else if (role == ListModel::TypeRole) - { - if (indexInLayer < 0) - { - QString type = "layer"; - if (layer == _variables.length()) - type += ",virtual"; - result = type; - } - else - result = "variable"; - } - else if (role == ListModel::ColumnTypeRole) - { - if (layer >= 0 && layer < _variables.length() && indexInLayer >= 0 && indexInLayer < _variables[layer].length()) - { - QString variable = _variables[layer][indexInLayer]; - result = requestInfo(VariableInfo::VariableTypeName, variable).toString(); - } - } - else - result = ListModelAssignedInterface::data(index, role); - - - return result; -} diff --git a/QMLComponents/models/listmodellayersassigned.h b/QMLComponents/models/listmodellayersassigned.h deleted file mode 100644 index 0c291a17929..00000000000 --- a/QMLComponents/models/listmodellayersassigned.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELLAYERSASSIGNED_H -#define LISTMODELLAYERSASSIGNED_H - -#include "listmodelassignedinterface.h" - -class ListModelLayersAssigned : public ListModelAssignedInterface -{ - Q_OBJECT -public: - ListModelLayersAssigned(JASPListControl* listView); - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - Terms termsFromIndexes(const QList &indexes) const override; - Terms addTerms(const Terms& terms, int dropItemIndex = -1, const RowControlsValues& rowValues = RowControlsValues()) override; - void moveTerms(const QList& indexes, int dropItemIndex = -1) override; - void removeTerms(const QList& indexes) override; - - void initLayers(const std::vector >& allVariables); - std::vector > > getLayers() const; - -private: - int _getLayer(int index, int& realIndex, bool inclusive = false) const; - void _setTerms(); - - QList > _variables; -}; - -#endif // LISTMODELLAYERSASSIGNED_H diff --git a/QMLComponents/models/listmodelmeasurescellsassigned.cpp b/QMLComponents/models/listmodelmeasurescellsassigned.cpp deleted file mode 100644 index 7f3ed2b554c..00000000000 --- a/QMLComponents/models/listmodelmeasurescellsassigned.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelmeasurescellsassigned.h" -#include "listmodelfactorlevels.h" -#include "controls/variableslistbase.h" -#include "boundcontrols/boundcontrolmeasurescells.h" -#include "log.h" - -using namespace std; - - -ListModelMeasuresCellsAssigned::ListModelMeasuresCellsAssigned(JASPListControl* listView) - : ListModelAssignedInterface(listView) -{ -} - -void ListModelMeasuresCellsAssigned::initLevels(const Terms &levels, const Terms &variables, bool initVariables) -{ - beginResetModel(); - _levels.clear(); - vector > allLevels = levels.asVectorOfVectors(); - - for (const vector& levels : allLevels) - { - string concatLevels; - if (levels.size() > 0) - concatLevels = levels[0]; - for (uint i = 1; i < levels.size(); i++) - concatLevels += "," + levels[i]; - _levels.push_back(QString::fromStdString(concatLevels)); - } - - if (initVariables) - _setTerms(variables); - - _fitTermsWithLevels(); - - if (availableModel() != nullptr) - availableModel()->removeTermsInAssignedList(); - - endResetModel(); -} - -void ListModelMeasuresCellsAssigned::_fitTermsWithLevels() -{ - while (terms().size() < size_t(_levels.size())) - _addTerm(QString(), false); - - if (terms().size() > size_t(_levels.size())) - { - while (terms().size() > size_t(_levels.size())) - _removeLastTerm(); - } -} - -void ListModelMeasuresCellsAssigned::sourceTermsReset() -{ - VariablesListBase* measureCellsListView = dynamic_cast(listView()); - if (measureCellsListView) - { - BoundControlMeasuresCells* boundControl = dynamic_cast(measureCellsListView->boundControl()); - initLevels(boundControl->getLevels()); - availableModel()->removeTermsInAssignedList(); - } - else - Log::log() << "ListView from Measures cells model is not of a Measures Cell type!!"; -} - -Terms ListModelMeasuresCellsAssigned::termsFromIndexes(const QList &indexes) const -{ - Terms result; - for (int index : indexes) - { - size_t realIndex = size_t(index / 2); - if (realIndex < terms().size()) - result.add(terms().at(realIndex)); - } - - return result; -} - -void ListModelMeasuresCellsAssigned::initTerms(const Terms &terms, const ListModel::RowControlsValues &allValuesMap, bool reInit) -{ - ListModelAssignedInterface::initTerms(terms, allValuesMap, reInit); - _fitTermsWithLevels(); -} - -Terms ListModelMeasuresCellsAssigned::addTerms(const Terms& termsToAdd, int dropItemIndex, const RowControlsValues&) -{ - beginResetModel(); - if (dropItemIndex >= 0) - dropItemIndex = dropItemIndex / 2; - Terms termsToSendBack; - if (dropItemIndex >= 0) - { - if (termsToAdd.size() > 1 || dropItemIndex >= int(terms().size())) - termsToSendBack.set(termsToAdd); - else - { - const Term& newTerm = termsToAdd.at(0); - const Term& oldTerm = terms().at(size_t(dropItemIndex)); - if (!oldTerm.asString().empty()) - termsToSendBack.add(Term(oldTerm)); - _replaceTerm(dropItemIndex, newTerm); - } - } - else - { - size_t index = 0; - for (size_t i = 0; i < terms().size() && index < termsToAdd.size(); i++) - { - const Term& oldTerm = terms().at(i); - if (oldTerm.asQString().isEmpty()) - { - const Term& newTerm = termsToAdd.at(index); - _replaceTerm(int(i), newTerm); - index++; - } - } - - for (size_t i = index; i < termsToAdd.size(); i++) - { - const Term& term = termsToAdd.at(i); - termsToSendBack.add(term); - } - } - - endResetModel(); - - return termsToSendBack; -} - -void ListModelMeasuresCellsAssigned::moveTerms(const QList &indexes, int dropItemIndex) -{ - if (indexes.length() != 1 || dropItemIndex < 0) - return; - - size_t fromIndex = size_t(indexes[0]); - size_t fromRow = fromIndex / 2; - if (fromRow >= terms().size()) - return; - size_t dropRow = size_t(dropItemIndex / 2); - if (dropRow >= terms().size()) - return; - - beginResetModel(); - Term fromValue = terms().at(fromRow); - Term dropValue = terms().at(dropRow); - _replaceTerm(int(fromRow), dropValue); - _replaceTerm(int(dropRow), fromValue); - endResetModel(); -} - -void ListModelMeasuresCellsAssigned::removeTerms(const QList &indexes) -{ - beginResetModel(); - for (int i = 0; i < indexes.length(); i++) - { - int index = indexes[i] / 2; - if (index < int(terms().size())) - _replaceTerm(index, QString()); - } - endResetModel(); -} - -QVariant ListModelMeasuresCellsAssigned::data(const QModelIndex &index, int role) const -{ - if ( ! index.isValid()) - { - Log::log() << "ListModelMeasuresCellsAssigned::data: Data invalid!" << std::endl; - return QVariant(); - } - - int indexRow = index.row(); - int realCol = indexRow % 2; - int realRow = indexRow / 2; - - if (realRow >= int(terms().size())) - return QVariant(); - - if (role == Qt::DisplayRole || role == ListModel::NameRole) - { - if (realCol == 0) - return terms()[size_t(realRow)].asQString(); - else - return _levels[realRow]; - } - else if (role == ListModel::SelectableRole) - { - return realCol == 0 && !terms().at(size_t(realRow)).asString().empty(); - } - else if (role == ListModel::SelectedRole) - { - if (_selectedItems.contains(indexRow) && realCol == 0) - return true; - else - return false; - } - else if (role == ListModel::TypeRole) - { - if (realCol == 0) - return "variable"; - else - return "level"; - } - else - return ListModelAssignedInterface::data(index, role); -} diff --git a/QMLComponents/models/listmodelmeasurescellsassigned.h b/QMLComponents/models/listmodelmeasurescellsassigned.h deleted file mode 100644 index b0e37eff94b..00000000000 --- a/QMLComponents/models/listmodelmeasurescellsassigned.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELMEASURESCELLSASSIGNED_H -#define LISTMODELMEASURESCELLSASSIGNED_H - -#include "listmodelassignedinterface.h" - -class ListModelFactorLevels; - -class ListModelMeasuresCellsAssigned : public ListModelAssignedInterface -{ - Q_OBJECT -public: - ListModelMeasuresCellsAssigned(JASPListControl* listView); - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { return _levels.size() * 2; } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - Terms termsFromIndexes(const QList &indexes) const override; - void initTerms(const Terms &terms, const RowControlsValues& allValuesMap = RowControlsValues(), bool reInit = false) override; - Terms addTerms(const Terms& termsToAdd, int dropItemIndex = -1, const RowControlsValues& rowValues = RowControlsValues()) override; - void moveTerms(const QList& indexes, int dropItemIndex = -1) override; - void removeTerms(const QList& indexes) override; - - void initLevels(const Terms& levels, const Terms &variables = Terms(), bool initVariables = false); - -public slots: - void sourceTermsReset() override; - -private: - void _fitTermsWithLevels(); - - QList _levels; -}; - -#endif // LISTMODELMEASURESCELLSASSIGNED_H diff --git a/QMLComponents/models/listmodelmultinomialchi2test.cpp b/QMLComponents/models/listmodelmultinomialchi2test.cpp deleted file mode 100644 index 41c8f03f758..00000000000 --- a/QMLComponents/models/listmodelmultinomialchi2test.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "log.h" -#include "qutils.h" -#include "listmodelmultinomialchi2test.h" -#include "analysisform.h" -#include "controls/tableviewbase.h" - -ListModelMultinomialChi2Test::ListModelMultinomialChi2Test(TableViewBase * parent) - : ListModelTableViewBase(parent) -{ - _tableView->setUseSourceLevels(true); -} - -bool ListModelMultinomialChi2Test::sourceLabelsChanged(QString columnName, QMap changedLabels) -{ - if (!_columnsUsedForLabels.contains(columnName)) - return false; - - if (changedLabels.size() == 0) - { - // the changed labels are not specified. Reset the values from the source. - sourceTermsReset(); - return true; - } - - QList keys = changedLabels.keys(); - for (int row=0; row<_tableTerms.rowNames.size(); row++) - if (changedLabels.contains(_tableTerms.rowNames[row])) - { - _tableTerms.rowNames[row] = changedLabels[_tableTerms.rowNames[row]]; - emit headerDataChanged(Qt::Vertical, row, row); - break; - } - - return false; -} - -bool ListModelMultinomialChi2Test::sourceLabelsReordered(QString columnName) -{ - if (!_columnsUsedForLabels.contains(columnName)) - return false; - - std::map> tempStore; - - //because everything is stored in columns we first need to map all the rows, to well rows (with the name being key) - for (int row = 0; row < rowCount(); row++) - for (int col = 0; col < columnCount(); col++) - tempStore[_tableTerms.rowNames[row]].push_back(_tableTerms.values[col][row]); - - beginResetModel(); - _tableTerms.rowNames = getSourceTerms().asQList(); - _tableTerms.values.clear(); - _tableTerms.values.resize(columnCount()); - - for (int row = 0; row < rowCount(); row++) - for( int col = 0; col < columnCount(); col++) - _tableTerms.values[col].push_back(tempStore[_tableTerms.rowNames[row]][size_t(col)]); - - endResetModel(); - - return true; -} - diff --git a/QMLComponents/models/listmodelmultinomialchi2test.h b/QMLComponents/models/listmodelmultinomialchi2test.h deleted file mode 100644 index c528c7a153c..00000000000 --- a/QMLComponents/models/listmodelmultinomialchi2test.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELMULTINOMIALCHI2TEST_H -#define LISTMODELMULTINOMIALCHI2TEST_H - -#include "listmodeltableviewbase.h" - - -class ListModelMultinomialChi2Test : public ListModelTableViewBase -{ - Q_OBJECT - -public: - explicit ListModelMultinomialChi2Test(TableViewBase * parent); - -public slots: - bool sourceLabelsChanged(QString columnName, QMap = {}) override; - bool sourceLabelsReordered(QString columnName) override; -}; - -#endif // LISTMODELMULTINOMIALCHI2TEST_H - diff --git a/QMLComponents/models/listmodelmultitermsassigned.cpp b/QMLComponents/models/listmodelmultitermsassigned.cpp deleted file mode 100644 index a0c2b29d9e7..00000000000 --- a/QMLComponents/models/listmodelmultitermsassigned.cpp +++ /dev/null @@ -1,364 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodelmultitermsassigned.h" -#include "controls/jasplistcontrol.h" -#include "log.h" - - -using namespace std; - -ListModelMultiTermsAssigned::ListModelMultiTermsAssigned(JASPListControl* listView, int columns) - : ListModelAssignedInterface(listView) - , _columns(columns) -{ - _copyTermsWhenDropped = true; - _allowDuplicatesInMultipleColumns = listView->property("allowDuplicatesInMultipleColumns").toBool(); -} - -void ListModelMultiTermsAssigned::initTerms(const Terms &terms, const RowControlsValues& allValuesMap, bool) -{ - beginResetModel(); - - // The terms are sent either in groups (terms has multiple components) or one by one (no multiple components) - if (terms.size() > 0) - { - if (terms[0].components().size() > 1) - { - _tuples.clear(); - - for (const Term& term : terms) - { - Terms row; - - for (const QString& comp : term.components()) - row.add(comp, false); - _tuples.push_back(row); - } - } - else - { - // In this case discard elements in tuples that are not in terms. - // And then add the terms that were not in the tuples - QList newTuples; - for (int i = 0; i < _tuples.size(); i++) - { - Terms row = _tuples[i]; - row.discardWhatIsntTheseTerms(terms); - if (row.size() > 0) - { - for (int j = int(row.size()); j < _columns; j++) - row.add(QString(), false); - newTuples.push_back(row); - } - } - - _tuples = newTuples; - Terms unusedTerms = terms; - - for (const Terms& tuple : _tuples) - unusedTerms.discardWhatDoesContainTheseTerms(tuple); - - size_t index = 0; - while (unusedTerms.size() > index) - { - Terms row; - for (int i = 0; i < _columns; i++) - { - if (unusedTerms.size() > index) - row.add(unusedTerms.at(index), false); - else - row.add(QString(), false); - index++; - } - _tuples.push_back(row); - } - } - } - - _setTerms(); - - _rowControlsValues = allValuesMap; - endResetModel(); - -} - -void ListModelMultiTermsAssigned::removeTerms(const QList &indexes) -{ - if (indexes.length() == 0) return; - - beginResetModel(); - - QList orderedIndexed = indexes; - std::sort(orderedIndexed.begin(), orderedIndexed.end(), std::greater()); - - for (const int &orderedIndexed: orderedIndexed) - { - int row = orderedIndexed / _columns; - int col = orderedIndexed % _columns; - - if (row < _tuples.length()) - { - const Terms& terms = _tuples.at(row); - bool isEmpty = true; - for (int i = 0; i < _columns; i++) - { - if (i != col && !terms.at(size_t(i)).asQString().isEmpty()) - isEmpty = false; - } - if (isEmpty) - _tuples.removeAt(row); - else - { - Terms newTerms = terms; - newTerms.replace(col, QString()); - _tuples[row] = newTerms; - } - } - } - - _setTerms(); - endResetModel(); -} - -void ListModelMultiTermsAssigned::availableTermsResetHandler(Terms , Terms termsToRemove) -{ - QList indexes; - int i = 0; - for (const Term& oneTerm : terms()) - { - if (termsToRemove.contains(oneTerm)) indexes.append(i); - i++; - } - - if (indexes.size() > 0) - removeTerms(indexes); -} - -void ListModelMultiTermsAssigned::_setTerms() -{ - Terms newTerms; - for (const Terms& terms : _tuples) - { - for (const Term& term : terms) - newTerms.add(term, false); - } - - ListModel::_setTerms(newTerms); -} - - -Terms ListModelMultiTermsAssigned::addTerms(const Terms& termsToAdd, int dropItemIndex, const RowControlsValues&) -{ - beginResetModel(); - Terms termsToReturn; - - if (termsToAdd.size() == 0) - return termsToReturn; - - bool done = false; - if (termsToAdd.size() == 1 && dropItemIndex >= 0) - { - // Case when only 1 term is added on one particular place - // . Check first if it is possible to the term at this place. - // . Then set the term at this place. - // . It there was already a term at that place, return it. - int realRow = dropItemIndex / _columns; - int realCol = dropItemIndex % _columns; - if (realRow < _tuples.size()) - { - Terms row = _tuples[realRow]; - const Term& termToAdd = termsToAdd.at(0); - - if (row.contains(termToAdd) && !_allowDuplicatesInMultipleColumns) - termsToReturn.add(termToAdd); - else - { - const Term& term = row[size_t(realCol)]; - if (!term.asQString().isEmpty()) - termsToReturn.add(term); - row.replace(realCol, termToAdd); - _tuples[realRow] = row; - } - done = true; - } - } - - if (!done) - { - // First try to set the terms to the empty places - size_t index = 0; - for (int row = 0; row < _tuples.length() && index < termsToAdd.size(); row++) - { - Terms tuple = _tuples.at(row); - bool changed = false; - for (int col = 0; col < _columns && index < termsToAdd.size(); col++) - { - if (tuple[size_t(col)].asQString().isEmpty()) - { - const Term& termToAdd = termsToAdd.at(index); - if (tuple.contains(termToAdd) && !_allowDuplicatesInMultipleColumns) - termsToReturn.add(termsToAdd); - else - { - tuple.replace(col, termsToAdd.at(index)); - changed = true; - } - index++; - } - } - if (changed) - _tuples[row] = tuple; - } - - // If there still some terms to add, add them at the end of the list - while (index < termsToAdd.size()) - { - Terms newTuple; - for (int i = 0; i < _columns; i++) - { - if (index < termsToAdd.size()) - { - newTuple.add(termsToAdd.at(index), false); - index++; - } - else - newTuple.add(QString(), false); - } - _tuples.push_back(newTuple); - } - } - - _setTerms(); - endResetModel(); - - return termsToReturn; -} - -void ListModelMultiTermsAssigned::moveTerms(const QList &indexes, int dropItemIndex) -{ - if (indexes.length() != 1) - return; - - int fromIndex = indexes[0]; - if (fromIndex == dropItemIndex) - return; - - int fromRow = fromIndex / _columns; - int fromCol = fromIndex % _columns; - - if (fromRow >= _tuples.size()) - return; - - Terms fromTuple = _tuples[fromRow]; - Terms dropTuple; - int dropRow = -1; - bool addNewRow = false; - Term fromValue = fromTuple[size_t(fromCol)]; - - if (fromValue.asQString().isEmpty()) - return; - - beginResetModel(); - - if (dropItemIndex >= 0) - { - // First handle the case when the term is dropped on one particular place - dropRow = dropItemIndex / _columns; - int dropCol = dropItemIndex % _columns; - - if (dropRow < _tuples.size()) - { - dropTuple = _tuples[dropRow]; - Term dropValue = dropTuple[size_t(dropCol)]; - - if (dropRow == fromRow) - { - if (fromCol != dropCol) - { - dropTuple.replace(dropCol, fromValue); - dropTuple.replace(fromCol, dropValue); - _tuples[dropRow] = dropTuple; - } - } - else - { - // If it does not allow duplicates, and the dropTuple contains the fromValue or the fromTuple contains the dropValue (if not empty), then do not exchange the values. - if (!(!_allowDuplicatesInMultipleColumns && (dropTuple.contains(fromValue) || (!dropValue.asQString().isEmpty() && fromTuple.contains(dropValue))))) - { - dropTuple.replace(dropCol, fromValue); - fromTuple.replace(fromCol, dropValue); - _tuples[dropRow] = dropTuple; - _tuples[fromRow] = fromTuple; - } - } - } - else - { - fromTuple.replace(fromCol, QString()); - _tuples[fromRow] = fromTuple; - addNewRow = true; - } - } - else - { - // The term is dropped at the end of the list. - // Check whether the last row has still some place - fromTuple.replace(fromCol, QString()); - _tuples[fromRow] = fromTuple; - - dropRow = _tuples.size() - 1; - dropTuple = _tuples[dropRow]; - addNewRow = true; - - // It it does not allow duplicates, and the last row contains the fromValue, then do not try to add the fromValue to the last row - if (!(!_allowDuplicatesInMultipleColumns && dropTuple.contains(fromValue))) - { - for (int i = 0; i < _columns && !addNewRow; i++) - { - if (dropTuple[size_t(i)].asQString().isEmpty()) - { - dropTuple.replace(i, fromValue); - _tuples[dropRow] = dropTuple; - addNewRow = false; - } - } - } - } - - if (addNewRow) - { - Terms newRow; - newRow.add(fromValue); - for (int i = 1; i < _columns; i++) - newRow.add(QString(), false); - _tuples.push_back(newRow); - } - - bool removeFromTuple = true; - for (int i = 0; i < _columns; i++) - { - if (!fromTuple[size_t(i)].asQString().isEmpty()) - removeFromTuple = false; - } - if (removeFromTuple) - _tuples.removeAt(fromRow); - - _setTerms(); - endResetModel(); -} diff --git a/QMLComponents/models/listmodelmultitermsassigned.h b/QMLComponents/models/listmodelmultitermsassigned.h deleted file mode 100644 index 3d9cb3b834e..00000000000 --- a/QMLComponents/models/listmodelmultitermsassigned.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELMULTITERMSASSIGNED_H -#define LISTMODELMULTITERMSASSIGNED_H - -#include "listmodelassignedinterface.h" - -class ListModelMultiTermsAssigned: public ListModelAssignedInterface -{ - Q_OBJECT -public: - ListModelMultiTermsAssigned(JASPListControl* listView, int columns = 2); - - void initTerms(const Terms &terms, const RowControlsValues& allValuesMap = RowControlsValues(), bool reInit = false) override; - Terms addTerms(const Terms &terms, int dropItemIndex = -1, const RowControlsValues& rowValues = RowControlsValues()) override; - void moveTerms(const QList& indexes, int dropItemIndex = -1) override; - void removeTerms(const QList &indexes) override; - - const QList& tuples() const { return _tuples; } - -public slots: - void availableTermsResetHandler(Terms termsToAdd, Terms termsToRemove) override; - -private: - void _setTerms(); - -protected: - int _columns = 2; - QList _tuples; - bool _allowDuplicatesInMultipleColumns = false; -}; - -#endif // LISTMODELMULTITERMSASSIGNED_H diff --git a/QMLComponents/models/listmodeltableviewbase.cpp b/QMLComponents/models/listmodeltableviewbase.cpp deleted file mode 100644 index 835b3bb939f..00000000000 --- a/QMLComponents/models/listmodeltableviewbase.cpp +++ /dev/null @@ -1,508 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "log.h" -#include -#include -#include "listmodeltableviewbase.h" -#include "analysisform.h" -#include "qutils.h" -#include "controls/tableviewbase.h" -#include "controls/textinputbase.h" -#include "utilities/desktopcommunicator.h" - -using namespace std; - -ListModelTableViewBase::ListModelTableViewBase(TableViewBase * tableView) - : ListModel(tableView), _tableView(tableView) -{ - connect(DesktopCommunicator::singleton(), &DesktopCommunicator::uiScaleChanged, this, &ListModelTableViewBase::refresh); -} - -QVariant ListModelTableViewBase::data(const QModelIndex &index, int role) const -{ - int column = index.column(), - row = index.row(); - - if (column < 0 || column >= columnCount() || row < 0 || row >= rowCount()) - return QVariant(); - - switch(role) - { - case int(specialRoles::lines): - { - bool belowMeIsActive = row < rowCount() - 1, - up = true, - left = true, - down = !belowMeIsActive, - right = column == columnCount() - 1; //always draw left line and right line only if last col - - return (left ? 1 : 0) + - (right ? 2 : 0) + - (up ? 4 : 0) + - (down ? 8 : 0); - } - case int(specialRoles::itemInputType): return getItemInputType(index); - case Qt::DisplayRole: return QVariant(_tableTerms.values[column][row]); - default: return ListModel::data(index, role); - } -} - - -int ListModelTableViewBase::getMaximumColumnWidthInCharacters(size_t columnIndex) const -{ - int maxL = 3; - int column = int(columnIndex); - - if (column < _tableTerms.values.size()) - for (QVariant val : _tableTerms.values[column]) - maxL = std::max(static_cast(val.toString().size()), maxL); - - return maxL + 3; -} - - -QString ListModelTableViewBase::getMaximumRowHeaderString() const -{ - int maxL = 7; - - for (QString val : _tableTerms.rowNames) - maxL = std::max(static_cast(val.size() + 2), maxL); - - QString dummyText; - while (maxL > dummyText.length()) - dummyText += "X"; - - return dummyText; -} - -void ListModelTableViewBase::addColumn(bool emitStuff) -{ - if (emitStuff) - beginResetModel(); - - size_t count = size_t(columnCount()); - - if (count < _maxColumn) - { - _tableTerms.colNames.push_back(getDefaultColName(count)); - QVector values; - for (int rowIndex = 0; rowIndex < _tableTerms.rowNames.length(); rowIndex++) - values.push_back(_tableView->defaultValue(count, rowIndex)); - _tableTerms.values.push_back(values); - } - - if (emitStuff) - { - endResetModel(); - - emit columnCountChanged(); - } -} - -void ListModelTableViewBase::removeColumn(size_t col, bool emitStuff) -{ - if (emitStuff) - beginResetModel(); - int colIndex = int(col); - - if (colIndex < columnCount()) - { - _tableTerms.values.removeAt(colIndex); - _tableTerms.colNames.pop_back(); - } - - if (emitStuff) - { - endResetModel(); - - emit columnCountChanged(); - } -} - -void ListModelTableViewBase::addRow(bool emitStuff) -{ - if (emitStuff) - beginResetModel(); - - if (rowCount() < int(_maxRow)) - { - _tableTerms.rowNames.push_back(getDefaultRowName(rowCount())); - int colIndex = 0; - for (QVector & value : _tableTerms.values) - { - while (value.size() < _tableTerms.rowNames.size()) //Lets make sure the data is rectangular! - value.push_back(_tableView->defaultValue(colIndex, value.length())); - colIndex++; - } - } - - if (emitStuff) - { - endResetModel(); - - emit rowCountChanged(); - } -} - -void ListModelTableViewBase::removeRow(size_t row, bool emitStuff) -{ - if (emitStuff) - beginResetModel(); - - if (row < rowCount()) - { - for (QVector & value : _tableTerms.values) - value.removeAt(int(row)); - _tableTerms.rowNames.pop_back(); //Should we remove the exact right rowName? Or I guess there just generated row for row in the base.. - } - - if (emitStuff) - { - endResetModel(); - - emit rowCountChanged(); - } -} - -void ListModelTableViewBase::setSize(int rows, int columns, bool emitStuff) -{ - if (emitStuff) - beginResetModel(); - - bool rowsChanged = false; - if (rows > -1) - { - if (rows < rowCount()) - { - for (QVector & value : _tableTerms.values) - value.erase(value.begin() + rows, value.end()); - _tableTerms.rowNames.erase(_tableTerms.rowNames.begin() + rows, _tableTerms.rowNames.end()); - - rowsChanged = true; - } - else if (rows > rowCount()) - { - size_t oldRowCount = rowCount(); - for (int i = 0; i < rows - oldRowCount; i++) - { - _tableTerms.rowNames.push_back(getDefaultRowName(rowCount())); - int colIndex = 0; - for (QVector & value : _tableTerms.values) - { - while (value.size() < _tableTerms.rowNames.size()) - value.push_back(_tableView->defaultValue(colIndex, value.length())); - colIndex++; - } - } - - rowsChanged = true; - } - } - - bool columnsChanged = false; - if (columns > -1) - { - if (columns < columnCount()) - { - _tableTerms.values.erase(_tableTerms.values.begin() + columns, _tableTerms.values.end()); - _tableTerms.colNames.erase(_tableTerms.colNames.begin() + columns, _tableTerms.colNames.end()); - - columnsChanged = true; - } - else if (columns > columnCount()) - { - size_t oldColumnCount = columnCount(); - for (int i = 0; i < columns - oldColumnCount; i++) - { - _tableTerms.colNames.push_back(getDefaultColName(columnCount())); - QVector values; - for (int rowIndex = 0; rowIndex < _tableTerms.rowNames.length(); rowIndex++) - values.push_back(_tableView->defaultValue(columnCount(), rowIndex)); - _tableTerms.values.push_back(values); - } - - columnsChanged = true; - } - } - - if (emitStuff) - { - endResetModel(); - - if (columnsChanged) - emit columnCountChanged(); - - if (rowsChanged) - emit rowCountChanged(); - } -} - -void ListModelTableViewBase::reset() -{ - beginResetModel(); - - if (!_keepColsOnReset) _tableTerms.colNames.clear(); - if (!_keepRowsOnReset) _tableTerms.rowNames.clear(); - - _tableTerms.values.clear(); - - if (!_keepColsOnReset) - for (int col=0; col < _tableView->initialColumnCount(); col++) - addColumn(false); - - int rows = std::max(static_cast(_tableTerms.rowNames.length()), _tableView->initialRowCount()); - - if (!_keepRowsOnReset) - for (int row=0; row < rows; row++) - addRow(false); - - endResetModel(); - - emit columnCountChanged(); - emit rowCountChanged(); -} - -void ListModelTableViewBase::itemChanged(int column, int row, QVariant value, QString type) -{ - //If you change this function, also take a look at ListModelFilteredDataEntry::itemChanged - if (column > -1 && column < columnCount() && row > -1 && row < rowCount()) - { - if (_tableTerms.values[column][row] != value) - { - JASPControl::ItemType itemType = _tableView->itemTypePerItem(column, row); - _tableTerms.values[column][row] = itemType == JASPControl::ItemType::Integer ? value.toInt() : itemType == JASPControl::ItemType::Double ? value.toDouble() : value; - - if (type != "formula") // For formula type, wait for the formulaCheckSucceeded signal before emitting modelChanged - emit termsChanged(); - - // Here we should *actually* check if specialRoles::maxColString changes and in that case: (so that the view can recalculate stuff) - // emit headerDataChanged(Qt::Orientation::Horizontal, column, column); - } - } -} - -Terms ListModelTableViewBase::filterTerms(const Terms& terms, const QStringList& filters) -{ - Terms tempTerms; - QStringList otherFilters; - - std::set colNbs; - if (filters.empty() && _tableTerms.values.length() == 1) - colNbs.insert(0); - - for (const QString& filter : filters) - { - int colNb = _tableTerms.colNames.indexOf(filter); - if (colNb == -1 && filter.startsWith("column")) - { - QString tempWhat = filter; - QString colNbStr = tempWhat.remove("column"); - bool ok = false; - colNb = colNbStr.toInt(&ok); - if (!ok) colNb = -1; - if (colNb > 0) colNb--; - } - - if (colNb != -1) colNbs.insert(colNb); - else otherFilters.append(filter); - } - - for (int colNb : colNbs) - { - if (_tableTerms.values.length() > colNb) - { - const QVector& values = _tableTerms.values[colNb]; - for (const QVariant& val : values) - { - QString value = val.toString(); - if (!value.isEmpty() && value != "...") - tempTerms.add(val.toString()); - } - } - else - addControlError(tr("Column number in source is bigger than the number of columns of %1").arg(name())); - } - - return ListModel::filterTerms(tempTerms, otherFilters); -} - -QVariant ListModelTableViewBase::headerData( int section, Qt::Orientation orientation, int role) const -{ - if (role == int(specialRoles::maxRowHeaderString)) return getMaximumRowHeaderString(); - - if (section < 0 || section >= (orientation == Qt::Horizontal ? _tableTerms.colNames.length() : _tableTerms.rowNames.length())) - return QVariant(); - - switch(role) - { - case int(specialRoles::maxColString): //A query from DataSetView for the maximumlength string to be expected! This to accomodate columnwidth - { - QString dummyText = headerData(section, orientation, Qt::DisplayRole).toString() + "XXXXX"; - int colWidth = getMaximumColumnWidthInCharacters(size_t(section)); - - while (colWidth > dummyText.length()) - dummyText += "X"; - - return dummyText; - } - case Qt::DisplayRole: return QVariant(orientation == Qt::Horizontal ? _tableTerms.colNames[section] : _tableTerms.rowNames[section]); - case Qt::TextAlignmentRole: return QVariant(Qt::AlignCenter); - default: return QVariant(); - } -} - -void ListModelTableViewBase::sourceTermsReset() -{ - beginResetModel(); - - QMap> tempStore; - - for (int row = 0; row < rowCount(); row++) - for (int col = 0; col < columnCount(); col++) - tempStore[_tableTerms.rowNames[row]].push_back(_tableTerms.values[col][row]); - - _tableTerms.values.clear(); - _tableTerms.rowNames = getSourceTerms().asQList(); - if (_tableTerms.colNames.size() == 0) - _tableTerms.colNames.push_back(getDefaultColName(0)); - - for (int col = 0; col < columnCount(); col++) - { - QVector newValues; - for (int row = 0; row < rowCount(); row++) - newValues.push_back(_tableView->defaultValue(col, row)); - _tableTerms.values.push_back(newValues); - - for (int row = 0; row < rowCount(); row++) - if (tempStore.contains(_tableTerms.rowNames[row]) && tempStore[_tableTerms.rowNames[row]].size() > col) - _tableTerms.values[col][row] = tempStore[_tableTerms.rowNames[row]][col]; - } - - endResetModel(); - - emit columnCountChanged(); - emit rowCountChanged(); -} - -QHash ListModelTableViewBase::roleNames() const -{ - static QHash roles = ListModel::roleNames(); - - static bool addRoles = true; - - if (addRoles) - { - roles[int(specialRoles::active)] = QString("active").toUtf8(); - roles[int(specialRoles::lines)] = QString("lines").toUtf8(); - roles[int(specialRoles::maxColString)] = QString("maxColString").toUtf8(); - roles[int(specialRoles::maxRowHeaderString)] = QString("maxRowHeaderString").toUtf8(); - roles[int(specialRoles::itemInputType)] = QString("itemInputType").toUtf8(); - addRoles = false; - } - - return roles; -} - -Qt::ItemFlags ListModelTableViewBase::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - - if (isEditable(index)) - flags |= Qt::ItemIsEditable; - - return flags; -} - -void ListModelTableViewBase::runRScript(const QString & script) -{ - _tableView->runRScript(script); -} - -bool ListModelTableViewBase::valueOk(QVariant value, int col, int row) -{ - bool ok = true; - JASPControl::ItemType itemType = _tableView->itemTypePerItem(col, row); - - if (itemType == JASPControl::ItemType::Double) value.toDouble(&ok); - else if (itemType == JASPControl::ItemType::Integer) value.toInt(&ok); - - return ok; -} - -JASPControl *ListModelTableViewBase::getRowControl(const QString &key, const QString &name) const -{ - if (_itemControls.contains(key)) return _itemControls[key][name]; - else return nullptr; -} - -bool ListModelTableViewBase::addRowControl(const QString &key, JASPControl *control) -{ - _itemControls[key][control->name()] = control; - - if (control->controlType() == JASPControl::ControlType::TextField) - { - TextInputBase* textInput = dynamic_cast(control); - if (textInput && textInput->inputType() == TextInputBase::TextInputType::FormulaType) - connect(textInput, &TextInputBase::formulaCheckSucceeded, this, &ListModelTableViewBase::formulaCheckSucceededSlot); - } - - return true; -} - -void ListModelTableViewBase::formulaCheckSucceededSlot() -{ - _tableView->resetBoundValue(); -} - - -void ListModelTableViewBase::initTableTerms(const TableTerms& terms) -{ - beginResetModel(); - - _tableTerms = terms; - - for (auto & col : _tableTerms.values) - if(_tableTerms.rowNames.size() < col.size()) - { - Log::log() << "Too many rows in a column of OptionsTable for ListModelTableViewBase! Shrinking column to fit." << std::endl; - col.resize(_tableTerms.rowNames.size()); - } - else - for (int row = col.size(); row < _tableTerms.rowNames.size(); row++) - col.push_back(1); - - endResetModel(); - - emit columnCountChanged(); - emit rowCountChanged(); -} - -QString ListModelTableViewBase::getDefaultColName(size_t index) const -{ - return listView()->property("colName").toString() + " " + QString::number(index + 1); -} - -QString ListModelTableViewBase::getItemInputType(const QModelIndex &index) const -{ - JASPControl::ItemType itemType = _tableView->itemTypePerItem(index.column(), index.row()); - - if (itemType == JASPControl::ItemType::Double) return "double"; - else if (itemType == JASPControl::ItemType::Integer) return "integer"; - else return "string"; -} diff --git a/QMLComponents/models/listmodeltableviewbase.h b/QMLComponents/models/listmodeltableviewbase.h deleted file mode 100644 index c4e7d1dbfb7..00000000000 --- a/QMLComponents/models/listmodeltableviewbase.h +++ /dev/null @@ -1,132 +0,0 @@ -// -// Copyright (C) 2013-2019 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELTABLEVIEWBASE_H -#define LISTMODELTABLEVIEWBASE_H - -#include "listmodel.h" -#include "common.h" - -class TableViewBase; - -///This class makes sure the roles that DataSetView expects are implemented and returned. -class ListModelTableViewBase : public ListModel -{ - Q_OBJECT - -public: - struct TableTerms - { - QVector > values; - QStringList rowNames, - colNames, - variables; - QString colName, - extraCol, - filter; - QVector rowIndices; - - TableTerms() {} - - void clear() - { - values.clear(); - rowNames.clear(); - colNames.clear(); - variables.clear(); - colName.clear(); - extraCol.clear(); - filter.clear(); - } - }; - - - enum class specialRoles { active = Qt::UserRole, lines, maxColString, maxRowHeaderString, itemInputType }; - - explicit ListModelTableViewBase(TableViewBase * tableView); - - QHash roleNames() const override; - - int rowCount( const QModelIndex & = QModelIndex()) const override { return _tableTerms.rowNames.length(); } - int columnCount(const QModelIndex & = QModelIndex()) const override { return _tableTerms.colNames.length(); } - int variableCount() const { return _tableTerms.variables.length(); } - QVariant data( const QModelIndex &index, int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags( const QModelIndex &index) const override; - QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - - void sourceTermsReset() override; - - virtual int getMaximumColumnWidthInCharacters(size_t columnIndex) const; - QString getMaximumRowHeaderString() const; - - virtual void initTableTerms(const TableTerms& terms); - void addColumn( bool emitStuff = true); - void removeColumn(size_t index, bool emitStuff = true); - void addRow( bool emitStuff = true); - void removeRow(size_t index, bool emitStuff = true); - void setSize(int rows, int columns, bool emitStuff = true); - virtual void reset(); - virtual void setup() {} - virtual void itemChanged(int column, int row, QVariant value, QString type); - virtual void refreshModel() { return ListModel::refresh(); } - virtual QString getDefaultColName(size_t index) const; - virtual QString getDefaultRowName(size_t index) const { return tr("Row %1").arg(index); } - virtual bool isEditable(const QModelIndex &) const { return true; } - virtual QString getItemInputType(const QModelIndex &index) const; - - const TableTerms & tableTerms() const { return _tableTerms; } - Terms filterTerms(const Terms& terms, const QStringList& filters) override; - - - void runRScript( const QString & script); - virtual void rScriptDoneHandler(const QString & result) { throw std::runtime_error("runRScript done but handler not implemented!\nImplement an override for RScriptDoneHandler and usesRScript\nResult was: "+result.toStdString()); } - - bool valueOk(QVariant value, int col = -1, int row = -1); - virtual bool isRCodeColumn(int) const { return false; } - virtual bool areColumnNamesVariables() const { return false; } - - - JASPControl* getRowControl(const QString& key, const QString& name) const override; - bool addRowControl(const QString& key, JASPControl* control) override; - -signals: - void columnCountChanged(); - void rowCountChanged(); - void variableCountChanged(); - void itemChangedSignal(int column, int row, double value); - -public slots: - virtual void initialValuesChanged() {} - -protected slots: - void formulaCheckSucceededSlot(); - -protected: - TableViewBase * _tableView = nullptr; - TableTerms _tableTerms; - - const size_t _maxColumn = 10, - _maxRow = 100; - int _rowSelected = -1; - bool _keepRowsOnReset = true, - _keepColsOnReset = false; - - QMap > _itemControls; -}; - -#endif // LISTMODELTABLEVIEWBASE_H diff --git a/QMLComponents/models/listmodeltermsassigned.cpp b/QMLComponents/models/listmodeltermsassigned.cpp deleted file mode 100644 index 96df7346eef..00000000000 --- a/QMLComponents/models/listmodeltermsassigned.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodeltermsassigned.h" -#include "listmodeltermsavailable.h" -#include "analysisform.h" -#include "controls/rowcontrols.h" -#include "controls/jasplistcontrol.h" -#include - - -using namespace std; - -ListModelTermsAssigned::ListModelTermsAssigned(JASPListControl* listView) - : ListModelAssignedInterface(listView) -{ -} - -void ListModelTermsAssigned::initTerms(const Terms &terms, const RowControlsValues& allValuesMap, bool reInit) -{ - ListModelAssignedInterface::initTerms(terms, allValuesMap, reInit); - - if (availableModel() != nullptr) - { - if (!_copyTermsWhenDropped) - availableModel()->removeTermsInAssignedList(); - } -} - -void ListModelTermsAssigned::availableTermsResetHandler(Terms termsAdded, Terms termsRemoved) -{ - if (termsAdded.size() > 0 && listView()->addAvailableVariablesToAssigned()) - { - beginResetModel(); - _addTerms(termsAdded); - endResetModel(); - - if (!_copyTermsWhenDropped) - availableModel()->removeTermsInAssignedList(); - } - - if (termsRemoved.size() > 0) - { - beginResetModel(); - _removeTerms(termsRemoved); - endResetModel(); - } -} - -Terms ListModelTermsAssigned::canAddTerms(const Terms& terms) const -{ - if (listView()->maxRows() >= 0 && int(terms.size()) > listView()->maxRows()) - return Terms(); - - return ListModelDraggable::canAddTerms(terms); -} - -Terms ListModelTermsAssigned::addTerms(const Terms& termsToAdd, int dropItemIndex, const RowControlsValues& rowValues) -{ - Terms termsToSendBack; - int maxRows = listView()->maxRows(); // maxRows == -1 means no maximum - - if (termsToAdd.size() == 0) - return termsToSendBack; - else if (maxRows > 0 && dropItemIndex >= maxRows) - return termsToAdd; - - Terms newTerms; - - if (dropItemIndex < 0 && maxRows == 1) - dropItemIndex = 0; // for single row, per default replace old item by new one. - - for (const auto& it : rowValues.toStdMap()) - _rowControlsValues[it.first] = it.second; - - if (dropItemIndex == 0 && maxRows == termsToAdd.size()) - { - // If we replace all the items, use beginResetModel - termsToSendBack = terms(); - newTerms = termsToAdd; - - beginResetModel(); - _setTerms(newTerms); - endResetModel(); - } - else - { - // We try to use beginInsertRows/endInsetRows (and beginRemoveRows/endRemoveRows) to set the values instead of beginResetModel: this is indeed the right way to use QAbstractItemModel - // By using beginResetModel/endResetModel all QML objects of the list are removed and rebuild again. This should not be a problem, apart from one special case: - // in a TabView, if the user changes the title of a Tab and clicks direclty the '+' button to add another tab, adding a new tab will be done first, and will add a new - // term to the model: if the model of the TabView is reset, the TextField controls that handle the titles of the Tabs are destroyed and recreated. As the TextField control - // that was used to change the title is destroyed, the signal that changes this title is not received, and the title gets back its old value. - newTerms = terms(); - if (dropItemIndex >= 0 && dropItemIndex < terms().size()) - newTerms.insert(dropItemIndex, termsToAdd); - else - { - dropItemIndex = terms().size(); - newTerms.add(termsToAdd); - } - - beginInsertRows(QModelIndex(), dropItemIndex, dropItemIndex + termsToAdd.size() - 1); - _setTerms(newTerms); - endInsertRows(); - - if (maxRows > 0 && newTerms.size() > maxRows) - { - for (size_t i = maxRows; i < newTerms.size(); i++) - termsToSendBack.add(newTerms.at(i)); - newTerms.remove(maxRows, newTerms.size() - maxRows); - - beginRemoveRows(QModelIndex(), maxRows, maxRows + termsToSendBack.size()); - _setTerms(newTerms); - endRemoveRows(); - } - } - - return termsToSendBack; -} - -void ListModelTermsAssigned::removeTerm(int index) -{ - if (index < 0 || index >= rowCount()) return; - - beginResetModel(); - - const Term& term = terms().at(size_t(index)); - const QString& termQ = term.asQString(); - - RowControls* controls = _rowControlsMap.value(termQ); - if (controls) - { - for (JASPControl* control : controls->getJASPControlsMap().values()) - { - control->setHasError(false); - listView()->form()->clearControlError(control); - } - - _rowControlsMap.remove(termQ); - } - _removeTerm(term); - - endResetModel(); -} - -void ListModelTermsAssigned::changeTerm(int index, const QString& name) -{ - QString oldName = terms()[size_t(index)].asQString(); - if (oldName != name) - { - _rowControlsMap[name] = _rowControlsMap.value(oldName); - _rowControlsValues[name] = _rowControlsValues.value(oldName); - _rowControlsMap.remove(oldName); - _rowControlsValues.remove(oldName); - _replaceTerm(index, Term(name)); - - emit oneTermChanged(oldName, name); - QModelIndex modelIndex = ListModelTermsAssigned::index(index, 0); - emit dataChanged(modelIndex, modelIndex); - } -} - diff --git a/QMLComponents/models/listmodeltermsassigned.h b/QMLComponents/models/listmodeltermsassigned.h deleted file mode 100644 index 80508ea6ecf..00000000000 --- a/QMLComponents/models/listmodeltermsassigned.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELTERMSASSIGNED_H -#define LISTMODELTERMSASSIGNED_H - -#include "listmodelassignedinterface.h" - - -class ListModelTermsAssigned : public ListModelAssignedInterface -{ - Q_OBJECT - -public: - ListModelTermsAssigned(JASPListControl* listView); - - void initTerms(const Terms &terms, const RowControlsValues& allValuesMap = RowControlsValues(), bool reInit = false) override; - Terms canAddTerms(const Terms& terms) const override; - Terms addTerms(const Terms& termsToAdd, int dropItemIndex = -1, const RowControlsValues& rowValues = RowControlsValues()) override; - void removeTerm(int index); - - virtual void changeTerm(int index, const QString& name); - -public slots: - void availableTermsResetHandler(Terms termsToAdd, Terms termsToRemove) override; - -}; - -#endif // LISTMODELTERMSASSIGNED_H diff --git a/QMLComponents/models/listmodeltermsavailable.cpp b/QMLComponents/models/listmodeltermsavailable.cpp deleted file mode 100644 index ef1043ff6b6..00000000000 --- a/QMLComponents/models/listmodeltermsavailable.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "listmodeltermsavailable.h" - -void ListModelTermsAvailable::resetTermsFromSources(bool updateAssigned) -{ - - beginResetModel(); - - Terms termsAvailable = getSourceTerms(); - Terms removedTerms, addedTerms; - - for (const Term& term : _allTerms) - if (!termsAvailable.contains(term)) - removedTerms.add(term); - - for (const Term& term : termsAvailable) - if (!_allTerms.contains(term)) - addedTerms.add(term); - - initTerms(termsAvailable); - - endResetModel(); - - if (updateAssigned) - emit availableTermsReset(addedTerms, removedTerms); -} diff --git a/QMLComponents/models/listmodeltermsavailable.h b/QMLComponents/models/listmodeltermsavailable.h deleted file mode 100644 index 73472543fa7..00000000000 --- a/QMLComponents/models/listmodeltermsavailable.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef LISTMODELTERMSAVAILABLE_H -#define LISTMODELTERMSAVAILABLE_H - -#include "listmodelavailableinterface.h" - -class ListModelTermsAvailable : public ListModelAvailableInterface -{ - Q_OBJECT -public: - ListModelTermsAvailable(JASPListControl* listView) : ListModelAvailableInterface(listView) {} - - void resetTermsFromSources(bool updateAssigned = true) override; -}; - -#endif // LISTMODELTERMSAVAILABLE_H diff --git a/QMLComponents/models/sortmenumodel.cpp b/QMLComponents/models/sortmenumodel.cpp deleted file mode 100644 index a6b17e12201..00000000000 --- a/QMLComponents/models/sortmenumodel.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "sortmenumodel.h" -#include "models/listmodelavailableinterface.h" -#include "jasptheme.h" - -QMap SortMenuModel::_labels; //Only set this constructor because otherwise it might cause a crash on Windows - -SortMenuModel::SortMenuModel(QObject* parent, const QVector &menuEntries) : QAbstractListModel(parent) -{ - if(_labels.size() == 0) - _labels = - { - { Sortable::SortType::None, tr("None") }, - { Sortable::SortType::SortByName, tr("Sort by name") }, - { Sortable::SortType::SortByNameAZ, tr("Sort by name A-Z") }, - { Sortable::SortType::SortByNameZA, tr("Sort by name Z-A") }, - { Sortable::SortType::SortByType, tr("Sort by type") }, - { Sortable::SortType::SortByDate, tr("Sort by date") }, - { Sortable::SortType::SortBySize, tr("Sort by size") } - }; - - - _sortable = dynamic_cast(parent); - if (!_sortable) - { - QString errormsg(tr("SortMenuModel not called with a sortable parent")); - throw new std::runtime_error(errormsg.toStdString().c_str()); - } - - for (const Sortable::SortType& sortType : menuEntries) - _menuEntries.push_back(new SortMenuItem(sortType)); - - _sortable->setSortModel(this); -} - -QVariant SortMenuModel::data(const QModelIndex &index, int role) const -{ - if (index.row() >= rowCount()) - return QVariant(); - - SortMenuItem* entry = _menuEntries.at(index.row()); - - switch(role) - { - case DisplayRole: return _labels[entry->sortType]; - case MenuImageSourceRole: return index.row() == _currentEntry ? JaspTheme::currentIconPath() + "check-mark.png" : ""; - case IsEnabledRole: return true; - default: return QVariant(); - } -} - - -QHash SortMenuModel::roleNames() const -{ - static const auto roles = QHash{ - { DisplayRole, "displayText" }, - { MenuImageSourceRole, "menuImageSource" }, - { IsEnabledRole, "isEnabled" } - }; - - return roles; -} - -void SortMenuModel::clickSortItem(int index) -{ - SortMenuItem* entry = _menuEntries[index]; - _sortable->sortItems(entry->sortType); - - _currentEntry = index; -} - -void SortMenuModel::sortItems() -{ - SortMenuItem* entry = _menuEntries[_currentEntry]; - _sortable->sortItems(entry->sortType); -} - -Sortable::SortType SortMenuModel::currentSortType() -{ - SortMenuItem* entry = _menuEntries[_currentEntry]; - return entry->sortType; -} - -bool SortMenuModel::isAscending() -{ - SortMenuItem* entry = _menuEntries[_currentEntry]; - return entry->ascending; -} - -void SortMenuModel::setCurrentEntry(Sortable::SortType sortType) -{ - int index = 0; - for (const SortMenuItem* menuItem : _menuEntries) - { - if (menuItem->sortType == sortType) - _currentEntry = index; - index++; - } -} diff --git a/QMLComponents/models/sortmenumodel.h b/QMLComponents/models/sortmenumodel.h deleted file mode 100644 index ca55721b1a8..00000000000 --- a/QMLComponents/models/sortmenumodel.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef SORTMENUMODEL_H -#define SORTMENUMODEL_H - -#include -#include "sortable.h" - -class ListModelAvailableInterface; - -class SortMenuModel : public QAbstractListModel -{ - Q_OBJECT - -public: - enum { - DisplayRole, - MenuImageSourceRole, - IsEnabledRole - }; - - SortMenuModel(QObject *parent, const QVector &menuEntries); - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { return _menuEntries.length(); } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - virtual QHash roleNames() const override; - - Q_INVOKABLE void clickSortItem(int index); - void sortItems(); - Sortable::SortType currentSortType(); - bool isAscending(); - void setCurrentEntry(Sortable::SortType sortType); - -private: - static QMap _labels; - - struct SortMenuItem - { - Sortable::SortType sortType; - bool ascending; - - SortMenuItem(Sortable::SortType _sortType, bool _ascending = true) : sortType(_sortType), ascending(_ascending) {} - }; - - QVector _menuEntries; - int _currentEntry = 0; - Sortable* _sortable; -}; - -#endif // SORTMENUMODEL_H diff --git a/QMLComponents/models/term.cpp b/QMLComponents/models/term.cpp deleted file mode 100644 index 2b5601e4ada..00000000000 --- a/QMLComponents/models/term.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "term.h" -#include "qutils.h" -#include - -const char * Term::separator = -#ifdef _WIN32 - " * "; -#else - " \xEF\xB9\xA1 "; -#endif - - -Term::Term(const std::vector components) { initFrom(tq(components)); } -Term::Term(const std::string component) { initFrom(tq(component)); } -Term::Term(const QStringList components) { initFrom(components); } -Term::Term(const QString component) { initFrom(component); } - -void Term::initFrom(const QStringList components) -{ - _asQString = components.join(separator); - _components = components; -} - -void Term::initFrom(const QString component) -{ - _components.append(component); - _asQString = component; -} - -const QStringList &Term::components() const -{ - return _components; -} - -std::vector Term::scomponents() const -{ - return fq(_components); -} - -std::string Term::asString() const -{ - return fq(_asQString); -} - -bool Term::contains(const QString &component) const -{ - for(const QString &termComponent : _components) - if (component == termComponent) - return true; - - return false; -} - -bool Term::containsAll(const Term &term) const -{ - for(const QString &termComponent : term._components) - if ( ! contains(termComponent)) - return false; - - return true; -} - -bool Term::containsAny(const Term &term) const -{ - for(const QString &termComponent : _components) - if (term.contains(termComponent)) - return true; - - return false; -} - -const QString &Term::asQString() const -{ - return _asQString; -} - -Term::iterator Term::begin() -{ - return _components.begin(); -} - -Term::iterator Term::end() -{ - return _components.end(); -} - -const QString &Term::at(int index) const -{ - return _components.at(index); -} - -bool Term::operator==(const Term &other) const -{ - if (this == &other) - return true; - - return (other.size() == size()) && containsAll(other); -} - -bool Term::operator!=(const Term &other) const -{ - return this->operator==(other) == false; -} - -size_t Term::size() const -{ - return _components.size(); -} - -bool Term::replaceVariableName(const std::string & oldName, const std::string & newName) -{ - bool changed = false; - for(int i=0; i<_components.size(); i++) - if(_components[i] == tq(oldName)) - { - _components[i] = tq(newName); - changed = true; - } - - initFrom(_components); - - return changed; -} - -Term Term::readTerm(std::string str) -{ - return readTerm(tq(str)); -} - -Term Term::readTerm(QString str) -{ - return Term(str.split(separator)); -} diff --git a/QMLComponents/models/term.h b/QMLComponents/models/term.h deleted file mode 100644 index 777908f633a..00000000000 --- a/QMLComponents/models/term.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef TERM_H -#define TERM_H - -#include -#include - -#include -#include - -/// -/// A term is a basic element of a VariablesList -/// It is usually just a string, but in case of interactions, it is a vector of strings, a component being one part of an interaction. -/// -class Term -{ -public: - Term(const std::vector components); - Term(const std::string component); - Term(const QStringList components); - Term(const QString component); - - const QStringList & components() const; - const QString & asQString() const; - - std::vector scomponents() const; - std::string asString() const; - - typedef QStringList::const_iterator const_iterator; - typedef QStringList::iterator iterator; - - bool contains( const QString & component) const; - bool containsAll( const Term & term) const; - bool containsAny( const Term & term) const; - - iterator begin(); - iterator end(); - - const QString &at(int i) const; - - bool operator==(const Term &other) const; - bool operator!=(const Term &other) const; - - size_t size() const; - - bool replaceVariableName(const std::string & oldName, const std::string & newName); - - static const char* separator; - static Term readTerm(std::string str); - static Term readTerm(QString str); - -private: - void initFrom(const QStringList components); - void initFrom(const QString component); - - QStringList _components; - QString _asQString; - -}; - -#endif // TERM_H diff --git a/QMLComponents/models/terms.cpp b/QMLComponents/models/terms.cpp deleted file mode 100644 index 362a55f36e2..00000000000 --- a/QMLComponents/models/terms.cpp +++ /dev/null @@ -1,713 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "terms.h" - -#include - -#include -#include -#include -#include "qutils.h" - -using namespace std; - -Terms::Terms(const QList > &terms, Terms *parent) -{ - _parent = parent; - set(terms); -} - -Terms::Terms(const QList &terms, Terms *parent) -{ - _parent = parent; - set(terms); -} - -Terms::Terms(const std::vector > &terms, Terms *parent) -{ - _parent = parent; - set(terms); -} - -Terms::Terms(const std::vector &terms, Terms *parent) -{ - _parent = parent; - set(terms); -} - -Terms::Terms(const QList &terms, Terms *parent) -{ - _parent = parent; - set(terms); -} - -Terms::Terms(Terms *parent) -{ - _parent = parent; -} - -void Terms::set(const std::vector &terms, bool isUnique) -{ - _terms.clear(); - - for(const Term &term : terms) - add(term, isUnique); -} - -void Terms::set(const std::vector &terms, bool isUnique) -{ - _terms.clear(); - - for(const Term &term : terms) - add(term, isUnique); -} - -void Terms::set(const std::vector > &terms, bool isUnique) -{ - _terms.clear(); - - for(const Term &term : terms) - add(term, isUnique); -} - -void Terms::set(const QList &terms, bool isUnique) -{ - _terms.clear(); - - for(const Term &term : terms) - add(term, isUnique); -} - -void Terms::set(const Terms &terms, bool isUnique) -{ - _terms.clear(); - _hasDuplicate = terms.hasDuplicate(); - - for(const Term &term : terms) - add(term, isUnique); -} - -void Terms::set(const QList > &terms, bool isUnique) -{ - _terms.clear(); - - for(const QList &term : terms) - add(Term(term), isUnique); -} - -void Terms::set(const QList &terms, bool isUnique) -{ - _terms.clear(); - - for(const QString &term : terms) - add(Term(term), isUnique); -} - -void Terms::setSortParent(const Terms &parent) -{ - _parent = &parent; -} - -void Terms::removeParent() { - _parent = nullptr; -} - -void Terms::add(const Term &term, bool isUnique) -{ - if (!isUnique || _hasDuplicate) - { - if (!_hasDuplicate && contains(term)) _hasDuplicate = true; - _terms.push_back(term); - } - else if (_parent != nullptr) - { - vector::iterator itr = _terms.begin(); - int result = -1; - - for (; itr != _terms.end(); itr++) - { - result = termCompare(term, *itr); - if (result >= 0) - break; - } - - if (result > 0) - _terms.insert(itr, term); - else if (result < 0) - _terms.push_back(term); - } - else - { - if ( ! contains(term)) - _terms.push_back(term); - } -} - -void Terms::insert(int index, const Term &term) -{ - if (_parent == nullptr) - { - vector::iterator itr = _terms.begin(); - - for (int i = 0; i < index; i++) - itr++; - - _terms.insert(itr, term); - } - else - { - add(term); - } -} - -void Terms::insert(int index, const Terms &terms) -{ - if (_parent == nullptr) - { - vector::iterator itr = _terms.begin(); - - for (int i = 0; i < index; i++) - itr++; - - _terms.insert(itr, terms.begin(), terms.end()); - } - else - { - add(terms); - } -} - -void Terms::add(const Terms &terms) -{ - _hasDuplicate = _hasDuplicate || terms.hasDuplicate(); - - for(const Term & term : terms) - add(term); -} - -const Term& Terms::at(size_t index) const -{ - return _terms.at(index); -} - -bool Terms::contains(const Term &term) const -{ - return std::find(_terms.begin(), _terms.end(), term) != _terms.end(); -} - -bool Terms::contains(const std::string & component) -{ - return contains(tq(component)); -} - -int Terms::indexOf(const QString &component) const -{ - int i = 0; - for(const Term &term : _terms) - { - if (term.contains(component)) - return i; - i++; - } - - return -1; -} - -bool Terms::contains(const QString & component) -{ - for(const Term &term : _terms) - { - if (term.contains(component)) - return true; - } - - return false; -} - -vector Terms::asVector() const -{ - vector items; - - for(const Term &term : _terms) - items.push_back(term.asString()); - - return items; -} - -std::set Terms::asSet() const -{ - std::set items; - - for(const Term &term : _terms) - for(std::string termComp : term.scomponents()) - items.insert(termComp); - - return items; -} - -vector > Terms::asVectorOfVectors() const -{ - vector > items; - - for(const Term &term : _terms) - { - vector components = term.scomponents(); - items.push_back(components); - } - - return items; -} - -QList Terms::asQList() const -{ - QList items; - - for(const Term &term : _terms) - items.append(term.asQString()); - - return items; -} - -QList > Terms::asQListOfQLists() const -{ - QList > items; - - for(const Term &term : _terms) - { - QList components = term.components(); - items.append(components); - } - - return items; -} - -Terms Terms::sortComponents(const Terms &terms) const -{ - QList ts; - - for (const Term &term : terms) - ts.append(sortComponents(term)); - - return Terms(ts); -} - -Terms Terms::crossCombinations() const -{ - if (_terms.size() <= 1) - return Terms(asVector()); - - Terms t; - - for (uint r = 1; r <= _terms.size(); r++) - { - vector v(_terms.size()); - fill(v.begin() + r, v.end(), true); - - do { - - vector combination; - - for (uint i = 0; i < _terms.size(); i++) { - if (!v[i]) - combination.push_back(_terms.at(i).asString()); - } - - t.add(Term(combination)); - - } while (std::next_permutation(v.begin(), v.end())); - } - - return t; -} - -Terms Terms::wayCombinations(int ways) const -{ - Terms t; - - for (int r = ways; r <= ways; r++) - { - vector v(_terms.size()); - std::fill(v.begin() + r, v.end(), true); - - do { - - vector combination; - - for (uint i = 0; i < _terms.size(); ++i) { - if (!v[i]) - combination.push_back(_terms.at(i).asString()); - } - - t.add(Term(combination)); - - } while (std::next_permutation(v.begin(), v.end())); - } - - return t; -} - -Terms Terms::ffCombinations(const Terms &terms) -{ - // full factorial combinations - - Terms combos = terms.crossCombinations(); - - Terms newTerms; - - newTerms.add(*this); - newTerms.add(combos); - - for (uint i = 0; i < _terms.size(); i++) - { - for (uint j = 0; j < combos.size(); j++) - { - QStringList term = _terms.at(i).components(); - QStringList newTerm = combos.at(j).components(); - - term.append(newTerm); - newTerms.add(Term(term)); - } - } - - newTerms.add(terms); - - return newTerms; -} - -Terms Terms::combineTerms(JASPControl::CombinationType type) -{ - Terms combinedTerms; - - size_t nbTerms = size(); - - switch (type) - { - case JASPControl::CombinationType::CombinationCross: - combinedTerms = crossCombinations(); - break; - case JASPControl::CombinationType::CombinationInteraction: - combinedTerms = wayCombinations(nbTerms); - break; - case JASPControl::CombinationType::Combination2Way: - combinedTerms = nbTerms < 2 ? Terms() : wayCombinations(2); - break; - case JASPControl::CombinationType::Combination3Way: - combinedTerms = nbTerms < 3 ? Terms() : wayCombinations(3); - break; - case JASPControl::CombinationType::Combination4Way: - combinedTerms = nbTerms < 4 ? Terms() : wayCombinations(4); - break; - case JASPControl::CombinationType::Combination5Way: - combinedTerms = nbTerms < 5 ? Terms() : wayCombinations(5); - break; - case JASPControl::CombinationType::NoCombination: - default: - combinedTerms = *this; - break; - } - - return combinedTerms; -} - - -string Terms::asString() const -{ - if (_terms.size() == 0) - return ""; - - stringstream ss; - - ss << _terms.at(0).asString(); - - for (size_t i = 1; i < _terms.size(); i++) - ss << ", " << _terms.at(i).asString(); - - return ss.str(); -} - -bool Terms::operator==(const Terms &terms) const -{ - return _terms == terms._terms; -} - -bool Terms::operator!=(const Terms &terms) const -{ - return _terms != terms._terms; -} - -void Terms::set(const QByteArray & array, bool isUnique) -{ - QDataStream stream(array); - - if (stream.atEnd()) - throw exception(); - - int count; - stream >> count; - - clear(); - - while ( ! stream.atEnd()) - { - QStringList variable; - stream >> variable; - add(Term(variable), isUnique); - } -} - -Term Terms::sortComponents(const Term &term) const -{ - QStringList components = term.components(); - std::sort(components.begin(), components.end(), [&](const QString & l, const QString & r)->bool{ return componentLessThan(l,r); }); - return Term(components); -} - -int Terms::rankOf(const QString &component) const -{ - if (_parent == nullptr) - return 0; - - int index = 0; - - for(const Term& compare : _parent->terms()) - { - if (compare.asQString() == component) - break; - index++; - } - - return index; -} - -int Terms::termCompare(const Term &t1, const Term &t2) const -{ - if (_parent == nullptr) - return 1; - - if (t1.size() < t2.size()) - return 1; - if (t1.size() > t2.size()) - return -1; - - for (uint i = 0; i < t1.size(); i++) - { - int t1Rank = rankOf(t1.at(i)); - int t2Rank = rankOf(t2.at(i)); - - if (t1Rank < t2Rank) - return 1; - if (t1Rank > t2Rank) - return -1; - } - - return 0; -} - -bool Terms::termLessThan(const Term &t1, const Term &t2) const -{ - return termCompare(t1, t2) > 0; -} - -bool Terms::componentLessThan(const QString &c1, const QString &c2) const -{ - return rankOf(c1) < rankOf(c2); -} - -void Terms::remove(const Terms &terms) -{ - for(const Term &term : terms) - { - vector::iterator itr = find(_terms.begin(), _terms.end(), term); - if (itr != _terms.end()) - _terms.erase(itr); - } -} - -void Terms::remove(size_t pos, size_t n) -{ - vector::iterator itr = _terms.begin(); - - for (size_t i = 0; i < pos && itr != _terms.end(); i++) - itr++; - - for (; n > 0 && itr != _terms.end(); n--) - _terms.erase(itr); -} - -void Terms::replace(int pos, const Term &term) -{ - size_t pos_t = size_t(pos); - if (pos_t <_terms.size()) - { - remove(pos_t); - insert(pos, term); - } -} - -bool Terms::discardWhatDoesntContainTheseComponents(const Terms &terms) -{ - bool changed = false; - - _terms.erase( - std::remove_if( - _terms.begin(), - _terms.end(), - [&](Term& existingTerm) - { - for (const string &str : existingTerm.scomponents()) - if (! terms.contains(str)) - { - changed = true; - return true; - } - - return false; - } - ), - _terms.end() - ); - - return changed; -} - -bool Terms::discardWhatDoesContainTheseComponents(const Terms &terms) -{ - bool changed = false; - - _terms.erase( - std::remove_if( - _terms.begin(), - _terms.end(), - [&](Term& existingTerm) - { - for (const Term &term : terms) - for (const QString &component : term.components()) - if (existingTerm.contains(component)) - { - changed = true; - return true; - } - - - return false; - }), - _terms.end() - ); - - return changed; -} - -bool Terms::discardWhatDoesContainTheseTerms(const Terms &terms) -{ - bool changed = false; - - _terms.erase( - std::remove_if( - _terms.begin(), - _terms.end(), - [&](const Term& existingTerm) - { - for (const Term &term : terms) - if (existingTerm.containsAll(term)) - { - changed = true; - return true; - } - - return false; - }), - _terms.end() - ); - - return changed; -} - -bool Terms::discardWhatIsntTheseTerms(const Terms &terms, Terms *discarded) -{ - bool changed = false; - - _terms.erase( - std::remove_if( - _terms.begin(), - _terms.end(), - [&](Term& term) - { - if (!term.asString().empty() && !terms.contains(term)) - { - if (discarded != nullptr) - discarded->add(term); - - changed = true; - return true; - } - - return false; - }), - _terms.end() - ); - - return changed; -} - -void Terms::clear() -{ - _terms.clear(); -} - -size_t Terms::size() const -{ - return _terms.size(); -} - -const std::vector &Terms::terms() const -{ - return _terms; -} - -Terms::const_iterator Terms::begin() const -{ - return _terms.begin(); -} - -Terms::const_iterator Terms::end() const -{ - return _terms.end(); -} - -void Terms::remove(const Term &term) -{ - vector::iterator itr = std::find(_terms.begin(), _terms.end(), term); - if (itr != end()) - _terms.erase(itr); -} - -QSet Terms::replaceVariableName(const std::string & oldName, const std::string & newName) -{ - QSet change; - - int i = 0; - for(Term & t : _terms) - { - if (t.replaceVariableName(oldName, newName)) - change.insert(i); - i++; - } - - return change; -} diff --git a/QMLComponents/models/terms.h b/QMLComponents/models/terms.h deleted file mode 100644 index 78618641c28..00000000000 --- a/QMLComponents/models/terms.h +++ /dev/null @@ -1,131 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef TERMS_H -#define TERMS_H - -#include -#include -#include - -#include -#include -#include - -#include "term.h" -#include "controls/jaspcontrol.h" - -/// -/// Terms is a list of Term. They are used in VariablesList -/// Some extra functionalities are added to deal with terms with interactions, in order for example to remove all terms that contain some component -/// (a component is most of the time a Variable name, but it can be a factor of level name). -/// Terms may have a parent Terms. This is used mainly in the available Variables List: this list has some variables that can be assigned to another (assigned) list. -/// The variable is then removed from the Available list and added to the assigned list. But if this variable is set back to the available list, it should get the same -/// order as before being set to the assigned list. For this we keep the original terms, and set it as parent of the 'functional' terms of the available list. When a variable -/// is set back to the available list, we can know with the parent terms where it was before being moved. -/// -class Terms -{ -public: - Terms(const QList > & terms, Terms *parent = nullptr); - Terms(const QList & terms, Terms *parent = nullptr); - Terms(const std::vector > & terms, Terms *parent = nullptr); - Terms(const std::vector & terms, Terms *parent = nullptr); - Terms(const QList & terms, Terms *parent = nullptr); - Terms( Terms *parent = nullptr); - - void set(const QList > & terms, bool isUnique = true); - void set(const QList & terms, bool isUnique = true); - void set(const std::vector & terms, bool isUnique = true); - void set(const std::vector & terms, bool isUnique = true); - void set(const std::vector > & terms, bool isUnique = true); - void set(const QList & terms, bool isUnique = true); - void set(const Terms & terms, bool isUnique = true); - void set(const QByteArray & array, bool isUnique = true); - - void removeParent(); - void setSortParent(const Terms &parent); - - void add(const Term &term, bool isUnique = true); - void add(const Terms &terms); - - void insert(int index, const Term &term); - void insert(int index, const Terms &terms); - - size_t size() const; - const std::vector &terms() const; - - typedef std::vector::const_iterator const_iterator; - typedef std::vector::iterator iterator; - - const_iterator begin() const; - const_iterator end() const; - - void remove(const Term &term); - void remove(const Terms &terms); - void remove(size_t pos, size_t n = 1); - void replace(int pos, const Term& term); - bool discardWhatDoesntContainTheseComponents( const Terms &terms); - bool discardWhatDoesContainTheseComponents( const Terms &terms); - bool discardWhatDoesContainTheseTerms( const Terms &terms); - bool discardWhatIsntTheseTerms( const Terms &terms, Terms *discarded = nullptr); - - QSet replaceVariableName(const std::string & oldName, const std::string & newName); - - void clear(); - - const Term &at(size_t index) const; - bool contains(const Term & term) const; - bool contains(const QString & component); - bool contains(const std::string & component); - int indexOf(const QString & component) const; - - std::vector asVector() const; - std::set asSet() const; - std::vector > asVectorOfVectors() const; - QList asQList() const; - QList > asQListOfQLists() const; - - Term sortComponents(const Term &term) const; - Terms sortComponents(const Terms &terms) const; - - Terms crossCombinations() const; - Terms wayCombinations(int ways) const; - Terms ffCombinations(const Terms &terms); - Terms combineTerms(JASPControl::CombinationType type); - - std::string asString() const; - bool hasDuplicate() const { return _hasDuplicate; } - - bool operator==(const Terms &terms) const; - bool operator!=(const Terms &terms) const; - const Term& operator[](size_t index) const { return at(index); } - -private: - - int rankOf(const QString &component) const; - int termCompare(const Term& t1, const Term& t2) const; - bool termLessThan(const Term &t1, const Term &t2) const; - bool componentLessThan(const QString &c1, const QString &c2) const; - - const Terms * _parent; - std::vector _terms; - bool _hasDuplicate = false; -}; - -#endif // TERMS_H diff --git a/QMLComponents/preferencesmodelbase.cpp b/QMLComponents/preferencesmodelbase.cpp deleted file mode 100644 index dc98a13c10a..00000000000 --- a/QMLComponents/preferencesmodelbase.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "preferencesmodelbase.h" -#include "jasptheme.h" - -PreferencesModelBase* PreferencesModelBase::_singleton = nullptr; - -PreferencesModelBase::PreferencesModelBase(QObject *parent) - : QObject{parent} -{ - assert(!_singleton); - _singleton = this; -} - -PreferencesModelBase *PreferencesModelBase::preferences() -{ - if (_singleton == nullptr) - _singleton = new PreferencesModelBase(); - - return _singleton; -} - -void PreferencesModelBase::currentThemeNameHandler() -{ - setCurrentThemeName(JaspTheme::currentTheme()->themeName()); -} diff --git a/QMLComponents/preferencesmodelbase.h b/QMLComponents/preferencesmodelbase.h deleted file mode 100644 index 26428d3ffe0..00000000000 --- a/QMLComponents/preferencesmodelbase.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef PREFERENCESMODELBASE_H -#define PREFERENCESMODELBASE_H - -#include - -class PreferencesModelBase : public QObject -{ - Q_OBJECT -public: - explicit PreferencesModelBase(QObject *parent = nullptr); - ~PreferencesModelBase() { _singleton = nullptr; } - - virtual double uiScale() { return 1; } - virtual int maxFlickVelocity() const { return 808; } - virtual bool showRSyntax() const { return false; } - virtual bool showAllROptions() const { return false; } - - static PreferencesModelBase* preferences(); - -public slots: - void currentThemeNameHandler(); - virtual void setCurrentThemeName(QString currentThemeName) {} - virtual void setShowRSyntax(bool showRSyntax) {} - virtual void setShowAllROptions(bool showAllROptions) {} - -signals: - void uiScaleChanged(); - void maxFlickVelocityChanged(); - void currentJaspThemeChanged(); - void currentThemeReady(); - void interfaceFontChanged(); - void showRSyntaxChanged(); - void showAllROptionsChanged(); - -protected: - static PreferencesModelBase* _singleton; - -}; - -#endif // PREFERENCESMODELBASE_H diff --git a/QMLComponents/rsyntax/formulabase.cpp b/QMLComponents/rsyntax/formulabase.cpp deleted file mode 100644 index d37edeebeed..00000000000 --- a/QMLComponents/rsyntax/formulabase.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "formulabase.h" -#include "formulasource.h" -#include "rsyntax.h" -#include "controls/sourceitem.h" -#include "analysisform.h" -#include "log.h" -#include "formulaparser.h" - -FormulaBase::FormulaBase(QQuickItem *parent) : QQuickItem(parent) -{ - setVisible(false); -} - -void FormulaBase::setUp() -{ - _leftFormulaSources = FormulaSource::makeFormulaSources(this, _lhs); - _rightFormulaSources = FormulaSource::makeFormulaSources(this, _rhs); - - connect(this, &FormulaBase::lhsChanged, this, [this]() { _leftFormulaSources = FormulaSource::makeFormulaSources(this, _lhs); emit somethingChanged();} ); - connect(this, &FormulaBase::rhsChanged, this, [this]() { _rightFormulaSources = FormulaSource::makeFormulaSources(this, _rhs); emit somethingChanged();} ); -} - -// Generate the R Formula -QString FormulaBase::toString(const QString& newLine, const QString& indent, bool &isNull) const -{ - if (!_rSyntax) - return ""; - - QString result = indent + _name + " = "; - bool isEmpty = true; - - for (FormulaSource* formulaSource : _rightFormulaSources) - if (isEmpty) isEmpty = formulaSource->isEmpty(); - - if (isEmpty) - { - isNull = true; - result += "NULL"; - return result; - } - - isNull = false; - - auto addFormulaTerms = [] (const QVector& formulaSources, bool isLhs) -> QString - { - QString result; - - bool first = true; - for (FormulaSource* formulaSource: formulaSources) - { - if (formulaSource->isEmpty()) continue; - - QString terms = formulaSource->toString(); - if (terms.isEmpty()) continue; - - if (!first) result += " + "; - first = false; - - result += terms; - } - - if (isLhs && result.contains(" +")) result = "cbind(" + result.replace(" +", ",") + ")"; - return result; - }; - - result += addFormulaTerms(_leftFormulaSources, true) + " ~ " + addFormulaTerms(_rightFormulaSources, false); - - // In case of a formula uses a VarialesList which has also extra controls for each variable (typically the isNuisance checkbox in Bayesian ANOVA), - // then this information cannot be added in the formula. For this we need to add extra option with the values of these extra controls. - for (FormulaSource* formulaSource : _leftFormulaSources + _rightFormulaSources) - { - QMap extraOptions = formulaSource->additionalOptionStrings(); - for (const QString& key : extraOptions.keys()) - { - if (!result.isEmpty()) - result += "," + newLine; - - result += indent + _rSyntax->getRSyntaxFromControlName(key) + " = " + extraOptions[key]; - } - } - - // When terms come from different sources. only one can be unspecified, for the other one the user must specify in the script - // which terms are in these sources. - for (const QString& optionToSpecify : _getSourceList(_userMustSpecify)) - { - ListModel* model = getModel(optionToSpecify); - if (!model) - continue; - - QStringList elements = model->terms().asQList(); - - if (elements.isEmpty()) - continue; - - if (!result.isEmpty()) - result += "," + newLine; - - result += indent + _rSyntax->getRSyntaxFromControlName(optionToSpecify) + " = "; - - if (elements.length() == 0) result += "\"\""; - else if (elements.length() == 1) result += "\"" + elements[0] + "\""; - else - { - result += "list("; - bool first = true; - for (const QString& element : elements) - { - if (!first) - result += ", "; - - first = false; - result += "\"" + element + "\""; - } - result += ")"; - } - } - - return result; -} - -bool FormulaBase::parseRSyntaxOptions(Json::Value &options) const -{ - const Json::Value& formulaJson = options[fq(_name)]; - - Log::log() << "Formula: " << formulaJson.toStyledString() << std::endl; - if (formulaJson.empty()) return true; - - if (!formulaJson.isObject()) - { - Log::log() << "Formula option is not an object!" << std::endl; - return false; - } - - const Json::Value lhs = formulaJson["lhs"], - rhs = formulaJson["rhs"]; - - FormulaParser::ParsedTerms leftParsedTerms, rightParsedTerms; - QString error; - - if (!FormulaParser::parse(lhs, true, leftParsedTerms, error) || !FormulaParser::parse(rhs, false, rightParsedTerms, error)) - { - _rSyntax->addError(error); - return false; - } - - return _parseFormulaSources(_leftFormulaSources, leftParsedTerms, options) && _parseFormulaSources(_rightFormulaSources, rightParsedTerms, options); -} - -AnalysisForm *FormulaBase::form() const -{ - return _rSyntax ? _rSyntax->form() : nullptr; -} - -QStringList FormulaBase::modelSources() const -{ - QStringList result = sourcesThatMustBeSpecified(); - - for (FormulaSource* formulaSource : _leftFormulaSources + _rightFormulaSources) - result += formulaSource->modelSources(); - - return result; -} - -QStringList FormulaBase::sourcesThatMustBeSpecified() const -{ - return _getSourceList(_userMustSpecify); -} - -QStringList FormulaBase::extraOptions(bool useOptionName, bool onlyFormula) const -{ - QStringList result; - - for (FormulaSource* formulaSource : _leftFormulaSources + _rightFormulaSources) - result += formulaSource->extraOptions(useOptionName, onlyFormula); - - return result; -} - -QStringList FormulaBase::_getSourceList(const QVariant &var) const -{ - QStringList result; - for (const QVariant& modelSpec : SourceItem::getListVariant(var)) - { - if (modelSpec.canConvert()) - { - QString sourceName = modelSpec.toString(); - if (!sourceName.isEmpty()) - result.push_back(sourceName); - } - else if (modelSpec.canConvert >()) - { - QMap map = modelSpec.toMap(); - if (map.contains("name")) - { - QString sourceName = map["name"].toString(); - if (!sourceName.isEmpty()) - result.push_back(sourceName); - } - } - } - return result; -} - - -bool FormulaBase::_parseFormulaSources(const QVector& formulaSources, FormulaParser::ParsedTerms& parsedTerms, Json::Value& options) const -{ - if (parsedTerms.fixedTerms.terms().empty()) - return true; - - for (const FormulaSource* formulaSource : formulaSources) - parsedTerms = formulaSource->fillOptionsWithParsedTerms(parsedTerms, options); - - if (!parsedTerms.fixedTerms.terms().empty() && !_rSyntax->hasError()) - _rSyntax->addError(tr("Could not find term %1 in Formula").arg(parsedTerms.fixedTerms.terms()[0].asQString())); - - return !_rSyntax->hasError(); -} - -ListModel *FormulaBase::getModel(const QString &name) const -{ - AnalysisForm * aform = form(); - ListModel * model = nullptr; - JASPListControl * listControl = nullptr; - - if (!aform) - return model; - - JASPControl* control = aform->getControl(name); - if (!control) - aform->addFormError(tr("Source %1 in Formula not found").arg(name)); - else - { - listControl = qobject_cast(control); - if (!listControl) aform->addFormError(tr("Source %1 in Formula is not a Variables List").arg(name)); - else model = listControl->model(); - } - - return model; -} - -void FormulaBase::componentComplete() -{ - AnalysisForm* form = qobject_cast(parent()); - - if (form) - _rSyntax = form->rSyntax(); - - if (_rSyntax) - _rSyntax->addFormula(this); -} diff --git a/QMLComponents/rsyntax/formulabase.h b/QMLComponents/rsyntax/formulabase.h deleted file mode 100644 index 925782074ce..00000000000 --- a/QMLComponents/rsyntax/formulabase.h +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef FORMULABASE_H -#define FORMULABASE_H - -#include -#include "qutils.h" -#include "formulaparser.h" - -class FormulaSource; -class RSyntax; -class AnalysisForm; -class ListModel; - -class FormulaBase : public QQuickItem -{ - Q_OBJECT - - Q_PROPERTY( QVariant userMustSpecify READ userMustSpecify WRITE setUserMustSpecify NOTIFY userMustSpecifyChanged ) - Q_PROPERTY( QVariant lhs READ lhs WRITE setLhs NOTIFY lhsChanged ) - Q_PROPERTY( QVariant rhs READ rhs WRITE setRhs NOTIFY rhsChanged ) - Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged ) - -public: - FormulaBase(QQuickItem *parent = nullptr); - - void setUp(); - QVariant userMustSpecify() const { return _userMustSpecify; } - QVariant lhs() const { return _lhs; } - QVariant rhs() const { return _rhs; } - QString name() const { return _name; } - - QString toString(const QString& newLine, const QString& indent, bool &isNull) const; - bool parseRSyntaxOptions(Json::Value &options) const; - RSyntax* rSyntax() const { return _rSyntax; } - AnalysisForm * form() const; - QStringList modelSources() const; - QStringList sourcesThatMustBeSpecified() const; - QStringList extraOptions(bool useOptionName = true, bool onlyFormula = false) const; - - ListModel* getModel(const QString& name) const; - -signals: - void userMustSpecifyChanged(); - void lhsChanged(); - void rhsChanged(); - void somethingChanged(); - void nameChanged(); - -public slots: - GENERIC_SET_FUNCTION(UserMustSpecify , _userMustSpecify , userMustSpecifyChanged , QVariant ) - GENERIC_SET_FUNCTION(Lhs , _lhs , lhsChanged , QVariant ) - GENERIC_SET_FUNCTION(Rhs , _rhs , rhsChanged , QVariant ) - GENERIC_SET_FUNCTION(Name , _name , nameChanged , QString ) - -protected: - void componentComplete() override; - -private: - QStringList _getSourceList(const QVariant& var) const; - bool _parseFormulaSources(const QVector& formulaSources, FormulaParser::ParsedTerms& formula, Json::Value& options) const; - - RSyntax* _rSyntax = nullptr; - QVariant _userMustSpecify, - _lhs, - _rhs; - QString _name = "formula"; - QVector _leftFormulaSources, - _rightFormulaSources; -}; - -#endif // FORMULABASE_H diff --git a/QMLComponents/rsyntax/formulaparser.cpp b/QMLComponents/rsyntax/formulaparser.cpp deleted file mode 100644 index 8a56bbbdb6f..00000000000 --- a/QMLComponents/rsyntax/formulaparser.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "formulaparser.h" -#include -#include "log.h" - -const char FormulaParser::interactionSeparator = ':'; -const char FormulaParser::allInterationsSeparator = '*'; - -Terms FormulaParser::parseTerm(QString term) -{ - auto trim = [] (const QString& input) -> QString - { - QString output = input.trimmed(); - if (output.startsWith('`')) output = output.mid(1); - if (output.endsWith('`')) output = output.chopped(1); - - return output; - }; - - auto trimList = [=] (const QString& input, const char& separator) -> QStringList - { - QStringList output; - if (input.contains(separator)) - { - QStringList components = input.split(separator); - for (const QString& component : components) - output.append(trim(component)); - } - else - output.append(trim(input)); - - return output; - }; - - Terms result; - if (term.contains(FormulaParser::interactionSeparator)) - { - term.replace(FormulaParser::interactionSeparator, Term::separator); - result.add(Term::readTerm(term)); - } - else if (term.contains(FormulaParser::allInterationsSeparator)) - { - Terms baseTerms = trimList(term, FormulaParser::allInterationsSeparator); - result = baseTerms.crossCombinations(); - } - else - result.add(term); - - return result; -} - -Terms FormulaParser::parseTerm(const Json::Value& jsonString) -{ - if (jsonString.isString()) - return parseTerm(tq(jsonString.asString())); - else - { - Log::log() << "Wrong kind of object for the vars in formula" << jsonString.toStyledString() << std::endl; - return Terms(); - } -} - -Terms FormulaParser::parseTerms(const Json::Value& json) -{ - Terms result; - if (json.isNull()) return result; - - if (json.isString()) - result.add(parseTerm(json)); - else if (json.isArray()) - { - for (const Json::Value& col : json) - result.add(parseTerm(col)); - } - else - { - Log::log() << "Wrong kind of terms in json during parseTerms: " << json.toStyledString() << std::endl; - return result; - } - - return result; -} - -bool FormulaParser::parse(const Json::Value& formula, bool isLhs, ParsedTerms& parsedTerms, QString& error) -{ - error.clear(); - - if (formula.isNull()) return true; - - if (!formula.isObject()) - { - error.append("Wrong type of formula object"); - return false; - } - - const Json::Value& fixedTerms = isLhs ? formula : formula["fixed"]; - - if (!fixedTerms.isNull()) - { - if (!fixedTerms.isObject()) - { - error.append("Wrong type of fixed terms"); - return false; - } - - parsedTerms.intercept = fixedTerms["intercept"].asBool(); - parsedTerms.fixedTerms = parseTerms(fixedTerms["vars"]); - } - - if (!isLhs) - { - const Json::Value& randomTerms = formula["random"]; - if (!randomTerms.isNull()) - { - if (!randomTerms.isObject()) - { - error.append("Wrong type of random terms object"); - return false; - } - for (const std::string& col : randomTerms.getMemberNames()) - { - const Json::Value& randomValues = randomTerms[col]; - RandomTerm randomTerm; - randomTerm.terms = parseTerms(randomValues["vars"]); - randomTerm.correlated = randomValues["correlated"].asBool(); - randomTerm.intercept = randomValues["intercept"].asBool(); - parsedTerms.randomTerms[tq(col)] = randomTerm; - } - } - } - - return true; -} - -QString FormulaParser::transformToFormulaTerm(const Term &term, char join, bool addQuotes) -{ - static QRegularExpression rx("^[a-zA-Z0-9_]+$"); - QString result; - const QStringList& components = term.components(); - - bool first = true; - for (const QString& component : components) - { - if (!first) - result += QString(' ') + join + ' '; - - first = false; - - if (addQuotes) result += '"' + component + '"'; - else if (component.contains(rx)) result += component; - else result += '`' + component + '`'; - } - return result; -} - diff --git a/QMLComponents/rsyntax/formulaparser.h b/QMLComponents/rsyntax/formulaparser.h deleted file mode 100644 index 90a3b262dbd..00000000000 --- a/QMLComponents/rsyntax/formulaparser.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef FORMULAPARSER_H -#define FORMULAPARSER_H - -#include -#include "models/terms.h" - -class FormulaParser -{ - Q_DECLARE_TR_FUNCTIONS(FormulaParser) -public: - struct RandomTerm - { - Terms terms; - bool intercept = true, - correlated = true; - - RandomTerm() {} - - }; - struct ParsedTerms - { - Terms fixedTerms; - bool intercept = true; - QMap randomTerms; - - ParsedTerms() {} - }; - - static const char interactionSeparator; - static const char allInterationsSeparator; - - static bool parse(const Json::Value& formula, bool isLhs, ParsedTerms& parsedTerms, QString& error); - static Terms parseTerm(QString term); - static Terms parseTerm(const Json::Value& jsonString); - static Terms parseTerms(const Json::Value& json); -// static ParsedTerm parseTerm(const QString& term, const ParsedTerms& conditionalParsedTerms, bool isCorrelated); -// static ParsedTerm parseTerm(const ParsedTerm& term, const ParsedTerms& conditionalParsedTerms, bool isCorrelated); - - static QString transformToFormulaTerm(const Term& term, char join = FormulaParser::allInterationsSeparator, bool withCrossCombinations = false); - -private: - static ParsedTerms squeezeConditionalTerms(const ParsedTerms& terms); -}; - -#endif // FORMULAPARSER_H diff --git a/QMLComponents/rsyntax/formulasource.cpp b/QMLComponents/rsyntax/formulasource.cpp deleted file mode 100644 index f29c7815d7d..00000000000 --- a/QMLComponents/rsyntax/formulasource.cpp +++ /dev/null @@ -1,702 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "formulasource.h" -#include "formulabase.h" -#include "analysisform.h" -#include "controls/jasplistcontrol.h" -#include "controls/sourceitem.h" -#include "models/listmodelassignedinterface.h" -#include "models/listmodelinteractionassigned.h" -#include "controls/rowcontrols.h" -#include "log.h" -#include "rsyntax.h" -#include "boundcontrols/boundcontrolterms.h" -#include "controls/componentslistbase.h" -#include "controls/variableslistbase.h" - -FormulaSource::ExtraOption::ExtraOption(const QString& controlName, const QVariant &var) -{ - if (var.canConvert >()) - { - QMap map = var.toMap(); - if (map.contains("optionName")) optionName = map["optionName"].toString(); - else optionName = controlName; - - if (map.contains("useFormula")) useFormula = map["useFormula"].toBool(); - } - else - optionName = controlName; -} - -FormulaSource::RandomEffects::RandomEffects(const QVariant &var) -{ - QMap map; - JASPControl* sourceControl = var.value(); - if (sourceControl) - name = sourceControl->name(); - else if (var.canConvert()) - name = var.toString(); - else if (var.canConvert >()) - { - map = var.toMap(); - if (map.contains("id")) - { - sourceControl = map["id"].value(); - if (sourceControl) name = sourceControl->name(); - } - - if (map.contains("variablesSource")) fixedEffectsSource = map["variablesSource"].toString(); - if (map.contains("variablesControl")) variablesControl = map["variablesControl"].toString(); - if (map.contains("checkControl")) checkControl = map["checkControl"].toString(); - if (map.contains("correlationControl")) correlationControl = map["correlationControl"].toString(); - if (map.contains("variablesKey")) variablesKey = map["variablesKey"].toString(); - } -} - -FormulaSource::FormulaSource(FormulaBase* formula, const QVariant& var) : QObject(formula), _formula(formula) -{ - QMap map; - JASPControl* sourceControl = var.value(); - - if (sourceControl) - _sourceName = sourceControl->name(); - - else if (var.canConvert()) - _sourceName = var.toString(); - - else if (var.canConvert >()) - { - map = var.toMap(); - if (map.contains("id")) - { - sourceControl = map["id"].value(); - if (sourceControl) _sourceName = sourceControl->name(); - } - else if (map.contains("randomEffects")) - { - _randomEffects = RandomEffects(map["randomEffects"]); - _sourceName = _randomEffects.name; - } - else - _sourceName = map["name"].toString(); - } - - if (_sourceName.isEmpty()) - _addError(tr("No name given in Formula description")); - else - { - _model = _formula->getModel(_sourceName); - if (!_model) - _addError(tr("Cannot find item %1 given in Formula description").arg(_sourceName)); - } - - if (!_model) map.clear(); - - if (map.contains("extraOptions")) - { - QList allExtraOptions = SourceItem::getListVariant(map["extraOptions"]); - for (const QVariant& extraOptionVar : allExtraOptions) - { - QString controlName, optionName; - if (extraOptionVar.canConvert()) - optionName = controlName = extraOptionVar.toString(); - else if (extraOptionVar.canConvert >()) - { - QMap extraOptionMap = extraOptionVar.toMap(); - optionName = controlName = extraOptionMap["name"].toString(); - if (extraOptionMap.contains("controlName")) controlName = extraOptionMap["controlName"].toString(); - } - if (!optionName.isEmpty()) - _extraOptions[controlName] = ExtraOption(optionName, extraOptionVar); - } - } - - if (!_randomEffects.isEmpty()) - { - _randomEffects.fixedEffectsModel = _formula->form()->getModel(_randomEffects.fixedEffectsSource); - if (!_randomEffects.fixedEffectsModel) - { - _randomEffects = RandomEffects(); - _addError(tr("No source found in Formula randomEffects")); - } - _randomEffects.componentsList = qobject_cast(_model->listView()); - if (!_randomEffects.componentsList) - { - _addError(tr("randomEffects in Formula can be used only with a ComponentsList item")); - _randomEffects = RandomEffects(); - } - } -} - -QVector FormulaSource::makeFormulaSources(FormulaBase* formula, const QVariant& var) -{ - QVector result; - QList allFormulaSources = SourceItem::getListVariant(var); - - for (const QVariant& formulaSourceVar : allFormulaSources) - if (!formulaSourceVar.isNull()) - { - FormulaSource* formulaSource = new FormulaSource(formula, formulaSourceVar); - // formulaSource with randomEffetcs is set last in the list, in order to be treated after the fixed effects - if (formulaSource->hasRandomEffects()) result.push_back(formulaSource); - else result.push_front(formulaSource); - } - - return result; -} - -QStringList FormulaSource::modelSources() const -{ - QStringList result; - if (_model == nullptr) return result; - - auto findSources = [] (ListModel* model, QStringList &sources) - { - sources.append(model->name()); - const QVector& sourceItems = model->listView()->sourceItems(); - for (SourceItem* sourceItem : sourceItems) - { - ListModel* listModel = sourceItem->sourceListModel(); - if (listModel) sources.append(listModel->name()); - } - }; - - auto findSourcesWithAvailable = [=] (ListModel* model, QStringList &sources) - { - findSources(model, sources); - ListModelAssignedInterface* assignedModel = qobject_cast(model); - if (assignedModel) - { - ListModelAvailableInterface* availableModel = assignedModel->availableModel(); - if (availableModel) findSources(availableModel, sources); - } - - }; - - findSourcesWithAvailable(_model, result); - - if (_randomEffects.fixedEffectsModel) - findSourcesWithAvailable(_randomEffects.fixedEffectsModel, result); - - return result; -} - -QString FormulaSource::toString() const -{ - if (!_model) return tr("No source found in Formula"); - - const Terms& terms = _model->terms(); - - if (hasRandomEffects()) return _generateRandomEffectsTerms(terms); - if (_model->listView()->containsInteractions()) return generateInteractionTerms(terms); - else return _generateSimpleTerms(terms); -} - - -QString FormulaSource::_generateRandomEffectsTerms(const Terms& terms) const -{ - QString result; - - QMap allRowControls = _model->getAllRowControls(); - for (const Term& term : terms) - { - QString key = term.asQString(); - if (!allRowControls.contains(key)) - { - Log::log() << "Cannot find key " << key << " in rowControls for RandomEffetcs Source" << std::endl; - continue; - } - RowControls* rowControls = allRowControls[key]; - JASPControl* correlationControl = rowControls && !_randomEffects.correlationControl.isEmpty() ? rowControls->getJASPControl(_randomEffects.correlationControl) : nullptr; - JASPListControl* variablesListControl = qobject_cast(rowControls && !_randomEffects.variablesControl.isEmpty() ? rowControls->getJASPControl(_randomEffects.variablesControl) : nullptr); - - if (!variablesListControl) - { - Log::log() << "Cannot find component list " << _randomEffects.variablesControl << " in RandomEffetcs terms!" << std::endl; - continue; - } - ListModel* componentListModel = variablesListControl->model(); - bool hasCorrelation = correlationControl ? correlationControl->property("checked").toBool() : false; - - Terms filteredTerms = _randomEffects.checkControl.isEmpty() ? componentListModel->terms() : SourceItem::filterTermsWithCondition(componentListModel, componentListModel->terms(), _randomEffects.checkControl); - bool hasIntercept = _checkIntercept(filteredTerms); - - if (filteredTerms.size() > 0 || hasIntercept) - { - if (!result.isEmpty()) result += " + " ; - - result += "("; - result += (hasIntercept ? "1" : "0"); - - if (filteredTerms.size() > 0) - result += " + " + generateInteractionTerms(filteredTerms); - - result += (hasCorrelation ? " | " : " || "); - result += key; - result += ")"; - } - } - - return result; -} - -QString FormulaSource::generateInteractionTerms(const Terms& tterms) -{ - // If the terms has interactions, try to use the '*' symbol when all combinations of the subterms are also present in the terms. - QString result; - bool first = true; - std::vector terms = tterms.terms(); - std::sort(terms.begin(), terms.end(), [](const Term& a, const Term& b){ return a.components().length() < b.components().length(); }); - std::vector orgTerms = terms; - - while (!terms.empty()) - { - if (!first) result += " + "; - first = false; - const Term& term = terms.at(terms.size() - 1); - terms.pop_back(); - if (term.components().size() == 1) result += FormulaParser::transformToFormulaTerm(term); - else - { - bool allComponentsAreAlsoInTerms = true; - Terms allCrossedTerms = Terms(term.components()).crossCombinations(); - allCrossedTerms.remove(term); - for (const Term& oneTerm : allCrossedTerms) - { - if (std::find(orgTerms.begin(), orgTerms.end(), oneTerm) == orgTerms.end()) - { - allComponentsAreAlsoInTerms = false; - break; - } - } - - if (allComponentsAreAlsoInTerms) - { - // Remove the components and their combinations in terms so that they don't appear in the formula - for (const Term& oneTerm : allCrossedTerms) - { - auto found = std::find(terms.begin(), terms.end(), oneTerm); - if (found != terms.end()) terms.erase(found); - } - - result += FormulaParser::transformToFormulaTerm(term, FormulaParser::allInterationsSeparator); - } - else - result += FormulaParser::transformToFormulaTerm(term, FormulaParser::interactionSeparator); - } - } - - return result; -} - - -QString FormulaSource::_generateSimpleTerms(const Terms &terms) const -{ - QString result; - bool first = true; - - for (const Term& term : terms) - { - if (!first) result += " + "; - first = false; - result += FormulaParser::transformToFormulaTerm(term, FormulaParser::interactionSeparator); - } - - return result; -} - -Terms FormulaSource::_onlyTrueTerms(const QString& controlName, const Terms &terms) const -{ - Terms result; - if (!_model) return result; - - for (const Term& term : terms) - { - JASPControl* control = _model->getRowControl(term.asQString(), controlName); - BoundControl* boundControl = control ? control->boundControl() : nullptr; - if (boundControl && boundControl->boundValue().asBool()) - result.add(term); - } - - return result; -} - -ListModel::RowControlsValues FormulaSource::_getTermsFromExtraOptions(const Json::Value& options) const -{ - QMap > extraTermsMap; - for (const QString& extraControlName : _extraOptions.keys()) - { - const Json::Value& extraOptionJson = options[fq(_extraOptions[extraControlName].optionName)]; - if (extraOptionJson.isObject()) - { - FormulaParser::ParsedTerms parsedTerms; - QString error; - - if (FormulaParser::parse(extraOptionJson["rhs"], false, parsedTerms, error)) - { - for (const Term& parsedTerm : parsedTerms.fixedTerms) - extraTermsMap[parsedTerm.asQString()][extraControlName] = true; - } - } - else if (extraOptionJson.isString()) - { - extraTermsMap[tq(extraOptionJson.asString())][extraControlName] = true; - } - else if (extraOptionJson.isArray()) - { - for (const Json::Value& jsonTerm : extraOptionJson) - { - if (jsonTerm.isString()) extraTermsMap[tq(jsonTerm.asString())][extraControlName] = true; - else if (jsonTerm.isArray()) - { - QStringList components; - for (const Json::Value& jsonComponent : jsonTerm) - if (jsonComponent.isString()) - components.append(tq(jsonComponent.asString())); - extraTermsMap[Term(components).asQString()][extraControlName] = true; - } - } - } - else - Log::log() << "Impossible Json type in _addTermsToOptions: " << extraOptionJson.toStyledString() << std::endl; - } - - return extraTermsMap; - -} - -const QString FormulaSource::interceptTerm = "Intercept"; - -bool FormulaSource::_checkIntercept(Terms &terms) const -{ - bool hasIntercept = false; - for (const Term& term : terms) - { - if (term.asQString() == interceptTerm) - { - hasIntercept = true; - terms.remove(term); - break; - } - } - - return hasIntercept; -} - -void FormulaSource::_addTermsToOptions(ListModelAssignedInterface *model, Json::Value &options, const Terms &terms) const -{ - BoundControlTerms* boundControl = dynamic_cast(model->listView()->boundControl()); - if (!boundControl) - { - Log::log() << "Add terms to options with a view that has not a BoundControlBase!!" << std::endl; - return; - } - - std::string optionName = fq(model->name()); - ListModel::RowControlsValues extraTermsMap; - - if (model == _model && _extraOptions.size() > 0) extraTermsMap = _getTermsFromExtraOptions(options); - - options[optionName] = boundControl->addTermsToOption(options[optionName], terms, extraTermsMap); -} - -bool FormulaSource::_areTermsInOptions(ListModelAssignedInterface *model, const Json::Value &options, Terms &terms) const -{ - BoundControlTerms* boundControl = dynamic_cast(model->listView()->boundControl()); - std::string optionName = fq(model->name()); - - return boundControl ? boundControl->areTermsInOption(options[optionName], terms) : false; -} - -FormulaParser::ParsedTerms FormulaSource::fillOptionsWithParsedTerms(const FormulaParser::ParsedTerms& parsedTerms, Json::Value& options) const -{ - if (_randomEffects.isEmpty()) return _fillOptionsWithFixedTerms(_model, parsedTerms, options); - else return _fillOptionsWithRandomTerms(parsedTerms, options); -} - -FormulaParser::ParsedTerms FormulaSource::_fillOptionsWithFixedTerms(ListModel* model, const FormulaParser::ParsedTerms& parsedTerms, Json::Value& options, QMap* termsMap) const -{ - FormulaParser::ParsedTerms remainingParsedTerms; - QList unspecifiedSourceModels, - specifiedSourceModels; - QStringList specifiedByUserSources = _formula->sourcesThatMustBeSpecified(); - - if (_sourceName.isEmpty()) return parsedTerms; - - ListModelAssignedInterface* assignedModel = qobject_cast(model); - - if (!assignedModel) - { - Log::log() << "Not an assigned model in fillOptionsWithParsedTerms..." << std::endl; - return parsedTerms; - } - - options[fq(assignedModel->name())] = Json::Value::null; - bool isInteractionModel = qobject_cast(assignedModel) != nullptr; - const QVector& sourceItems = model->listView()->sourceItems(); - for (SourceItem* sourceItem : sourceItems) - { - ListModelAssignedInterface* assignedSourceModel = qobject_cast(sourceItem->sourceListModel()); - if (assignedSourceModel) - { - if (specifiedByUserSources.contains(assignedSourceModel->name())) specifiedSourceModels.push_back(assignedSourceModel); - else unspecifiedSourceModels.push_back(assignedSourceModel); - } - } - - ListModelAvailableInterface* availableModel = assignedModel->availableModel(); - if (availableModel) - { - const QVector& sourceItems = availableModel->listView()->sourceItems(); - for (SourceItem* sourceItem : sourceItems) - { - ListModelAssignedInterface* assignedSourceModel = qobject_cast(sourceItem->sourceListModel()); - if (assignedSourceModel) - { - if (specifiedByUserSources.contains(assignedSourceModel->name())) specifiedSourceModels.push_back(assignedSourceModel); - else unspecifiedSourceModels.push_back(assignedSourceModel); - } - } - } - - remainingParsedTerms.intercept = parsedTerms.intercept; - remainingParsedTerms.randomTerms = parsedTerms.randomTerms; - for (const Term& parsedTerm : parsedTerms.fixedTerms) - { - if (parsedTerms.randomTerms.contains(parsedTerm.asQString())) - { - remainingParsedTerms.fixedTerms.add(parsedTerm); - continue; - } - bool found = false; - Terms terms; - terms.add(parsedTerm); - Terms termsToSearch = isInteractionModel ? Terms(parsedTerm.components()) : terms; - - if (termsToSearch.size() == 0) continue; - - // Check first whether the terms come from a user specified source first. - // In this case, as the model must be explicitly specified by the user, the model should not be changed. - for (ListModelAssignedInterface* model : specifiedSourceModels) - { - found = _areTermsInOptions(model, options, termsToSearch); - if (found) break; - } - - if (!found) - { - // If the terms does not come from the user specified sources, check if they are in a unspecified source model - // In this case the terms have to be added in this source. - for (ListModelAssignedInterface* sourceModel : unspecifiedSourceModels) - { - if (sourceModel->availableModel() != nullptr) - { - found = true; - const Terms& availableTerms = sourceModel->availableModel()->allTerms(); - for (const Term& term : termsToSearch) - if (!availableTerms.contains(term)) - found = false; - - if (found) - { - _addTermsToOptions(sourceModel, options, termsToSearch); - break; - } - } - } - - } - - if (!found && availableModel) - { - // If the terms do not come from the source models, it may then come from the available list. - found = true; - const Terms& availableTerms = availableModel->allTerms(); - for (const Term& term : termsToSearch) - if (!availableTerms.contains(term)) - found = false; - } - - if (found) - { - _addTermsToOptions(assignedModel, options, terms); - if (termsMap) - { - Terms currentTerms = (*termsMap)[assignedModel->name()]; - currentTerms.add(terms); - (*termsMap)[assignedModel->name()] = currentTerms; - } - } - else - remainingParsedTerms.fixedTerms.add(parsedTerm); - } - - return remainingParsedTerms; -} - -FormulaParser::ParsedTerms FormulaSource::_fillOptionsWithRandomTerms(const FormulaParser::ParsedTerms& parsedTerms, Json::Value& options) const -{ - FormulaParser::ParsedTerms remainingParsedTerms; - - VariablesListBase* fixedEffectsControl = qobject_cast(_randomEffects.fixedEffectsModel->listView()); - fixedEffectsControl->bindTo(options[fq(_randomEffects.fixedEffectsSource)]); - Terms fixedEffectTerms = fixedEffectsControl->model()->terms(); - - QList sourceModels; - - const QVector& sourceItems = _model->listView()->sourceItems(); - for (SourceItem* sourceItem : sourceItems) - { - ListModelAssignedInterface* assignedSourceModel = qobject_cast(sourceItem->sourceListModel()); - if (assignedSourceModel) - sourceModels.push_back(assignedSourceModel); - } - - std::map sourceMainTermsMap; - ListModel::RowControlsValues randomTermsMap; - - for (auto i = parsedTerms.randomTerms.begin(); i != parsedTerms.randomTerms.end(); ++i) - { - QString mainTerm = i.key(); - const FormulaParser::RandomTerm& randomTerm = i.value(); - - for (ListModelAssignedInterface* model : sourceModels) - { - if (model->availableModel() != nullptr) - { - const Terms& availableTerms = model->availableModel()->allTerms(); - if (availableTerms.contains(mainTerm)) - { - Terms sourceMainTerms = sourceMainTermsMap[model]; - sourceMainTerms.add(mainTerm); - sourceMainTermsMap[model] = sourceMainTerms; - break; - } - } - } - - QMap componentValues; - Json::Value variables(Json::arrayValue); - - Json::Value interceptVariable(Json::objectValue); - Json::Value interceptValue(Json::arrayValue); - interceptValue.append(fq(interceptTerm)); - interceptVariable[fq(_randomEffects.variablesKey)] = interceptValue; - interceptVariable[fq(_randomEffects.checkControl)] = randomTerm.intercept; - variables.append(interceptVariable); - - for (const Term& fixedTerm : fixedEffectTerms) - { - Json::Value variable(Json::objectValue); - variable[fq(_randomEffects.checkControl)] = randomTerm.terms.contains(fixedTerm); - Json::Value randomVariables(Json::arrayValue); - for (const std::string& fixedTermComponent : fixedTerm.scomponents()) - randomVariables.append(fixedTermComponent); - - variable[fq(_randomEffects.variablesKey)] = randomVariables; - variables.append(variable); - } - componentValues[_randomEffects.correlationControl] = randomTerm.correlated; - componentValues[_randomEffects.variablesControl] = variables; - randomTermsMap[mainTerm] = componentValues; - } - - for (auto sourceMainTermsIt : sourceMainTermsMap) - _addTermsToOptions(sourceMainTermsIt.first, options, sourceMainTermsIt.second); - - options[fq(_sourceName)] = _randomEffects.componentsList->getJsonFromComponentValues(randomTermsMap); - - return remainingParsedTerms; -} - -void FormulaSource::_addError(const QString &error) const -{ - _formula->rSyntax()->addError(error); -} - -// If a model is used in a formula, its row controls must be set as extra options -QMap FormulaSource::additionalOptionStrings() const -{ - QMap result; - if (!_model || hasRandomEffects()) return result; - - const QList& rowControls = _model->getAllRowControls().values(); - if (rowControls.size() == 0) return result; - - // Loop on all row controls. To do this, take the controls of the first row. - const QMap& firstRowControls = rowControls[0]->getJASPControlsMap(); - for (const QString& controlName : firstRowControls.keys()) - { - BoundControl* boundControl = firstRowControls[controlName]->boundControl(); - if (!boundControl) continue; // Only boundControl can get extra options - - const ExtraOption& extraOption = _extraOptions.contains(controlName) ? _extraOptions[controlName] : ExtraOption(controlName); - bool valueIsBool = boundControl->boundValue().type() == Json::booleanValue; - Terms terms = valueIsBool ? _onlyTrueTerms(controlName, _model->terms()) : _model->terms(); - if (terms.size() == 0) continue; - QString optionValue; - - if (valueIsBool && extraOption.useFormula) - optionValue = "~ " + generateInteractionTerms(terms); - else - { - optionValue = "list("; - bool first = true; - for (const Term& term : _model->terms()) - { - if (!first) optionValue += ", "; - first = false; - - if (valueIsBool) optionValue += FormulaParser::transformToFormulaTerm(term, FormulaParser::allInterationsSeparator, true); - else optionValue += FormulaParser::transformToFormulaTerm(term, FormulaParser::allInterationsSeparator, true) + " = " + RSyntax::transformJsonToR(boundControl->boundValue()); - } - optionValue += ")"; - } - - result[extraOption.optionName] = optionValue; - } - - return result; -} - -bool FormulaSource::isEmpty() const -{ - return _model ? _model->terms().size() == 0 : true; -} - -QStringList FormulaSource::extraOptions(bool useOptionName, bool onlyFormula) const -{ - QStringList result; - - for (const QString& controlName : _extraOptions.keys()) - { - const ExtraOption& extraOption = _extraOptions[controlName]; - - if (onlyFormula && !extraOption.useFormula) continue; - if (useOptionName) result.push_back(extraOption.optionName); - else result.push_back(controlName); - } - - return result; -} - -std::string FormulaSource::_controlToOptionName(const QString &name) const -{ - return fq(_formula->rSyntax()->getRSyntaxFromControlName(name)); -} diff --git a/QMLComponents/rsyntax/formulasource.h b/QMLComponents/rsyntax/formulasource.h deleted file mode 100644 index e95b047f774..00000000000 --- a/QMLComponents/rsyntax/formulasource.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef FORMULASOURCE_H -#define FORMULASOURCE_H - -#include -#include "formulaparser.h" -#include -#include "models/listmodel.h" - -class FormulaBase; -class ListModelAssignedInterface; -class Terms; -class ComponentsListBase; - -class FormulaSource : public QObject -{ - Q_OBJECT - -public: - struct ExtraOption - { - QString optionName; - bool useFormula = true; - - ExtraOption(const QString& _optionName, bool _useFormula = true) - : optionName(_optionName), useFormula(_useFormula) {} - ExtraOption(const QString& controlName, const QVariant& var); - ExtraOption() {} - }; - - struct RandomEffects - { - QString name, - fixedEffectsSource = "fixedEffects", - variablesControl = "randomComponents", - checkControl = "randomSlopes", - correlationControl = "correlations", - variablesKey = "value"; - ListModel* fixedEffectsModel = nullptr; - ComponentsListBase* componentsList = nullptr; // A RandomEffects can be made only from a ComponentsList item - - RandomEffects(const QVariant& var); - RandomEffects() {} - - bool isEmpty() const { return name.isEmpty(); } - }; - - FormulaSource(FormulaBase *formula, const QVariant& var); - - static const QString interceptTerm; - static QVector makeFormulaSources(FormulaBase* formula, const QVariant& var); - static QString generateInteractionTerms(const Terms& terms); - - const QString& sourceName() const { return _sourceName; } - QStringList modelSources() const; - QString toString() const; - QMap additionalOptionStrings() const; - bool isEmpty() const; - ListModel* model() const { return _model; } - FormulaParser::ParsedTerms fillOptionsWithParsedTerms(const FormulaParser::ParsedTerms& parsedTerms, Json::Value& options) const; - bool hasRandomEffects() const { return !_randomEffects.isEmpty(); } - QStringList extraOptions(bool useOptionName = true, bool onlyFormula = false) const; - -protected: - void _addError(const QString& error) const; - std::string _controlToOptionName(const QString& name) const; - QString _generateRandomEffectsTerms(const Terms& terms) const; - QString _generateSimpleTerms(const Terms& terms) const; - Terms _onlyTrueTerms(const QString& controlName, const Terms& terms) const; - bool _areTermsInOptions(ListModelAssignedInterface* model, const Json::Value& options, Terms& terms) const; - void _addTermsToOptions(ListModelAssignedInterface* model, Json::Value& options, const Terms& terms) const; - FormulaParser::ParsedTerms _fillOptionsWithFixedTerms(ListModel* model, const FormulaParser::ParsedTerms &parsedTerms, Json::Value &options, QMap* termsMap = nullptr) const; - FormulaParser::ParsedTerms _fillOptionsWithRandomTerms(const FormulaParser::ParsedTerms& parsedTerms, Json::Value& options) const; - ListModel::RowControlsValues _getTermsFromExtraOptions(const Json::Value& options) const; - bool _checkIntercept(Terms& terms) const; - - FormulaBase* _formula = nullptr; - ListModel* _model = nullptr; - QString _sourceName; - QMap _extraOptions; - RandomEffects _randomEffects; -}; - -#endif // FORMULASOURCE_H diff --git a/QMLComponents/rsyntax/rsyntax.cpp b/QMLComponents/rsyntax/rsyntax.cpp deleted file mode 100644 index 1bb572799a7..00000000000 --- a/QMLComponents/rsyntax/rsyntax.cpp +++ /dev/null @@ -1,486 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "rsyntax.h" -#include "appinfo.h" -#include "analysisform.h" -#include "log.h" -#include -#include "formulasource.h" -#include "controls/jasplistcontrol.h" -#include "boundcontrols/boundcontrolterms.h" - -QString RSyntax::FunctionOptionIndent = " "; -QString RSyntax::FunctionLineIndent = " "; - - -RSyntax::RSyntax(AnalysisForm *form) : QObject(form), _form(form) -{ -} - -QVariantList RSyntax::controlNameToRSyntaxMap() const -{ - QVariantList result; - - for (const QString& key : _controlNameToRSyntaxMap.keys()) - { - QVariantMap map; - map[key] = _controlNameToRSyntaxMap[key]; - result.push_back(map); - } - - return result; -} - -bool RSyntax::setControlNameToRSyntaxMap(const QVariantList &conversions) -{ - QMap newMap; - for (const QVariant& conversion : conversions) - { - if (conversion.canConvert()) - { - QVariantMap map = conversion.toMap(); - if (map.size() > 0) - { - QString key = map.firstKey(); - newMap[key] = map[key].toString(); - } - } - } - - if (newMap != _controlNameToRSyntaxMap) - { - _controlNameToRSyntaxMap = newMap; - - _rSyntaxToControlNameMap = QMap(); - for (const QString& key : _controlNameToRSyntaxMap.keys()) - _rSyntaxToControlNameMap[_controlNameToRSyntaxMap[key]] = key; - - return true; - } - - return false; -} - -QString RSyntax::generateSyntax(bool showAllOptions, bool useHtml) const -{ - QString result; - - QString newLine = useHtml ? "
    " : "\n", - indent = useHtml ? "        " : FunctionOptionIndent; - - - result = _analysisFullName() + "(" + newLine; - if (showAllOptions) - result += indent + "data = NULL," + newLine; - result += indent + "version = \"" + _form->version() + "\""; - - QStringList formulaSources; - for (FormulaBase* formula : _formulas) - { - bool isNull = false; - result += "," + newLine + formula->toString(newLine, indent, isNull); - if (!isNull) - formulaSources.append(formula->modelSources()); - } - - const Json::Value& boundValues = _form->boundValues(); - - for (const std::string& member : boundValues.getMemberNames()) - { - QString memberQ = tq(member); - if (member == ".meta" || formulaSources.contains(memberQ)) continue; - - JASPControl* control = _form->getControl(memberQ); - BoundControl* boundControl = control ? control->boundControl() : nullptr; - if (!boundControl) - { - Log::log() << "No control found with name " << memberQ << " in RSyntax" << std::endl; - continue; - } - - const Json::Value& defaultValue = boundControl->defaultBoundValue(); - const Json::Value& foundValue = boundValues.get(member, Json::Value::null); - if (showAllOptions || (defaultValue != foundValue)) - { - bool isDifferent = true; - // Sometimes a double value is set as integer, so their json value is different - // Check whether there are really different. - if (!showAllOptions && defaultValue.isNumeric() && foundValue.isNumeric()) - isDifferent = !qFuzzyCompare(defaultValue.asDouble(), foundValue.asDouble()); - if (isDifferent) - { - result += "," + newLine + indent + getRSyntaxFromControlName(control) + " = "; - - JASPListControl* listControl = qobject_cast(control); - if (listControl && !listControl->hasRowComponent() && listControl->containsInteractions()) - result += _transformInteractionTerms(listControl->model()); - else - result += transformJsonToR(foundValue); - } - } - } - - result += ")"; - - return result; -} - -QString RSyntax::generateWrapper() const -{ - QString result = "\ -#\n\ -# Copyright (C) 2013-2022 University of Amsterdam\n\ -#\n\ -# This program is free software: you can redistribute it and/or modify\n\ -# it under the terms of the GNU General Public License as published by\n\ -# the Free Software Foundation, either version 2 of the License, or\n\ -# (at your option) any later version.\n\ -#\n\ -# This program is distributed in the hope that it will be useful,\n\ -# but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ -# GNU General Public License for more details.\n\ -#\n\ -# You should have received a copy of the GNU General Public License\n\ -# along with this program. If not, see .\n\ -#\n\ -\n\ -# This is a generated file. Don't change it\n\ -\n\ -"; - result += _form->name() + " <- function(\n"; - result += FunctionOptionIndent + "data = NULL,\n"; - result += FunctionOptionIndent + "version = \"" + form()->version() + "\""; - for (FormulaBase* formula : _formulas) - result += ",\n" + FunctionOptionIndent + formula->name() + " = NULL"; - - for (FormulaBase* formula : _formulas) - { - QStringList extraOptions = formula->extraOptions(); - for (const QString& extraOption : extraOptions) - result += ",\n" + FunctionOptionIndent + extraOption + " = NULL"; - } - - const Json::Value& boundValues = _form->boundValues(); - QStringList optionsWithFormula; - for (FormulaBase* formula : _formulas) - optionsWithFormula += formula->extraOptions(true, true); - - for (const std::string& member : boundValues.getMemberNames()) - { - QString memberQ = tq(member); - if (member == ".meta") continue; - - JASPControl* control = _form->getControl(memberQ); - BoundControl* boundControl = control ? control->boundControl() : nullptr; - if (!boundControl) - { - Log::log() << "No control found with name " << memberQ << " in RSyntax" << std::endl; - continue; - } - - const Json::Value& defaultValue = boundControl->defaultBoundValue(); - result += ",\n" + FunctionOptionIndent + getRSyntaxFromControlName(control) + " = " + transformJsonToR(defaultValue); - - JASPListControl* listControl = qobject_cast(control); - if (listControl) - optionsWithFormula.push_back(getRSyntaxFromControlName(control)); - } - - result += ") {\n\n" - + FunctionLineIndent + "defaultArgCalls <- formals(" + _analysisFullName() + ")\n" - + FunctionLineIndent + "defaultArgs <- lapply(defaultArgCalls, eval)\n" - + FunctionLineIndent + "options <- as.list(match.call())[-1L]\n" - + FunctionLineIndent + "options <- lapply(options, eval)\n" - + FunctionLineIndent + "defaults <- setdiff(names(defaultArgs), names(options))\n" - + FunctionLineIndent + "options[defaults] <- defaultArgs[defaults]\n" - + FunctionLineIndent + "options[[\"data\"]] <- NULL\n" - + FunctionLineIndent + "options[[\"version\"]] <- NULL\n\n"; - - for (FormulaBase* formula : _formulas) - { - result += "" - + FunctionLineIndent + "if (!is.null(formula)) {\n" - + FunctionLineIndent + FunctionLineIndent + "if (!inherits(" + formula->name() + ", \"formula\")) {\n" - + FunctionLineIndent + FunctionLineIndent + FunctionLineIndent + formula->name() + " <- as.formula(" + formula->name() + ")\n" - + FunctionLineIndent + FunctionLineIndent + "}\n" - + FunctionLineIndent + FunctionLineIndent + "options$" + formula->name() + " <- jaspBase::jaspFormula(" + formula->name() + ", data)\n" - + FunctionLineIndent + "}\n\n"; - } - - if (optionsWithFormula.length() > 0) - { - result += "" - + FunctionLineIndent + "optionsWithFormula <- c("; - bool isFirst = true; - for (const QString& optionName : optionsWithFormula) - { - if (!isFirst) result += ", "; - result += "\"" + optionName + "\""; - isFirst = false; - } - result += ")\n" - + FunctionLineIndent + "for (name in optionsWithFormula) {\n" - + FunctionLineIndent + FunctionLineIndent + "if ((name %in% optionsWithFormula) && inherits(options[[name]], \"formula\")) options[[name]] = jaspBase::jaspFormula(options[[name]], data)" - + FunctionLineIndent + "}\n" - + "\n"; - } - - result += "" - + FunctionLineIndent + "return(jaspBase::runWrappedAnalysis(\"" + _analysisFullName() + "\", data, options, version))\n" - + "}"; - - return result; -} - -void RSyntax::setUp() -{ - for (FormulaBase* formula : _formulas) - { - formula->setUp(); - connect(formula, &FormulaBase::somethingChanged, this, &RSyntax::somethingChanged, Qt::QueuedConnection); - } -} - -FormulaBase* RSyntax::getFormula(const QString& name) const -{ - for (FormulaBase* formula : _formulas) - if (formula->name() == name) - return formula; - - return nullptr; -} - -void RSyntax::addFormula(FormulaBase *formula) -{ - if (getFormula(formula->name())) - _form->addFormError(tr("Formula with name '%1' is defined twice").arg(formula->name())); - else if (_form->getControl(formula->name())) - _form->addFormError(tr("A control and a formula have the same name '%1'").arg(formula->name())); - else - _formulas.append(formula); -} - -bool RSyntax::parseRSyntaxOptions(Json::Value &options) const -{ - Log::log() << "Parse Syntax Options: " << options.toStyledString() << std::endl; - if (!options.isObject()) - { - addError("Wrong type of options!"); - return false; - } - - Json::Value::Members members = options.getMemberNames(); - for (const std::string& member : members) - { - QString syntaxName = tq(member), - controlName = syntaxName; - if (_rSyntaxToControlNameMap.contains(syntaxName)) - { - controlName = _rSyntaxToControlNameMap[syntaxName]; - if (controlName != syntaxName) - { - options[fq(controlName)] = options[member]; - options.removeMember(member); - } - } - - JASPListControl* listControl = qobject_cast(_form->getControl(controlName)); - if (listControl) - { - BoundControl* boundControl = listControl->boundControl(); - Json::Value defaultOption = boundControl != nullptr ? boundControl->defaultBoundValue() : Json::Value::null; - const Json::Value& option = options[fq(controlName)]; - - // For user-friendliness purpose, an option that should have a structure (list of strings, or list of lists of strings...), - // can accept just a string. This may happen in 2 cases: - // . a formula is used - // . an array of strings contain only 1 element: this element is set without list. - BoundControlTerms* boundControlTerms = dynamic_cast(boundControl); - - if (option.isObject() && option.isMember("rhs") && boundControlTerms) - { - // When a formula is used, just parse it - FormulaParser::ParsedTerms parsedTerms; - QString error; - - if (!FormulaParser::parse(option["rhs"], false, parsedTerms, error)) - { - addError(error); - return false; - } - Json::Value newOption = boundControlTerms->addTermsToOption(Json::Value::null, parsedTerms.fixedTerms); - options[fq(controlName)] = newOption; - } - else if (defaultOption.isArray() && option.isString()) - { - // To make it easier, it is allowed to set a string when a Variables list has only 1 value: set back an array - Json::Value newOption(Json::arrayValue); - QString optionString = tq(option.asString()); - if (!optionString.isEmpty()) - newOption.append(fq(optionString)); - options[fq(controlName)] = newOption; - } - } - } - - for (FormulaBase* formula : _formulas) - formula->parseRSyntaxOptions(options); - - return !hasError(); -} - -void RSyntax::addError(const QString &msg) const -{ - _form->addControlError(_form->getControl(_form->rSyntaxControlName), msg); -} - -bool RSyntax::hasError() const -{ - return _form->hasError(); -} - -QString RSyntax::transformJsonToR(const Json::Value &json) -{ - QString result; - - switch (json.type()) - { - case Json::nullValue: - result = "NULL"; - break; - case Json::booleanValue: - result = json.asBool() ? "TRUE" : "FALSE"; - break; - case Json::stringValue: - result = "\"" + tq(json.asString()) + "\""; - break; - case Json::intValue: - result = QString::number(json.asInt()); - break; - case Json::uintValue: - result = QString::number(json.asUInt()); - break; - case Json::realValue: - result = QString::number(json.asDouble()); - break; - case Json::arrayValue: - if (json.size() == 0) result = "list()"; - else if (json.size() == 1 && (!json[uint(0)].isArray() && !json[uint(0)].isObject())) - result = transformJsonToR(json[uint(0)]); - else - { - bool first = true; - int index = -1; - result = "list("; - for (const Json::Value& val : json) - { - index++; - if (!first) result += ", "; - result += transformJsonToR(val); - first = false; - } - result += ")"; - } - break; - case Json::objectValue: - { - bool first = true; - result = "list("; - for (const std::string& member : json.getMemberNames()) - { - const Json::Value& val = json.get(member, Json::Value::null); - if (!first) result += ", "; - result += tq(member) + " = " + transformJsonToR(val); - first = false; - } - result += ")"; - } - } - - return result; -} - -bool RSyntax::_areTermsVariables(ListModel* model, const Terms& terms) const -{ - QStringList variables = model->requestInfo(VariableInfo::VariableNames).toStringList(); - - for (const Term& term : terms) - for (const QString& comp : term.components()) - if(!variables.contains(comp)) - return false; - - return true; -} - -QString RSyntax::_transformInteractionTerms(ListModel* model) const -{ - const Terms& terms = model->terms(); - - if (terms.size() == 0) return "NULL"; - - if (_areTermsVariables(model, terms)) return "~ " + FormulaSource::generateInteractionTerms(terms); - - QString result = "list("; - bool first = true; - for (const Term& term : terms) - { - if (!first) result += ", "; - first = false; - QStringList components = term.components(); - if (components.length() == 1) - result += "\"" + components[0] + "\""; - else - { - result += "list("; - bool firstComponent = true; - for (const QString& component : components) - { - if (!firstComponent) result += ", "; - firstComponent = false; - result += "\"" + component + "\""; - } - result += ")"; - } - } - - result += ")"; - - return result; -} - -QString RSyntax::_analysisFullName() const -{ - return _form->module() + "::" + _form->name(); -} - -QString RSyntax::getRSyntaxFromControlName(JASPControl *control) const -{ - return getRSyntaxFromControlName(control->name()); -} - -QString RSyntax::getRSyntaxFromControlName(const QString& name) const -{ - return _controlNameToRSyntaxMap.value(name, name); -} - -QString RSyntax::getControlNameFromRSyntax(const QString &name) const -{ - return _rSyntaxToControlNameMap.value(name, name); -} diff --git a/QMLComponents/rsyntax/rsyntax.h b/QMLComponents/rsyntax/rsyntax.h deleted file mode 100644 index b3331135443..00000000000 --- a/QMLComponents/rsyntax/rsyntax.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (C) 2013-2021 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef RSYNTAX_H -#define RSYNTAX_H - -#include -#include "formulabase.h" - -class AnalysisForm; -class JASPControl; -class Terms; - -class RSyntax : public QObject -{ - Q_OBJECT - -public: - RSyntax(AnalysisForm *form); - - AnalysisForm* form() const { return _form; } - QVariantList controlNameToRSyntaxMap() const; - bool setControlNameToRSyntaxMap(const QVariantList& conv); - - QString generateSyntax(bool showAllOptions = true, bool useHtml = false) const; - QString generateWrapper() const; - QString getRSyntaxFromControlName(JASPControl* control) const; - QString getRSyntaxFromControlName(const QString& name) const; - QString getControlNameFromRSyntax(const QString& name) const; - void setUp(); - void addFormula(FormulaBase* formula); - FormulaBase* getFormula(const QString& name) const; - bool parseRSyntaxOptions(Json::Value& options) const; - void addError(const QString& msg) const; - bool hasError() const; - - static QString FunctionOptionIndent, - FunctionLineIndent; - static QString transformJsonToR(const Json::Value& json); - -signals: - void somethingChanged(); - - -private: - - QString _analysisFullName() const; - QString _transformInteractionTerms(ListModel* model) const; - bool _areTermsVariables(ListModel* model, const Terms& terms) const; - - AnalysisForm* _form = nullptr; - QVector _formulas; - QMap _controlNameToRSyntaxMap; - QMap _rSyntaxToControlNameMap; -}; - -#endif // RSYNTAX_H diff --git a/QMLComponents/sortable.cpp b/QMLComponents/sortable.cpp deleted file mode 100644 index bd0378136df..00000000000 --- a/QMLComponents/sortable.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#include "sortable.h" -#include "models/sortmenumodel.h" - -Sortable::~Sortable() -{ -} - -void Sortable::sortItems() -{ - if (_sortMenuModel) - _sortMenuModel->sortItems(); -} - -Sortable::SortType Sortable::currentSortType() -{ - if (_sortMenuModel) - return _sortMenuModel->currentSortType(); - return SortType::None; -} diff --git a/QMLComponents/sortable.h b/QMLComponents/sortable.h deleted file mode 100644 index 1e7676d3049..00000000000 --- a/QMLComponents/sortable.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef SORTABLE_H -#define SORTABLE_H - -class SortMenuModel; - -class Sortable -{ - -public: - enum SortType { - None = 0, - SortByName, - SortByNameAZ, - SortByNameZA, - SortByType, - SortByDate, - SortBySize - }; - - virtual ~Sortable(); - - virtual void sortItems(SortType sortType) = 0; - void sortItems(); - - void setSortModel(SortMenuModel* menu) { _sortMenuModel = menu; } - SortType currentSortType(); - -private: - SortMenuModel* _sortMenuModel = nullptr; -}; - -#endif // SORTABLE_H diff --git a/QMLComponents/utilities/desktopcommunicator.cpp b/QMLComponents/utilities/desktopcommunicator.cpp deleted file mode 100644 index cc3536d6da5..00000000000 --- a/QMLComponents/utilities/desktopcommunicator.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "desktopcommunicator.h" - -DesktopCommunicator::DesktopCommunicator(QObject *parent) - : QObject{parent} -{ - assert(!_singleton); - - _singleton = this; -} - -DesktopCommunicator *DesktopCommunicator::singleton() -{ - if(!_singleton) - new DesktopCommunicator(); - - return _singleton; -} - -bool DesktopCommunicator::useNativeFileDialog() -{ -#ifdef BUILDING_JASP - return emit useNativeFileDialogSignal(); -#else - return true; -#endif -} - -DesktopCommunicator * DesktopCommunicator::_singleton = nullptr; diff --git a/QMLComponents/utilities/desktopcommunicator.h b/QMLComponents/utilities/desktopcommunicator.h deleted file mode 100644 index 3e8873bd6b5..00000000000 --- a/QMLComponents/utilities/desktopcommunicator.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef DESKTOPCOMMUNICATOR_H -#define DESKTOPCOMMUNICATOR_H - -#include - -///This class only exists to allow signal-slot connections to be made between certain classes in Desktop and in QMLComponents. -/// And to easily split that off when building for R -only -class DesktopCommunicator : public QObject -{ - Q_OBJECT -public: - explicit DesktopCommunicator(QObject *parent = nullptr); - - static DesktopCommunicator * singleton(); - - bool useNativeFileDialog(); - -signals: - void currentJaspThemeChanged(); - void uiScaleChanged(); - void interfaceFontChanged(); - bool useNativeFileDialogSignal(); //< For internal use only, `bool useNativeFileDialog();` is what you want - -private: - static DesktopCommunicator * _singleton; -}; - -#endif // DESKTOPCOMMUNICATOR_H diff --git a/QMLComponents/utilities/messageforwarder.cpp b/QMLComponents/utilities/messageforwarder.cpp deleted file mode 100644 index c5750304e4d..00000000000 --- a/QMLComponents/utilities/messageforwarder.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "messageforwarder.h" -#include "utilities/desktopcommunicator.h" -#include -#include -#include -#include -#include -#include -#include "qutils.h" -#include "log.h" -#include "appdirs.h" - -MessageForwarder::MessageForwarder(QObject *main) : QQuickItem(nullptr) -{ - if(_singleton != nullptr) - throw std::runtime_error("There can be only ONE MessageForwarder!"); - - _singleton = this; - - setParent(main); -} - -void MessageForwarder::log(QString msg) -{ - Log::log() << msg << std::endl; -} - -bool MessageForwarder::useNativeFileDialogs() -{ - return DesktopCommunicator::singleton()->useNativeFileDialog(); -} - -MessageForwarder * MessageForwarder::_singleton = nullptr; - -void MessageForwarder::showWarning(QString title, QString message) -{ - QMessageBox box; - box.setText(title); - box.setInformativeText(message); - box.setIcon(QMessageBox::Warning); - - box.exec(); -} - -bool MessageForwarder::showYesNo(QString title, QString message, QString YesButtonText, QString NoButtonText) -{ - if(YesButtonText == "") YesButtonText = tr("Yes"); - if(NoButtonText == "") NoButtonText = tr("No"); - - QMessageBox box; - - box.setText(title); - box.setInformativeText(message); - box.setIcon(QMessageBox::Question); - - QPushButton* yesButton = box.addButton(YesButtonText, QMessageBox::ButtonRole::YesRole); - QPushButton* noButton = box.addButton(NoButtonText, QMessageBox::ButtonRole::NoRole); - box.exec(); - - return box.clickedButton() == yesButton; -} - -MessageForwarder::DialogResponse MessageForwarder::showYesNoCancel(QString title, QString message, QString YesButtonText, QString NoButtonText, QString CancelButtonText) -{ - if(YesButtonText == "") YesButtonText = tr("Yes"); - if(NoButtonText == "") NoButtonText = tr("No"); - if(CancelButtonText == "") CancelButtonText = tr("Cancel"); - - QMessageBox box; - - box.setText(title); - box.setInformativeText(message); - box.setIcon(QMessageBox::Question); - - QPushButton* yesButton = box.addButton(YesButtonText, QMessageBox::ButtonRole::YesRole); - QPushButton* noButton = box.addButton(NoButtonText, QMessageBox::ButtonRole::NoRole); - QPushButton* cancelButton = box.addButton(CancelButtonText, QMessageBox::ButtonRole::RejectRole); - box.setDefaultButton(cancelButton); - - box.exec(); - - QAbstractButton * clicked = box.clickedButton(); - if (clicked == yesButton) return DialogResponse::Yes; - else if (clicked == noButton) return DialogResponse::No; - - return DialogResponse::Cancel; -} - -MessageForwarder::DialogResponse MessageForwarder::showSaveDiscardCancel(QString title, QString message, QString saveText, QString discardText, QString cancelText) -{ - QMessageBox box; - - box.setText(title); - box.setInformativeText(message); - box.setIcon(QMessageBox::Question); - - if(saveText == "") saveText = tr("Save"); - if(discardText == "") discardText = tr("Don't Save"); - if(cancelText == "") cancelText = tr("Cancel"); - - // In order to have the noSaveButton as first in the row of buttons, it has to get the role RejectRole. - QPushButton* saveButton = box.addButton(saveText, QMessageBox::ButtonRole::AcceptRole); - QPushButton* noSaveButton = box.addButton(discardText, QMessageBox::ButtonRole::DestructiveRole); - box.addButton(cancelText, QMessageBox::ButtonRole::RejectRole); - - box.setDefaultButton(saveButton); - box.exec(); - - QAbstractButton* clicked = box.clickedButton(); - - if (clicked == saveButton) return DialogResponse::Save; - else if (clicked == noSaveButton) return DialogResponse::Discard; - - return DialogResponse::Cancel; -} - -QString MessageForwarder::askPassword(QString title, QString message) -{ -// here we can open a nice QInputDialog with a password field etc (modally) - return QInputDialog::getText(nullptr, title, message, QLineEdit::Password); -} - -QString MessageForwarder::browseOpenFile(QString caption, QString browsePath, QString filter) -{ - if(useNativeFileDialogs()) return QFileDialog::getOpenFileName(nullptr, caption, browsePath, filter); - else return QFileDialog::getOpenFileName(nullptr, caption, browsePath, filter, nullptr, QFileDialog::DontUseNativeDialog); -} - -QString MessageForwarder::browseOpenFileDocuments(QString caption, QString filter) -{ - return browseOpenFile(caption, AppDirs::documents(), filter); -} - -QString MessageForwarder::browseSaveFileDocuments(QString caption, QString filter) -{ - return browseSaveFile(caption, AppDirs::documents(), filter); -} - -QString MessageForwarder::browseSaveFile(QString caption, QString browsePath, QString filter, QString * selectedExtension) -{ - Log::log() << "MessageForwarder::browseSaveFile(\"" << caption.toStdString() << "\", \"" << browsePath.toStdString() << "\", \"" << filter.toStdString() << "\")" << std::endl; - - QString saveFileName, selectedFilter; - - if(useNativeFileDialogs()) saveFileName = QFileDialog::getSaveFileName(nullptr, caption, browsePath, filter, &selectedFilter); - else saveFileName = QFileDialog::getSaveFileName(nullptr, caption, browsePath, filter, &selectedFilter, QFileDialog::DontUseNativeDialog); - - Log::log() << "Selected save file: " << saveFileName << " and selected filter: " << selectedFilter << std::endl; - - //Lets make sure the extension is added: - static const QRegularExpression extReg("\\*\\.(\\w+)"); - QRegularExpressionMatch possibleMatch = extReg.match(selectedFilter); - - if(possibleMatch.hasMatch()) - { - QString ext = possibleMatch.captured(1); - - if(!saveFileName.endsWith(ext)) - saveFileName += "." + ext; - - if(selectedExtension) - *selectedExtension = ext; - } - else if(selectedExtension)//So the filter doesnt tell us the extension but the caller expects to know what is what - { - if(saveFileName.lastIndexOf('.') >= 0) *selectedExtension = saveFileName.mid(saveFileName.lastIndexOf('.') + 1); - else *selectedExtension = ""; //??? - } - - if(selectedExtension) - Log::log() << "Selected extension: '" << *selectedExtension << "'" << std::endl; - - return saveFileName; -} - -QString MessageForwarder::browseOpenFolder(QString caption, QString browsePath) -{ - if(useNativeFileDialogs()) return QFileDialog::getExistingDirectory(nullptr, caption, browsePath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - else return QFileDialog::getExistingDirectory(nullptr, caption, browsePath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks | QFileDialog::DontUseNativeDialog); -} - -QString MessageForwarder::browseOpenFolder(QString caption) -{ - return browseOpenFolder(caption, AppDirs::documents()); -} diff --git a/QMLComponents/utilities/messageforwarder.h b/QMLComponents/utilities/messageforwarder.h deleted file mode 100644 index 0800df79c27..00000000000 --- a/QMLComponents/utilities/messageforwarder.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef MESSAGEFORWARDER_H -#define MESSAGEFORWARDER_H - -#include -#include - -/// -/// Singleton class for shwoing warnings, messages, etc -/// Can be accessed through the static function anywhere in Desktop -/// Can also be accessed through `messages.` in QML -class MessageForwarder : public QQuickItem -{ - Q_OBJECT -public: - enum class DialogResponse { Cancel, Yes, No, Save, Discard }; - Q_ENUM(DialogResponse) - - - explicit MessageForwarder(QObject *main); - ~MessageForwarder() { _singleton = nullptr;} - - static MessageForwarder * msgForwarder() { return _singleton; } - - static void showWarning(QString title, QString message); - static void showWarning(std::string title, std::string message) { showWarning(QString::fromStdString(title), QString::fromStdString(message)); } - static void showWarning(const char * title, const char * message) { showWarning(QString(title), QString(message)); } - - static void showWarning(QString message) { showWarning("", message); } - static void showWarning(std::string message) { showWarning(QString::fromStdString(message)); } - static void showWarning(const char * message) { showWarning(QString(message)); } - - static bool showYesNo(QString title, QString message, QString YesButtonText = "", QString NoButtonText = ""); - static bool showYesNo(std::string title, std::string message, std::string YesButtonText = "", std::string NoButtonText = "") { return showYesNo(QString::fromStdString(title), QString::fromStdString(message), QString::fromStdString(YesButtonText), QString::fromStdString(NoButtonText)); } - static bool showYesNo(const char * title, const char * message, const char * YesButtonText = "", const char * NoButtonText = "") { return showYesNo(QString(title), QString(message), QString(YesButtonText), QString(NoButtonText)); } - - - static DialogResponse showSaveDiscardCancel(QString title, QString message, QString saveTxt = "", QString discardText = "", QString cancelText = ""); - static DialogResponse showYesNoCancel( QString title, QString message, QString YesButtonText = "", QString NoButtonText = "", QString CancelButtonText = ""); - - static QString browseOpenFile( QString caption, QString browsePath, QString filter); - static QString browseSaveFile( QString caption, QString browsePath, QString filter, QString * selectedExtension = nullptr); - static QString browseOpenFolder( QString caption, QString browsePath); - static QString browseOpenFolder( QString caption); - static QString browseOpenFileDocuments( QString caption, QString filter); - static QString browseSaveFileDocuments( QString caption, QString filter); - - static QString askPassword(QString title, QString message); - - //Some non-static links to have QML handle it. Without figuring out how qmlRegisterSingletonType() works :p -public slots: - DialogResponse showSaveDiscardCancelQML(QString title, QString message, QString saveTxt = "", QString discardText = "", QString cancelText = "") { return showSaveDiscardCancel(title, message, saveTxt, discardText, cancelText); } - void showWarningQML(QString title, QString message) { showWarning(title, message); } - QString browseOpenFileQML(QString caption, QString browsePath, QString filter) { return browseOpenFile(caption, browsePath, filter); } - QString browseOpenFileDocumentsQML(QString caption, QString filter) { return browseOpenFileDocuments(caption, filter); } - - QString browseSaveFileQML(QString caption, QString browsePath, QString filter) { return browseSaveFile(caption, browsePath, filter); } - QString browseSaveFileDocumentsQML(QString caption, QString filter) { return browseSaveFileDocuments(caption, filter); } - QString browseOpenFolderQML(QString caption, QString browsePath) { return browseOpenFolder(caption, browsePath);} - QString browseOpenFolderQML(QString caption) { return browseOpenFolder(caption);} - - - void log(QString msg); - -private: - static bool useNativeFileDialogs(); - static MessageForwarder * _singleton; -}; - -#endif // MESSAGEFORWARDER_H diff --git a/QMLComponents/utilities/qmlutils.cpp b/QMLComponents/utilities/qmlutils.cpp deleted file mode 100644 index f0c09bbe044..00000000000 --- a/QMLComponents/utilities/qmlutils.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include -#include -#include "qmlutils.h" -#include "qutils.h" -#include "log.h" -#include "columnencoder.h" - -#ifdef linux -#include -#include -#include "appinfo.h" -#endif - - -const char * qmlLoadError::what() const noexcept -{ - //Just here to have an out-of-line virtual method so that clang and gcc don't complain so much - return std::runtime_error::what(); -} - - -QmlUtils::QmlUtils(QObject *parent) : QObject(parent) -{ - -} - -QString QmlUtils::encodeAllColumnNames(const QString & str) -{ - return tq(ColumnEncoder::encodeAll(fq(str))); -} - -QString QmlUtils::decodeAllColumnNames(const QString & str) -{ - return tq(ColumnEncoder::decodeAll(fq(str))); -} - -QJSValue QmlUtils::encodeJson(const QJSValue & val, QQuickItem * caller) -{ - Json::Value v(fqj(val)); - ColumnEncoder::encodeJson(v); - return tqj(v, caller); -} - -QJSValue QmlUtils::decodeJson(const QJSValue & val, QQuickItem * caller) -{ - Json::Value v(fqj(val)); - ColumnEncoder::decodeJson(v); - return tqj(v, caller); -} - -//Turning QMLENGINE_DOES_ALL_THE_WORK on also works fine, but has slightly less transparent errormsgs so isn't recommended -//#define QMLENGINE_DOES_ALL_THE_WORK - -QObject * instantiateQml(const QString & qmlTxt, const QUrl & url, const std::string & moduleName, const std::string & whatAmILoading, const std::string & filename, QQmlContext * ctxt) -{ - QObject * obj = nullptr; - -#ifdef QMLENGINE_DOES_ALL_THE_WORK - obj = MainWindow::singleton()->loadQmlData(qmlTxt, url); -#else -// if(!ctxt) -// ctxt = MainWindow::singleton()->giveRootQmlContext(); - - QQmlComponent qmlComp(ctxt->engine()); - - //Log::log() << "Setting url to '" << url.toString() << "' for Description.qml.\n" << std::endl;// data: '" << descriptionTxt << "'\n"<< std::endl; - - qmlComp.setData(qmlTxt.toUtf8(), url); - - if(qmlComp.isLoading()) - Log::log() << whatAmILoading << " for module " << moduleName << " is still loading, make sure you load a local file and that Windows doesn't mess this up for you..." << std::endl; - - - auto errorLogger =[&](bool isError, QList errors) - { - if(!isError) return; - - std::stringstream out; - - out << "Loading " << filename << " for module " << moduleName << " had errors:\n"; - - for(const QQmlError & error : errors) - out << error.toString() << "\n"; - - Log::log() << out.str() << std::flush; - - throw qmlLoadError("There were errors loading " + filename + ":\n" + out.str()); - }; - - errorLogger(qmlComp.isError(), qmlComp.errors()); - - if(!qmlComp.isReady()) - throw qmlLoadError(whatAmILoading + " Component is not ready!"); - - QQmlIncubator localIncubator(QQmlIncubator::Synchronous); - - - qmlComp.create(localIncubator); - - errorLogger(localIncubator.isError(), localIncubator.errors()); - - obj = localIncubator.object(); - -#endif - - return obj; -} - -QObject * instantiateQml(const QUrl & filePath, const std::string & moduleName, QQmlContext * ctxt) -{ - if(!filePath.isLocalFile()) - throw std::runtime_error(fq(filePath.toLocalFile()) + " is not a local file..."); - - QFileInfo qmlFileInfo(filePath.toLocalFile()); - - if(!qmlFileInfo.exists()) - throw std::runtime_error(fq(qmlFileInfo.absoluteFilePath()) + " does not exist..."); - - QString qmlTxt; - QFile qmlFile(qmlFileInfo.absoluteFilePath()); - - qmlFile.open(QIODevice::ReadOnly); - qmlTxt = qmlFile.readAll(); - qmlFile.close(); - - return instantiateQml(qmlTxt, filePath, moduleName, fq(qmlFileInfo.absoluteFilePath()), fq(qmlFileInfo.fileName()), ctxt); - -} - - -#ifdef linux - -void QmlUtils::configureQMLCacheDir() -{ - //set cache environment variable - QDir cacheDir = QmlUtils::generateQMLCacheDir(); - bool set = qputenv("QML_DISK_CACHE_PATH", cacheDir.absolutePath().toLocal8Bit()); - if(!set) - throw std::runtime_error("Could not set qml cache directory in environment"); - - //delete stale caches - QDir parent = cacheDir; - parent.cdUp(); - QStringList staleCaches = parent.entryList(QStringList() << "qmlcache*", QDir::NoDot | QDir::NoDotDot | QDir::Dirs); - - for(auto& cacheName: staleCaches) - { - QDir staleCache = parent; - staleCache.cd(cacheName); - if(cacheDir.absolutePath() != staleCache.absolutePath()) - staleCache.removeRecursively(); - } - Log::log() << "QML cache directory: " + cacheDir.absolutePath() << std::endl; -} - -QDir QmlUtils::generateQMLCacheDir() -{ - QString commit = tq(AppInfo::gitCommit), - basePath = qEnvironmentVariable("QML_DISK_CACHE_PATH", QStandardPaths::writableLocation(QStandardPaths::CacheLocation)), - path = basePath + "/qmlcache_" + commit; - QDir cacheDir(path); - - if(!cacheDir.exists() && !cacheDir.mkpath(".")) - throw std::runtime_error("Could not create qml cache directory: " + fq(cacheDir.absolutePath())); - - cacheDir.refresh(); - return cacheDir; -} - -#endif diff --git a/QMLComponents/utilities/qmlutils.h b/QMLComponents/utilities/qmlutils.h deleted file mode 100644 index 847488ea83e..00000000000 --- a/QMLComponents/utilities/qmlutils.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef QMLUTILS_H -#define QMLUTILS_H - -#include -#include -#include -#include - -struct qmlLoadError : public std::runtime_error -{ - qmlLoadError(std::string msg) : std::runtime_error(msg) {} - const char* what() const noexcept override; -}; - -/// Simply links through utilities for use in and around QML -class QmlUtils : public QObject -{ - Q_OBJECT -public: - explicit QmlUtils(QObject *parent = nullptr); - -#ifdef linux -// Functions for qml cache bug workaround on linux -public: - static void configureQMLCacheDir(); -private: - static QDir generateQMLCacheDir(); -#endif - -public slots: - QString encodeAllColumnNames( const QString & str); - QString decodeAllColumnNames( const QString & str); - - QJSValue encodeJson( const QJSValue & val, QQuickItem * caller); - QJSValue decodeJson( const QJSValue & val, QQuickItem * caller); - -}; - -QObject * instantiateQml( const QUrl & filePath, const std::string & moduleName, QQmlContext * ctxt = nullptr); -QObject * instantiateQml(const QString & qmlTxt, const QUrl & url, const std::string & moduleName, const std::string & whatAmILoading, const std::string & filename, QQmlContext * ctxt = nullptr); - - -#endif // QMLUTILS_H diff --git a/QMLComponents/variableinfo.cpp b/QMLComponents/variableinfo.cpp deleted file mode 100644 index 99fd9f14508..00000000000 --- a/QMLComponents/variableinfo.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "variableinfo.h" -#include "jasptheme.h" -#include "QQmlContext" -#include "QTimer" - -VariableInfo* VariableInfo::_singleton = nullptr; - -VariableInfo::VariableInfo(VariableInfoProvider* providerInfo) : - QObject(providerInfo->providerModel()), _provider(providerInfo) -{ - if (_singleton == nullptr) - { - _singleton = this; - QTimer::singleShot(0, [&]() { _setDataSetInfoInContext(); }); - } -} - -void VariableInfo::_setDataSetInfoInContext() -{ - QQmlContext* context = _provider->providerQMLContext(); - context->setContextProperty("dataSetInfo", this); -} - -VariableInfo *VariableInfo::info() -{ - return _singleton; -} - -QString VariableInfo::getIconFile(columnType colType, VariableInfo::IconType type) -{ - QString path = JaspTheme::currentIconPath(); - switch(type) - { - case VariableInfo::DefaultIconType: - switch(colType) - { - case columnType::scale: return path + "variable-scale.png"; - case columnType::ordinal: return path + "variable-ordinal.png"; - case columnType::nominal: return path + "variable-nominal.png"; - case columnType::nominalText: return path + "variable-nominal-text.png"; - default: return ""; - } - case VariableInfo::DisabledIconType: - switch(colType) - { - case columnType::scale: return path + "variable-scale-disabled.png"; - case columnType::ordinal: return path + "variable-ordinal-disabled.png"; - case columnType::nominal: return path + "variable-nominal-disabled.png"; - case columnType::nominalText: return path + "variable-nominal-text-inactive.png"; - default: return ""; - } - case VariableInfo::InactiveIconType: - switch(colType) - { - case columnType::scale: return path + "variable-scale-inactive.png"; - case columnType::ordinal: return path + "variable-ordinal-inactive.png"; - case columnType::nominal: return path + "variable-nominal-inactive.png"; - case columnType::nominalText: return path + "variable-nominal-text-inactive.png"; - default: return ""; - } - } - - return ""; //We are never getting here but GCC isn't convinced -} - -int VariableInfo::rowCount() -{ - return _provider ? _provider->provideInfo(VariableInfo::DataSetRowCount).toInt() : 0; -} - -bool VariableInfo::dataAvailable() -{ - return _provider ? _provider->provideInfo(VariableInfo::DataAvailable).toBool() : false; -} diff --git a/QMLComponents/variableinfo.h b/QMLComponents/variableinfo.h deleted file mode 100644 index 4c30e8fe6c5..00000000000 --- a/QMLComponents/variableinfo.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (C) 2013-2018 University of Amsterdam -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public -// License along with this program. If not, see -// . -// - -#ifndef VARIABLEINFO_H -#define VARIABLEINFO_H - -#include -#include -#include -#include -#include "columntype.h" - -class VariableInfoProvider; - -// The Provider/Consumer mechanism makes an interface so that the consumers (the QML models) get their data without having to know how the Provider furnishes this data -// Typically, for a JASP application, the Provider will be the ColumnsModel, but if the QML forms are used somewhere else, another Provider should be instantiated. -// We need a QObject class so that we can use the Qt signals. -// The VariableInfoProvider and VariableInfoConsumer are classes used by ColumnsModel, ListModel or SourceItem, that are already QObject classes. -// As a class cannot derive from 2 QObject classes, the VariableInfoProvider and VariableInfoConsumer cannot be QObject classes. -// So we just use the VariableInfo class (which is a singleton intialized at the start of the application) to propagate the signals -class VariableInfo : public QObject -{ - Q_OBJECT -public: - enum InfoType { VariableType, VariableTypeName, VariableTypeIcon, VariableTypeDisabledIcon, VariableTypeInactiveIcon, VariableNames, DataSetRowCount, Labels, DoubleValues, NameRole, DataSetValue, MaxWidth, SignalsBlocked, DataAvailable }; - enum IconType { DefaultIconType, DisabledIconType, InactiveIconType }; - -public: - VariableInfo(VariableInfoProvider* provider); - - Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged ) - Q_PROPERTY(bool dataAvailable READ dataAvailable NOTIFY dataAvailableChanged ) - - static VariableInfo* info(); - static QString getIconFile(columnType colType, IconType type); - - VariableInfoProvider* provider() { return _provider; } - - int rowCount(); - bool dataAvailable(); - -signals: - void namesChanged(QMap changedNames); - void columnsChanged(QStringList changedColumns); - void columnTypeChanged(QString colName); - void labelsChanged(QString columnName, QMap changedLabels); - void labelsReordered(QString columnName); - void rowCountChanged(); - void dataAvailableChanged(); - -private: - void _setDataSetInfoInContext(); - - VariableInfoProvider * _provider = nullptr; - - static VariableInfo *_singleton; -}; - -class VariableInfoProvider -{ -public: - virtual QVariant provideInfo(VariableInfo::InfoType info, const QString& name = "", int row = 0) const = 0; - virtual QAbstractItemModel* providerModel() { return nullptr; } - virtual QQmlContext* providerQMLContext() const = 0; -}; - -class VariableInfoConsumer -{ -public: - VariableInfoConsumer() { _provider = (VariableInfo::info() ? VariableInfo::info()->provider() : nullptr); -} - - QVariant requestInfo(VariableInfo::InfoType info, const QString &name = "", int row = 0) const { return _provider ? _provider->provideInfo(info, name, row) : QVariant(); } - bool isInfoProviderModel(QObject* model) const { return _provider ? model == _provider->providerModel() : false; } - QAbstractItemModel* infoProviderModel() { return _provider ? _provider->providerModel() : nullptr; } - -private: - VariableInfoProvider *_provider = nullptr; -}; - -#endif // VARIABLEINFO_H - diff --git a/R-Interface/CMakeLists.txt b/R-Interface/CMakeLists.txt index f3214a7f810..59ab34b8b56 100644 --- a/R-Interface/CMakeLists.txt +++ b/R-Interface/CMakeLists.txt @@ -38,7 +38,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT R-Interface) -file(GLOB SOURCE_FILES "${PROJECT_SOURCE_DIR}/Common/json/*.cpp") +file(GLOB SOURCE_FILES "${PROJECT_SOURCE_DIR}/jaspCommonLib/json/*.cpp") list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/jasprcpp.cpp") list(APPEND HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/jasprcpp.h") list(APPEND HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/jasprcpp_interface.h") @@ -150,7 +150,7 @@ if(WIN32) R-Interface PUBLIC # JASP ${CMAKE_CURRENT_LIST_DIR} - ${PROJECT_SOURCE_DIR}/../Common + ${PROJECT_SOURCE_DIR}/../jaspCommonLib ${PROJECT_SOURCE_DIR}/../CommonData # R ${R_INCLUDE_PATH} @@ -193,9 +193,9 @@ else() target_include_directories( R-Interface PUBLIC # JASP - ${PROJECT_SOURCE_DIR}/Common + ${PROJECT_SOURCE_DIR}/jaspCommonLib ${PROJECT_SOURCE_DIR}/CommonData - ${PROJECT_SOURCE_DIR}/Common/json + ${PROJECT_SOURCE_DIR}/jaspCommonLib/json #$<$:${_PKGCONFIG_LIB_JSONCPP_INCLUDEDIR}> # R ${R_INCLUDE_PATH} diff --git a/Tools/CMake/JASP.cmake b/Tools/CMake/JASP.cmake index 2db28a129d7..435627b74d4 100644 --- a/Tools/CMake/JASP.cmake +++ b/Tools/CMake/JASP.cmake @@ -9,40 +9,6 @@ list(APPEND CMAKE_MESSAGE_CONTEXT JASP) -if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") - - message(CHECK_START "Retrieving the git-branch information") - - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_BRANCH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --verify HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT - OUTPUT_STRIP_TRAILING_WHITESPACE) - - message(CHECK_PASS "done.") - - set(GIT_CURRENT_BRANCH ${GIT_BRANCH}) - set(GIT_CURRENT_COMMIT ${GIT_COMMIT}) - - cmake_print_variables(GIT_CURRENT_BRANCH) - cmake_print_variables(GIT_CURRENT_COMMIT) -endif() - -set(JASP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) -set(JASP_VERSION_MINOR ${PROJECT_VERSION_MINOR}) -set(JASP_VERSION_PATCH ${PROJECT_VERSION_PATCH}) -set(JASP_VERSION_TWEAK ${PROJECT_VERSION_TWEAK}) - -set(JASP_VERSION ${CMAKE_PROJECT_VERSION}) -set(JASP_SHORT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}) - -message(STATUS "Version: ${CMAKE_PROJECT_VERSION}") set(JASP_VERSION_MSIX_PATCH_POSTFIX "" @@ -108,32 +74,6 @@ endif() option(UPDATE_JASP_SUBMODULES "Whether to automatically initialize and update the submodules" OFF) -message(CHECK_START "Checking for CRYPT_KEY") -set(CRYPT_KEY - "" - CACHE STRING "") - -if(CRYPT_KEY STREQUAL "") - # Let's see if the user has set something in the environment - set(CRYPT_KEY $ENV{CRYPTKEY}) - - if(CRYPT_KEY STREQUAL "") - - message(CHECK_PASS "set to default.") - - set(CRYPT_KEY "0x0c2ad4a4acb9f023") - - else() - - message(CHECK_PASS "found in environment.") - - endif() - - message(STATUS " ${CRYPT_KEY}") - -else() - message(CHECK_PASS "set by user in cmake config.") -endif() # Dealing with Git submodules diff --git a/Tools/jaspTools b/Tools/jaspTools index 4a510a8b933..96f1367080d 160000 --- a/Tools/jaspTools +++ b/Tools/jaspTools @@ -1 +1 @@ -Subproject commit 4a510a8b933aef1d3025cf79749af9070e80b2cf +Subproject commit 96f1367080d2a9d47f8fb3d1d39d9059e245d8f7 diff --git a/jaspCommonLib b/jaspCommonLib new file mode 160000 index 00000000000..dae5c64dcff --- /dev/null +++ b/jaspCommonLib @@ -0,0 +1 @@ +Subproject commit dae5c64dcff432e229284506a2e735cc392f9324 diff --git a/jaspQMLControlsPlugin b/jaspQMLControlsPlugin new file mode 160000 index 00000000000..245f08d7234 --- /dev/null +++ b/jaspQMLControlsPlugin @@ -0,0 +1 @@ +Subproject commit 245f08d72345def8563dfdf6eaa463c236862ea2