From 53b7cc13761c073e88dbf976ee201f402ed49117 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 17 Nov 2018 15:06:25 +0100 Subject: [PATCH 01/46] Fix QML achoring warnings on Layouts --- interface/resources/qml/hifi/tablet/TabletHome.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index f1f54e8419..1b0165ea94 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -61,7 +61,7 @@ Item { RalewaySemiBold { text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in") horizontalAlignment: Text.AlignRight - anchors.right: parent.right + Layout.alignment: Qt.AlignRight font.pixelSize: 20 color: "#afafaf" } @@ -71,7 +71,7 @@ Item { height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0 text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : "" horizontalAlignment: Text.AlignRight - anchors.right: parent.right + Layout.alignment: Qt.AlignRight font.pixelSize: 20 color: "#afafaf" } From 932d1dbcd735d4b5e6a69afd07903a8cc3ce5999 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 17 Nov 2018 17:20:02 +0100 Subject: [PATCH 02/46] Fixed width binding loop warning --- interface/resources/qml/LoginDialog/LinkAccountBody.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 103761236d..3e4614c342 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -23,6 +23,8 @@ Item { width: root.pane.width property bool failAfterSignUp: false + onWidthChanged: d.resize(); + function login() { flavorText.visible = false mainTextContainer.visible = false @@ -127,7 +129,7 @@ Item { Column { id: form width: parent.width - onHeightChanged: d.resize(); onWidthChanged: d.resize(); + onHeightChanged: d.resize(); anchors { top: mainTextContainer.bottom From 7ffa70d0ac3558c31811877dc6af0b66b66dbea2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 20 Nov 2018 09:36:58 +1300 Subject: [PATCH 03/46] Fix memory accumulating while Interface is minimized --- interface/src/Application.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7a30b566e9..929a27c88b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6222,6 +6222,11 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("enqueueFrame"); getMain3DScene()->enqueueFrame(); } + + // If the display plugin is inactive then the frames won't be processed so process them here. + if (!getActiveDisplayPlugin()->isActive()) { + getMain3DScene()->processTransactionQueue(); + } } void Application::updateRenderArgs(float deltaTime) { From a2bcc9e899118fe47c0260e66f26539b3f5e4740 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 15:19:54 -0800 Subject: [PATCH 04/46] teeny weeny typo... --- tools/nitpick/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index 3bbc4fbac1..dce3880123 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -55,7 +55,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`. 1. __To run nitpick, double click **nitpick.exe**__ #### Mac -1. (Firat time) install Python from https://www.python.org/downloads/release/python-370/ (**macOS 64-bit installer** or **macOS 64-bit/32-bit installer**) +1. (First time) install Python from https://www.python.org/downloads/release/python-370/ (**macOS 64-bit installer** or **macOS 64-bit/32-bit installer**) 1. After installation - run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. 1. Verify that `/usr/local/bin/python3` exists. 1. (First time - AWS interface) Install pip with the script provided by the Python Packaging Authority: From f6ffb16103b3788078ca2cd90cf65c7562c263d4 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 15:21:39 -0800 Subject: [PATCH 05/46] Version 1.1 --- tools/nitpick/src/ui/Nitpick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/src/ui/Nitpick.cpp b/tools/nitpick/src/ui/Nitpick.cpp index a4aef8fad5..201d6e562d 100644 --- a/tools/nitpick/src/ui/Nitpick.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -36,7 +36,7 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) { _ui.statusLabel->setText(""); _ui.plainTextEdit->setReadOnly(true); - setWindowTitle("Nitpick - v1.0"); + setWindowTitle("Nitpick - v1.1"); // Coming soon to a nitpick near you... //// _helpWindow.textBrowser->setText() From c3c41700f6a9ea8fd00782e631a9ce38c4fdbd57 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 17:01:58 -0800 Subject: [PATCH 06/46] Can delete temporarY AppData folder and rename High Fidelity folder as a temporary folder --- tools/nitpick/src/TestRunner.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index c7823ba751..30aad70f5f 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -336,16 +336,18 @@ void TestRunner::saveExistingHighFidelityAppDataFolder() { QString dataDirectory{ "NOT FOUND" }; dataDirectory = qgetenv("USERPROFILE") + "\\AppData\\Roaming"; - +#elif defined Q_OS_MAC + QString dataDirectory{ QDir::homePath() + "/Library/Application Support" }; +#endif if (_runLatest->isChecked()) { - _appDataFolder = dataDirectory + "\\High Fidelity"; + _appDataFolder = dataDirectory + "/High Fidelity"; } else { // We are running a PR build - _appDataFolder = dataDirectory + "\\High Fidelity - " + getPRNumberFromURL(_url->text()); + _appDataFolder = dataDirectory + "/High Fidelity - " + getPRNumberFromURL(_url->text()); } _savedAppDataFolder = dataDirectory + "/" + UNIQUE_FOLDER_NAME; - if (_savedAppDataFolder.exists()) { + if (QDir(_savedAppDataFolder).exists()) { _savedAppDataFolder.removeRecursively(); } @@ -356,9 +358,6 @@ void TestRunner::saveExistingHighFidelityAppDataFolder() { // Copy an "empty" AppData folder (i.e. no entities) copyFolder(QDir::currentPath() + "/AppDataHighFidelity", _appDataFolder.path()); -#elif defined Q_OS_MAC - // TODO: find Mac equivalent of AppData -#endif } void TestRunner::createSnapshotFolder() { From 4ef54cd4f277e43bcbc355a87f8019da617266e9 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 17:45:37 -0800 Subject: [PATCH 07/46] Tests run without Interface crashing. --- tools/nitpick/src/TestRunner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 30aad70f5f..0a5002d02d 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -350,7 +350,6 @@ void TestRunner::saveExistingHighFidelityAppDataFolder() { if (QDir(_savedAppDataFolder).exists()) { _savedAppDataFolder.removeRecursively(); } - if (_appDataFolder.exists()) { // The original folder is saved in a unique name _appDataFolder.rename(_appDataFolder.path(), _savedAppDataFolder.path()); From 4c0f8b176b72ba0e66c0f50510d4fba0b4a67388 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 19:59:43 -0800 Subject: [PATCH 08/46] No need for this after implementation of AppData on Mac. --- tools/nitpick/src/TestRunner.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 0a5002d02d..9549dedb91 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -467,12 +467,7 @@ void TestRunner::runInterfaceWithTestScript() { // Move to an empty area url = "file:///~serverless/tutorial.json"; } else { -#ifdef Q_OS_WIN url = "hifi://localhost"; -#elif defined Q_OS_MAC - // TODO: Find out Mac equivalent of AppData, then this won't be needed - url = "hifi://localhost/9999,9999,9999"; -#endif } QString testScript = From eb2533d22418f0fc24b3f37f685d7235b2ae26fc Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 20:51:20 -0800 Subject: [PATCH 09/46] Updated CMake file to include the AppData folder --- tools/nitpick/CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/nitpick/CMakeLists.txt b/tools/nitpick/CMakeLists.txt index 543b9c9b47..efb5125f69 100644 --- a/tools/nitpick/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -50,10 +50,12 @@ if (WIN32) ) # add a custom command to copy the empty Apps/Data High Fidelity folder (i.e. - a valid folder with no entities) + # this also copied to the containing folder, to facilitate running from Visual Studio add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "$/AppDataHighFidelity" + COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "AppDataHighFidelity" ) # add a custom command to copy the SSL DLLs @@ -62,5 +64,12 @@ if (WIN32) POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "$ENV{VCPKG_ROOT}/installed/x64-windows/bin" "$" ) +elseif (APPLE) + # add a custom command to copy the empty Apps/Data High Fidelity folder (i.e. - a valid folder with no entities) + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "$/AppDataHighFidelity" + ) +endif () -endif () \ No newline at end of file From 2b71a82e4e59b853800a705f623744372d275d2a Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 20 Nov 2018 20:52:13 -0800 Subject: [PATCH 10/46] Updated to v1.1 --- tools/nitpick/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index dce3880123..e325be1f40 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -35,8 +35,8 @@ These steps assume the hifi repository has been cloned to `~/hifi`. 1. Change the loader instruction to find the dynamic library locally `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` 1. Delete any existing installer: `rm nitpick.dmg` -1. Create installer (note final period): `create-dmg --volname nitpick-installer-v1.0 nitpick-installer-v1.0.dmg .` -1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.0.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.0.dmg` +1. Create installer (note final period): `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` +1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` ### Installation #### Windows 1. (First time) download and install vc_redist.x64.exe (available at https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.0.exe) From 1e746e1b1c85233dcdf450250385e065ca76b799 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Nov 2018 16:43:13 -0800 Subject: [PATCH 11/46] Swap key light directions in Create --- scripts/system/html/js/entityProperties.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 78e3cd4dc8..ce6fabd0c5 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -197,7 +197,7 @@ const GROUPS = [ multiplier: DEGREES_TO_RADIANS, decimals: 2, unit: "deg", - propertyID: "keyLight.direction.x", + propertyID: "keyLight.direction.y", showPropertyRule: { "keyLightMode": "enabled" }, }, { @@ -206,7 +206,7 @@ const GROUPS = [ multiplier: DEGREES_TO_RADIANS, decimals: 2, unit: "deg", - propertyID: "keyLight.direction.y", + propertyID: "keyLight.direction.x", showPropertyRule: { "keyLightMode": "enabled" }, }, { From 1362e7f3613949ea967b87306ed231bd5c0076b3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 24 Nov 2018 08:26:54 +1300 Subject: [PATCH 12/46] Fix near parent grab entity tear away distance calc --- .../controllerModules/nearParentGrabEntity.js | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index f354067a77..e5d3b055bc 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -24,15 +24,6 @@ Script.include("/~/system/libraries/controllers.js"); // XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; // XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC; - // this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378 - var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral - - function getGrabOffset(handController) { - var offset = getGrabPointSphereOffset(handController, true); - offset.y = -offset.y; - return Vec3.multiply(MyAvatar.sensorToWorldScale, offset); - } - function NearParentingGrabEntity(hand) { this.hand = hand; this.targetEntityID = null; @@ -178,8 +169,10 @@ Script.include("/~/system/libraries/controllers.js"); this.lastUnequipCheckTime = now; if (props.parentID === MyAvatar.SELF_ID) { var tearAwayDistance = TEAR_AWAY_DISTANCE * MyAvatar.sensorToWorldScale; - var controllerIndex = (this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand); - var controllerGrabOffset = getGrabOffset(controllerIndex); + var controllerIndex = + this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand; + var controllerGrabOffset = getGrabPointSphereOffset(controllerIndex, true); + controllerGrabOffset = Vec3.multiply(-1, controllerGrabOffset); var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset); if (distance > tearAwayDistance) { this.autoUnequipCounter++; @@ -242,13 +235,15 @@ Script.include("/~/system/libraries/controllers.js"); // nearbyEntityProperties is already sorted by length from controller var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; var sensorScaleFactor = MyAvatar.sensorToWorldScale; + var tearAwayDistance = TEAR_AWAY_DISTANCE * sensorScaleFactor; + var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor; for (var i = 0; i < nearbyEntityProperties.length; i++) { var props = nearbyEntityProperties[i]; - var handPosition = controllerData.controllerLocations[this.hand].position; - var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props); - var distance = Vec3.distance(handPosition, props.position); - if ((dist > TEAR_AWAY_DISTANCE) || - (distance > NEAR_GRAB_RADIUS * sensorScaleFactor)) { + var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position. + var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props); + var distance = Vec3.distance(grabPosition, props.position); + if ((dist > tearAwayDistance) || + (distance > nearGrabRadius)) { // Only smallish entities can be near grabbed. continue; } if (entityIsGrabbable(props) || entityIsCloneable(props)) { From f1dad3c465b3bcc07605470db8a6a75fca168733 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 24 Nov 2018 08:35:02 +1300 Subject: [PATCH 13/46] Add hystersis between near parent grabbing and tearing away --- .../controllers/controllerModules/nearParentGrabEntity.js | 7 ++++--- scripts/system/libraries/controllerDispatcherUtils.js | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index e5d3b055bc..db10fff69a 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -12,7 +12,8 @@ findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME, TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity, - distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES + distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES, + NEAR_GRAB_DISTANCE */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -235,14 +236,14 @@ Script.include("/~/system/libraries/controllers.js"); // nearbyEntityProperties is already sorted by length from controller var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; var sensorScaleFactor = MyAvatar.sensorToWorldScale; - var tearAwayDistance = TEAR_AWAY_DISTANCE * sensorScaleFactor; + var nearGrabDistance = NEAR_GRAB_DISTANCE * sensorScaleFactor; var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor; for (var i = 0; i < nearbyEntityProperties.length; i++) { var props = nearbyEntityProperties[i]; var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position. var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props); var distance = Vec3.distance(grabPosition, props.position); - if ((dist > tearAwayDistance) || + if ((dist > nearGrabDistance) || (distance > nearGrabRadius)) { // Only smallish entities can be near grabbed. continue; } diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index e9d5255d28..ab2801087e 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -53,6 +53,7 @@ TEAR_AWAY_DISTANCE:true, TEAR_AWAY_COUNT:true, TEAR_AWAY_CHECK_TIME:true, + NEAR_GRAB_DISTANCE: true, distanceBetweenPointAndEntityBoundingBox:true, entityIsEquipped:true, entityIsFarGrabbedByOther:true, @@ -99,6 +100,10 @@ NEAR_GRAB_RADIUS = 1.0; TEAR_AWAY_DISTANCE = 0.15; // ungrab an entity if its bounding-box moves this far from the hand TEAR_AWAY_COUNT = 2; // multiply by TEAR_AWAY_CHECK_TIME to know how long the item must be away TEAR_AWAY_CHECK_TIME = 0.15; // seconds, duration between checks + +NEAR_GRAB_DISTANCE = 0.14; // Grab an entity if its bounding box is within this distance. +// Smaller than TEAR_AWAY_DISTANCE for hysteresis. + DISPATCHER_HOVERING_LIST = "dispactherHoveringList"; DISPATCHER_HOVERING_STYLE = { isOutlineSmooth: true, From 29c268df5ae0e4c9bf03543d9b96047da74f8490 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 24 Nov 2018 11:38:54 +1300 Subject: [PATCH 14/46] Remove extraneous grab entity haptic pulses --- .../controllers/controllerModules/farParentGrabEntity.js | 6 ------ .../controllerModules/nearActionGrabEntity.js | 7 ------- .../controllerModules/nearParentGrabEntity.js | 9 --------- 3 files changed, 22 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index f85869aa7f..4b85c6d046 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -256,7 +256,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.endFarParentGrab = function (controllerData) { - this.hapticTargetID = null; // var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (this.thisFarGrabJointIsParent(endProps)) { @@ -410,11 +409,6 @@ Script.include("/~/system/libraries/controllers.js"); if (targetEntity) { var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); if (entityIsGrabbable(gtProps)) { - // give haptic feedback - if (gtProps.id !== this.hapticTargetID) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.hapticTargetID = gtProps.id; - } // if we've attempted to grab a child, roll up to the root of the tree var groupRootProps = findGroupParent(controllerData, gtProps); if (entityIsGrabbable(groupRootProps)) { diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index 5ced6080a2..1d1f89e2c7 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -24,7 +24,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.hand = hand; this.targetEntityID = null; this.actionID = null; // action this script created... - this.hapticTargetID = null; this.parameters = makeDispatcherModuleParameters( 500, @@ -171,10 +170,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); break; } if (entityIsGrabbable(props) || entityIsCloneable(props)) { - if (props.id !== this.hapticTargetID) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.hapticTargetID = props.id; - } if (!entityIsCloneable(props)) { // if we've attempted to grab a non-cloneable child, roll up to the root of the tree var groupRootProps = findGroupParent(controllerData, props); @@ -206,7 +201,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); return makeRunningValues(true, [this.targetEntityID], []); } } else { - this.hapticTargetID = null; return makeRunningValues(false, [], []); } }; @@ -216,7 +210,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { this.endNearGrabAction(); - this.hapticTargetID = null; return makeRunningValues(false, [], []); } diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index db10fff69a..3be6f602c2 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -32,7 +32,6 @@ Script.include("/~/system/libraries/controllers.js"); this.previousParentID = {}; this.previousParentJointIndex = {}; this.previouslyUnhooked = {}; - this.hapticTargetID = null; this.lastUnequipCheckTime = 0; this.autoUnequipCounter = 0; this.lastUnexpectedChildrenCheckTime = 0; @@ -138,7 +137,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.endNearParentingGrabEntity = function (controllerData) { - this.hapticTargetID = null; var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; if (this.thisHandIsParent(props) && !this.robbed) { Entities.editEntity(this.targetEntityID, { @@ -248,11 +246,6 @@ Script.include("/~/system/libraries/controllers.js"); continue; } if (entityIsGrabbable(props) || entityIsCloneable(props)) { - // give haptic feedback - if (props.id !== this.hapticTargetID) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.hapticTargetID = props.id; - } if (!entityIsCloneable(props)) { // if we've attempted to grab a non-cloneable child, roll up to the root of the tree var groupRootProps = findGroupParent(controllerData, props); @@ -295,7 +288,6 @@ Script.include("/~/system/libraries/controllers.js"); unhighlightTargetEntity(this.highlightedEntity); this.highlightedEntity = null; } - this.hapticTargetID = null; this.robbed = false; return makeRunningValues(false, [], []); } @@ -316,7 +308,6 @@ Script.include("/~/system/libraries/controllers.js"); this.highlightedEntity = null; this.grabbing = false; this.targetEntityID = null; - this.hapticTargetID = null; this.robbed = false; return makeRunningValues(false, [], []); } From f2abf8e398a733fbe804c1168b6011cf5095abbc Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 24 Nov 2018 11:43:05 +1300 Subject: [PATCH 15/46] Debounce haptic pulses at start of near parent grab --- .../controllerModules/farParentGrabEntity.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index 4b85c6d046..230c4f06db 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -61,6 +61,8 @@ Script.include("/~/system/libraries/controllers.js"); this.reticleMinY = MARGIN; this.reticleMaxY = 0; this.lastUnexpectedChildrenCheckTime = 0; + this.endedGrab = 0; + this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX @@ -144,7 +146,12 @@ Script.include("/~/system/libraries/controllers.js"); // compute the mass for the purpose of energy and how quickly to move object this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density); - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + // Debounce haptic pules. Can occur as near grab controller module vacillates between being ready or not due to + // changing positions and floating point rounding. + if (Date.now() - this.endedGrab > this.MIN_HAPTIC_PULSE_INTERVAL) { + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + } + unhighlightTargetEntity(this.targetEntityID); var message = { hand: this.hand, @@ -256,6 +263,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.endFarParentGrab = function (controllerData) { + this.endedGrab = Date.now(); // var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (this.thisFarGrabJointIsParent(endProps)) { From c96cd422e186180dde2b2ce95e4e2059ad38ad66 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 24 Nov 2018 11:58:40 +1300 Subject: [PATCH 16/46] Fix near parent grab tear away calc for avatar scale --- .../controllers/controllerModules/nearParentGrabEntity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 3be6f602c2..433ad9ef53 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -171,7 +171,7 @@ Script.include("/~/system/libraries/controllers.js"); var controllerIndex = this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand; var controllerGrabOffset = getGrabPointSphereOffset(controllerIndex, true); - controllerGrabOffset = Vec3.multiply(-1, controllerGrabOffset); + controllerGrabOffset = Vec3.multiply(-MyAvatar.sensorToWorldScale, controllerGrabOffset); var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset); if (distance > tearAwayDistance) { this.autoUnequipCounter++; From b3f646e9dc1fe3833e99325545ad1cb710498b80 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 24 Nov 2018 09:44:46 -0800 Subject: [PATCH 17/46] Updated to v1.1 --- tools/nitpick/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index e325be1f40..ce65fec64f 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -24,7 +24,7 @@ Nitpick is built as part of the High Fidelity build. 1. Check "Create SFX archive 1. Enter installer name (i.e. `nitpick-installer-v1.0.exe`) 1. Click "OK" -1. Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.0.exe: aws s3 cp nitpick-installer-v1.0.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.0.exe +1. Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe: aws s3 cp nitpick-installer-v1.0.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.0.exe #### Mac These steps assume the hifi repository has been cloned to `~/hifi`. 1. (First time) install create-dmg: @@ -49,7 +49,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`. 1. Leave region name and ouput format as default [None] 1. Install the latest release of Boto3 via pip: `pip install boto3` -1. Download the installer by browsing to [here]() +1. Download the installer by browsing to [here]() 1. Double click on the installer and install to a convenient location ![](./setup_7z.PNG) @@ -69,7 +69,7 @@ $ python3 get-pip.py --user 1. Enter the secret key 1. Leave region name and ouput format as default [None] 1. Install the latest release of Boto3 via pip: pip3 install boto3 -1. Download the installer by browsing to [here](). +1. Download the installer by browsing to [here](). 1. Double-click on the downloaded image to mount it 1. Create a folder for the nitpick files (e.g. ~/nitpick) 1. Copy the downloaded files to the folder From f62fd97f09a7be1fa52984da8bb01f7865039ee9 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 24 Nov 2018 09:49:13 -0800 Subject: [PATCH 18/46] Updated to v1.1 --- tools/nitpick/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index ce65fec64f..78b4866880 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -22,9 +22,9 @@ Nitpick is built as part of the High Fidelity build. 1. Select all, right-click and select 7-Zip->Add to archive... 1. Set Archive format to 7z 1. Check "Create SFX archive -1. Enter installer name (i.e. `nitpick-installer-v1.0.exe`) +1. Enter installer name (i.e. `nitpick-installer-v1.1.exe`) 1. Click "OK" -1. Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe: aws s3 cp nitpick-installer-v1.0.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.0.exe +1. Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe: aws s3 cp nitpick-installer-v1.1.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.exe #### Mac These steps assume the hifi repository has been cloned to `~/hifi`. 1. (First time) install create-dmg: @@ -39,7 +39,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`. 1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` ### Installation #### Windows -1. (First time) download and install vc_redist.x64.exe (available at https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.0.exe) +1. (First time) download and install vc_redist.x64.exe (available at https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe) 1. (First time) download and install Python 3 from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/python-3.7.0-amd64.exe (also located at https://www.python.org/downloads/) 1. After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. 1. (First time) download and install AWS CLI from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/AWSCLI64PY3.msi (also available at https://aws.amazon.com/cli/ @@ -72,8 +72,9 @@ $ python3 get-pip.py --user 1. Download the installer by browsing to [here](). 1. Double-click on the downloaded image to mount it 1. Create a folder for the nitpick files (e.g. ~/nitpick) + If this folder exists then delete all it's contents. 1. Copy the downloaded files to the folder - `cp -r /Volumes/nitpick-installer-v1.0/* .` + `cp -r /Volumes/nitpick-installer-v1.1/* .` 1. __To run nitpick, cd to the folder that you copied to and run `./nitpick`__ #Use From bbbc358ccbfa31668ad2249f299f4e4326a4e850 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 24 Nov 2018 20:31:19 -0800 Subject: [PATCH 19/46] Restore AppData folder on Mac --- tools/nitpick/src/TestRunner.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 9549dedb91..30740bd28a 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -582,15 +582,11 @@ void TestRunner::addBuildNumberToResults(QString zippedFolderName) { } void TestRunner::restoreHighFidelityAppDataFolder() { -#ifdef Q_OS_WIN _appDataFolder.removeRecursively(); if (_savedAppDataFolder != QDir()) { _appDataFolder.rename(_savedAppDataFolder.path(), _appDataFolder.path()); } -#elif defined Q_OS_MAC - // TODO: find Mac equivalent of AppData -#endif } // Copies a folder recursively From 26319e6d6fbd04e4e3ec5f3163b574601ded6556 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 24 Nov 2018 20:37:21 -0800 Subject: [PATCH 20/46] Remove all disk images --- tools/nitpick/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index 78b4866880..bdea4eb059 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -34,7 +34,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`. `cp ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib .` 1. Change the loader instruction to find the dynamic library locally `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` -1. Delete any existing installer: `rm nitpick.dmg` +1. Delete any existing disk images: `rm *.dmg` 1. Create installer (note final period): `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` 1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` ### Installation From e173b2968739e50e5ae7569b2a04ee283d6deebc Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 24 Nov 2018 20:43:13 -0800 Subject: [PATCH 21/46] Added warning --- tools/nitpick/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index bdea4eb059..ae8821c6be 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -36,6 +36,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`. `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` 1. Delete any existing disk images: `rm *.dmg` 1. Create installer (note final period): `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` + Make sure to wait for completion. 1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` ### Installation #### Windows From 6313ab8ed7d610dd269a45cd03589f1eb0d13f19 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sun, 25 Nov 2018 20:10:01 -0800 Subject: [PATCH 22/46] Working on possible crash on Mac. --- tools/nitpick/src/Downloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nitpick/src/Downloader.cpp b/tools/nitpick/src/Downloader.cpp index de768398b0..3256e79601 100644 --- a/tools/nitpick/src/Downloader.cpp +++ b/tools/nitpick/src/Downloader.cpp @@ -12,12 +12,12 @@ #include Downloader::Downloader(QUrl fileURL, QObject *parent) : QObject(parent) { + _networkAccessManager.get(QNetworkRequest(fileURL)); + connect( &_networkAccessManager, SIGNAL (finished(QNetworkReply*)), this, SLOT (fileDownloaded(QNetworkReply*)) ); - - _networkAccessManager.get(QNetworkRequest(fileURL)); } void Downloader::fileDownloaded(QNetworkReply* reply) { From 2913d4f9841fd6ebd5f32767598b41d9b1700952 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 08:25:07 -0800 Subject: [PATCH 23/46] Removed baaaaaad file. --- .../domain-server/AccountInfo.bin | Bin 1450 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin diff --git a/tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin b/tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin deleted file mode 100644 index 645e34895e5c2ae38571d19a60c21df84c880b12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1450 zcmaiuX*d)J9EbliWDyXqirx)88es;s{=7|CAKh> zBjk=;YebG7Q;j3-rehG<dt}>pTS1HE7EiYrSuWTvl;>I*HM&!jW zQF^;JC>UK&QL*QLl`~)>=6uz{euwwhQzNZxEK;lngD; zU}IlZ50Qdg_G#^+%-96}TyTChjkG3Sd77^{k@e0kQ(4Vxx>j52LE7599bdxF^k7DC zL5aEuJBJc_m)W{@eN^tj=SuDz_M?2p)e*;LO>w4!y3seywe_dxv279TT=%hO`%1;5 z{QQ#%I0aWS>(pnJ*3z}%xqBAZ`3?8BF4)LzUfSWZr(J$tuRjrbnu*w0=UIH%uL%u8 zTJ24?;^qZs|KOw=lD|QUx^(Nu{G?E%1OgDq1O$*eFUT-cx9jFeelbfGK9Q;n+!Q=1 zyksC@q2k6^sd9bIQJz);%J95I*2a;-KKXRp)YhJIGT%UBQQ?v73k+sD(dFr<+YJ@Z z&X)hCsJeToSbv17bEHO*+b`&D>^0#vN69K{$S^HZTcC%xXyLLJD_qe%QMX8>S#Qp@FLf+ z$qKKOuD6C(v}Rq&Rm@Sn!?W#d@h}#UksJ=pkd9>2H6{`|JOjp1VFxw23<)Qv80!#H zT$J0or(#;Cv?!D>lvA(kyVx@Mruf$Eg+ZJpt+<7UkaYKOU#9BuN_Q!9G3Ub5K6E51 zi;hcwDzrX!;MeCSEstp$sWH}SdYO%&{m!qp61Q6a@E-F?-n#0rp1_BnuOjUkXRG?H zVaRw(ToHHKP~`iFnm8+U$bl_TX)M)$sK(Oic=w@YHtc>V-$HVdOl%jOAOv=MemJ~_ z=>3~m7c6#ey&p#ky^*0^_2Mep!pfJYULMd?LW@nD&CpK#g3eDS$YX~@<3DCxdY?pP z2k$-^cLa5?GpQ8fpx%qFpMh~w+*RRSqWwZc3)4Ri4vk#5HwOsYT!ua+Uk<=oRf zEt__XDpen1TCzwTnbhn}QWBU!IY~P)v9tu|wbgL*(zdz`rnV<)KIack!@U0#8OdQI z343_VBs0Ct9k!8@?=|YZ<>E7v&$s(eZa@W7-WM1pUd6BR2auc!{$8zgVqK7hZ}ZdE zuZx=Fbq@A_!LW%^>de**+TrNI7M$x)$MczObLpX%@9R1n7Rn~8KYDx3`1%FPVWC3u zK@D`WW0gM3-rR1q2-`a3fa{$Yi?2J5&3FNvYH}2YGpJ< z?$-5)<(3e)O-1K7CaKDx5MG}rYGh10w3pSnr*!4hzQ2PzQ20s_DSC}0U@fCoAR00n*mQ!oQ_pa32$ Qfed)SeP24@fdT>l0D=~Uga7~l From 48fabf51f2847359320b4e9d2ba4ac6f58ccd4ac Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 08:54:09 -0800 Subject: [PATCH 24/46] Corrected Linux compilation error. --- tools/nitpick/src/TestRunner.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 30740bd28a..65358a0c3d 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -332,12 +332,11 @@ void TestRunner::verifyInstallationSucceeded() { } void TestRunner::saveExistingHighFidelityAppDataFolder() { -#ifdef Q_OS_WIN QString dataDirectory{ "NOT FOUND" }; - +#ifdef Q_OS_WIN dataDirectory = qgetenv("USERPROFILE") + "\\AppData\\Roaming"; #elif defined Q_OS_MAC - QString dataDirectory{ QDir::homePath() + "/Library/Application Support" }; + dataDirectory{ QDir::homePath() + "/Library/Application Support" }; #endif if (_runLatest->isChecked()) { _appDataFolder = dataDirectory + "/High Fidelity"; From a6e203e3e5a58f31e12a57827dd0575dfe8ba0ee Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 26 Nov 2018 10:55:42 -0800 Subject: [PATCH 25/46] Fix draggable inputs not being tabbable --- scripts/system/html/css/edit-style.css | 11 ++++---- scripts/system/html/js/draggableNumber.js | 32 ++++++++++++++++------ scripts/system/html/js/entityProperties.js | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 5b5c9e057c..415d8e567f 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -916,7 +916,7 @@ div.refresh input[type="button"] { } .draggable-number div { height: 28px; - width: 92px; + width: 124px; } .draggable-number.text { display: inline-block; @@ -929,6 +929,7 @@ div.refresh input[type="button"] { height: 28px; width: 100%; line-height: 2; + box-sizing: border-box; } .draggable-number.text:hover { cursor: ew-resize; @@ -944,12 +945,12 @@ div.refresh input[type="button"] { cursor: default; } .draggable-number.left-arrow { - top: -5px; + top: 3px; left: 0px; transform: rotate(180deg); } .draggable-number.right-arrow { - top: -5px; + top: 3px; right: 0px; } .draggable-number input[type=number] { @@ -971,14 +972,14 @@ div.refresh input[type="button"] { left: 12px; } .draggable-number.fstuple + .draggable-number.fstuple { - padding-left: 28px; + margin-left: 28px; } .draggable-number.fstuple input { right: -10px; } .draggable-number.fstuple .sublabel { position: absolute; - top: 0; + top: 6px; left: -16px; font-family: FiraSans-SemiBold; font-size: 15px; diff --git a/scripts/system/html/js/draggableNumber.js b/scripts/system/html/js/draggableNumber.js index c08cac2ce4..951b123e67 100644 --- a/scripts/system/html/js/draggableNumber.js +++ b/scripts/system/html/js/draggableNumber.js @@ -23,6 +23,20 @@ function DraggableNumber(min, max, step, decimals, dragStart, dragEnd) { } DraggableNumber.prototype = { + showInput: function() { + this.elText.style.visibility = "hidden"; + this.elLeftArrow.style.visibility = "hidden"; + this.elRightArrow.style.visibility = "hidden"; + this.elInput.style.opacity = 1; + }, + + hideInput: function() { + this.elText.style.visibility = "visible"; + this.elLeftArrow.style.visibility = "visible"; + this.elRightArrow.style.visibility = "visible"; + this.elInput.style.opacity = 0; + }, + mouseDown: function(event) { if (event.target === this.elText) { this.initialMouseEvent = event; @@ -36,8 +50,8 @@ DraggableNumber.prototype = { if (event.target === this.elText && this.initialMouseEvent) { let dx = event.clientX - this.initialMouseEvent.clientX; if (Math.abs(dx) <= DELTA_X_FOCUS_THRESHOLD) { - this.elInput.style.visibility = "visible"; - this.elText.style.visibility = "hidden"; + this.showInput(); + this.elInput.focus(); } this.initialMouseEvent = null; } @@ -125,9 +139,8 @@ DraggableNumber.prototype = { this.setValue(this.elInput.value); }, - inputBlur: function() { - this.elInput.style.visibility = "hidden"; - this.elText.style.visibility = "visible"; + inputBlur: function(ev) { + this.hideInput(); }, initialize: function() { @@ -171,13 +184,14 @@ DraggableNumber.prototype = { if (this.step !== undefined) { this.elInput.setAttribute("step", this.step); } - this.elInput.style.visibility = "hidden"; + this.elInput.style.opacity = 0; this.elInput.addEventListener("change", this.onInputChange); this.elInput.addEventListener("blur", this.onInputBlur); + this.elInput.addEventListener("focus", this.showInput.bind(this)); - this.elText.appendChild(this.elLeftArrow); - this.elText.appendChild(this.elInput); - this.elText.appendChild(this.elRightArrow); + this.elDiv.appendChild(this.elLeftArrow); + this.elDiv.appendChild(this.elInput); + this.elDiv.appendChild(this.elRightArrow); this.elDiv.appendChild(this.elText); } }; diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 78e3cd4dc8..786df503df 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -2149,7 +2149,7 @@ function createTupleNumberInput(property, subLabel) { propertyData.decimals, dragStartFunction, dragEndFunction); elDraggableNumber.elInput.setAttribute("id", elementID); elDraggableNumber.elDiv.className += " fstuple"; - elDraggableNumber.elText.insertBefore(elLabel, elDraggableNumber.elLeftArrow); + elDraggableNumber.elDiv.insertBefore(elLabel, elDraggableNumber.elLeftArrow); return elDraggableNumber; } From e943504f608f5cb2d9129d3156be6c8441e65b5d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 15:59:08 -0800 Subject: [PATCH 26/46] Updated README.md --- tools/nitpick/README.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index ae8821c6be..fe027be227 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -12,7 +12,7 @@ Nitpick has 5 functions, separated into 4 tabs: 1. Evaluating the results of running tests 1. Web interface -## Build +## Build (for developers) Nitpick is built as part of the High Fidelity build. ### Creating installers #### Windows @@ -27,15 +27,17 @@ Nitpick is built as part of the High Fidelity build. 1. Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe: aws s3 cp nitpick-installer-v1.1.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.exe #### Mac These steps assume the hifi repository has been cloned to `~/hifi`. +1. (first time) Install brew + In a terminal: `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)` 1. (First time) install create-dmg: - `brew install create-dmg` -1. cd to the `build/tools/nitpick/Release` folder + In a terminal: `brew install create-dmg` +1. In a terminal: cd to the `build/tools/nitpick/Release` folder 1. Copy the quazip dynamic library (note final period): - `cp ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib .` + In a terminal: `cp ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib .` 1. Change the loader instruction to find the dynamic library locally - `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` -1. Delete any existing disk images: `rm *.dmg` -1. Create installer (note final period): `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` + In a terminal: `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` +1. Delete any existing disk images. In a terminal: `rm *.dmg` +1. Create installer (note final period).In a terminal: `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` Make sure to wait for completion. 1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` ### Installation @@ -56,16 +58,20 @@ These steps assume the hifi repository has been cloned to `~/hifi`. 1. __To run nitpick, double click **nitpick.exe**__ #### Mac +1. (first time) Install brew + In a terminal: `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)` +1. (First time) install Qt: + In a terminal: `brew install qt` 1. (First time) install Python from https://www.python.org/downloads/release/python-370/ (**macOS 64-bit installer** or **macOS 64-bit/32-bit installer**) - 1. After installation - run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. + 1. After installation - In a terminal: run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. 1. Verify that `/usr/local/bin/python3` exists. 1. (First time - AWS interface) Install pip with the script provided by the Python Packaging Authority: -$ curl -O https://bootstrap.pypa.io/get-pip.py -$ python3 get-pip.py --user +In a terminal: `curl -O https://bootstrap.pypa.io/get-pip.py` +In a terminal: `python3 get-pip.py --user` 1. Use pip to install the AWS CLI. - $ pip3 install awscli --upgrade --user + `pip3 install awscli --upgrade --user` This will install aws in your user. For user XXX, aws will be located in ~/Library/Python/3.7/bin - 1. Open a new command prompt and run `aws configure` + 1. Open a new command prompt and run `~/Library/Python/3.7/bin/aws configure` 1. Enter the AWS account number 1. Enter the secret key 1. Leave region name and ouput format as default [None] @@ -75,9 +81,11 @@ $ python3 get-pip.py --user 1. Create a folder for the nitpick files (e.g. ~/nitpick) If this folder exists then delete all it's contents. 1. Copy the downloaded files to the folder - `cp -r /Volumes/nitpick-installer-v1.1/* .` + In a terminal: + `cd ~/nitpick` + `cp -r /Volumes/nitpick-installer-v1.1/* .` -1. __To run nitpick, cd to the folder that you copied to and run `./nitpick`__ +1. __To run nitpick, cd to the folder that you copied to and run `./nitpick`__ #Use ## Create ![](./Create.PNG) From c211dc363b4d41fbef1d729ff04441fbef295a9b Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 16:05:49 -0800 Subject: [PATCH 27/46] Updated README.md --- tools/nitpick/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index fe027be227..319d374a5d 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -86,7 +86,7 @@ In a terminal: `python3 get-pip.py --user` `cp -r /Volumes/nitpick-installer-v1.1/* .` 1. __To run nitpick, cd to the folder that you copied to and run `./nitpick`__ -#Use +# Usage ## Create ![](./Create.PNG) From e7ab7094cd1acf473969e89283c87c567b4683e9 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 16:42:48 -0800 Subject: [PATCH 28/46] Kill Hifi processes after evaluation. --- tools/nitpick/src/TestRunner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 30740bd28a..e3b8adca28 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -528,8 +528,6 @@ void TestRunner::runInterfaceWithTestScript() { } void TestRunner::interfaceExecutionComplete() { - killProcesses(); - QFileInfo testCompleted(QDir::toNativeSeparators(_snapshotFolder) +"/tests_completed.txt"); if (!testCompleted.exists()) { QMessageBox::critical(0, "Tests not completed", "Interface seems to have crashed before completion of the test scripts\nExisting images will be evaluated"); @@ -537,6 +535,8 @@ void TestRunner::interfaceExecutionComplete() { evaluateResults(); + killProcesses(); + // The High Fidelity AppData folder will be restored after evaluation has completed } From 5da6ecad121ee1111115e5109b9c3b1db1c199ea Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 18:10:14 -0800 Subject: [PATCH 29/46] Compilation error. --- tools/nitpick/src/TestRunner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 7c2dfda1cd..12bdf87495 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -336,7 +336,7 @@ void TestRunner::saveExistingHighFidelityAppDataFolder() { #ifdef Q_OS_WIN dataDirectory = qgetenv("USERPROFILE") + "\\AppData\\Roaming"; #elif defined Q_OS_MAC - dataDirectory{ QDir::homePath() + "/Library/Application Support" }; + dataDirectory = QDir::homePath() + "/Library/Application Support"; #endif if (_runLatest->isChecked()) { _appDataFolder = dataDirectory + "/High Fidelity"; From aed947cb0a65ff3006054485503fe616fc45d4b1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 26 Nov 2018 18:10:41 -0800 Subject: [PATCH 30/46] Minor cleanup. --- tools/nitpick/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index 319d374a5d..a02980ddfe 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -37,7 +37,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`. 1. Change the loader instruction to find the dynamic library locally In a terminal: `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` 1. Delete any existing disk images. In a terminal: `rm *.dmg` -1. Create installer (note final period).In a terminal: `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` +1. Create installer (note final period).In a terminal: `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` Make sure to wait for completion. 1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` ### Installation From 9cc896c4a884c6feaa7584560b30ee7f7bd92c6f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 20 Nov 2018 09:13:07 -0800 Subject: [PATCH 31/46] fixing keyboard mallets dimensions --- interface/src/ui/Keyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 6852691634..46a25a24a7 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -60,7 +60,7 @@ static const float MALLET_TOUCH_Y_OFFSET = 0.050f; static const float MALLET_Y_OFFSET = 0.160f; static const glm::quat MALLET_ROTATION_OFFSET{0.70710678f, 0.0f, -0.70710678f, 0.0f}; -static const glm::vec3 MALLET_MODEL_DIMENSIONS{0.03f, MALLET_LENGTH, 0.03f}; +static const glm::vec3 MALLET_MODEL_DIMENSIONS{0.01f, MALLET_LENGTH, 0.01f}; static const glm::vec3 MALLET_POSITION_OFFSET{0.0f, -MALLET_Y_OFFSET / 2.0f, 0.0f}; static const glm::vec3 MALLET_TIP_OFFSET{0.0f, MALLET_LENGTH - MALLET_TOUCH_Y_OFFSET, 0.0f}; From 29028386c8a60abebac6248ba6b1911a87f35d65 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 27 Nov 2018 11:56:07 -0800 Subject: [PATCH 32/46] Keyboard menu option in general settings --- interface/resources/qml/controlsUit/Keyboard.qml | 4 ++-- interface/src/Menu.cpp | 2 -- interface/src/Menu.h | 1 - .../src/scripting/KeyboardScriptingInterface.cpp | 4 ++++ interface/src/scripting/KeyboardScriptingInterface.h | 3 +++ interface/src/ui/Keyboard.cpp | 11 +++++++++++ interface/src/ui/Keyboard.h | 7 +++++++ interface/src/ui/PreferencesDialog.cpp | 7 +++++++ 8 files changed, 34 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/controlsUit/Keyboard.qml b/interface/resources/qml/controlsUit/Keyboard.qml index c38631ff79..a55523f34a 100644 --- a/interface/resources/qml/controlsUit/Keyboard.qml +++ b/interface/resources/qml/controlsUit/Keyboard.qml @@ -44,14 +44,14 @@ Rectangle { onPasswordChanged: { - var use3DKeyboard = (typeof MenuInterface === "undefined") ? false : MenuInterface.isOptionChecked("Use 3D Keyboard"); + var use3DKeyboard = (typeof KeyboardScriptingInterface === "undefined") ? false : KeyboardScriptingInterface.use3DKeyboard; if (use3DKeyboard) { KeyboardScriptingInterface.password = password; } } onRaisedChanged: { - var use3DKeyboard = (typeof MenuInterface === "undefined") ? false : MenuInterface.isOptionChecked("Use 3D Keyboard"); + var use3DKeyboard = (typeof KeyboardScriptingInterface === "undefined") ? false : KeyboardScriptingInterface.use3DKeyboard; if (!use3DKeyboard) { keyboardBase.height = raised ? raisedHeight : 0; keyboardBase.visible = raised; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13c622627d..e9a44b1e87 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -364,8 +364,6 @@ Menu::Menu() { qApp->setHmdTabletBecomesToolbarSetting(action->isChecked()); }); - addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::Use3DKeyboard, 0, true); - // Developer > Render >>> MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d3d9e5e674..e0e48ff32c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -213,7 +213,6 @@ namespace MenuOption { const QString TurnWithHead = "Turn using Head"; const QString UseAudioForMouth = "Use Audio for Mouth"; const QString UseCamera = "Use Camera"; - const QString Use3DKeyboard = "Use 3D Keyboard"; const QString VelocityFilter = "Velocity Filter"; const QString VisibleToEveryone = "Everyone"; const QString VisibleToFriends = "Friends"; diff --git a/interface/src/scripting/KeyboardScriptingInterface.cpp b/interface/src/scripting/KeyboardScriptingInterface.cpp index b26e1ec378..d86bb56e64 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.cpp +++ b/interface/src/scripting/KeyboardScriptingInterface.cpp @@ -32,3 +32,7 @@ void KeyboardScriptingInterface::setPassword(bool password) { void KeyboardScriptingInterface::loadKeyboardFile(const QString& keyboardFile) { DependencyManager::get()->loadKeyboardFile(keyboardFile); } + +bool KeyboardScriptingInterface::getUse3DKeyboard() { + return DependencyManager::get()->getUse3DKeyboard(); +} diff --git a/interface/src/scripting/KeyboardScriptingInterface.h b/interface/src/scripting/KeyboardScriptingInterface.h index 1ab91ea7c3..709dfe01de 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.h +++ b/interface/src/scripting/KeyboardScriptingInterface.h @@ -30,6 +30,7 @@ class KeyboardScriptingInterface : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(bool raised READ isRaised WRITE setRaised) Q_PROPERTY(bool password READ isPassword WRITE setPassword) + Q_PROPERTY(bool use3DKeyboard READ getUse3DKeyboard); public: Q_INVOKABLE void loadKeyboardFile(const QString& string); @@ -39,5 +40,7 @@ private: bool isPassword(); void setPassword(bool password); + + bool getUse3DKeyboard(); }; #endif diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 6852691634..74fd869b87 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -241,6 +241,17 @@ void Keyboard::registerKeyboardHighlighting() { selection->enableListToScene(KEY_PRESSED_HIGHLIGHT); } +bool Keyboard::getUse3DKeyboard() const { + return _use3DKeyboardLock.resultWithReadLock([&] { + return _use3DKeyboard.get(); + }); +} + +void Keyboard::setUse3DKeyboard(bool use) { + _use3DKeyboardLock.withWriteLock([&] { + _use3DKeyboard.set(use); + }); +} void Keyboard::createKeyboard() { auto pointerManager = DependencyManager::get(); diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 18db38b2ae..9c0c8c40f2 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "ui/overlays/Overlay.h" @@ -97,6 +98,9 @@ public: bool isPassword() const; void setPassword(bool password); + bool getUse3DKeyboard() const; + void setUse3DKeyboard(bool use); + void loadKeyboardFile(const QString& keyboardFile); QVector getKeysID(); @@ -143,6 +147,9 @@ private: SharedSoundPointer _keySound { nullptr }; std::shared_ptr _layerSwitchTimer { std::make_shared() }; + mutable ReadWriteLockable _use3DKeyboardLock; + Setting::Handle _use3DKeyboard { "use3DKeyboard", true }; + QString _typedCharacters; TextDisplay _textDisplay; Anchor _anchor; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 5f8b191a4f..d1fbe02759 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -24,6 +24,7 @@ #include "Snapshot.h" #include "SnapshotAnimated.h" #include "UserActivityLogger.h" +#include "ui/Keyboard.h" void setupPreferences() { auto preferences = DependencyManager::get(); @@ -119,6 +120,12 @@ void setupPreferences() { preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter)); } + { + auto getter = []()->bool { return DependencyManager::get()->getUse3DKeyboard(); }; + auto setter = [](bool value) { DependencyManager::get()->setUse3DKeyboard(value); }; + preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use Virtual Keyboard", getter, setter)); + } + { auto getter = []()->bool { return qApp->getMiniTabletEnabled(); }; auto setter = [](bool value) { qApp->setMiniTabletEnabled(value); }; From fac27553d740edacc270122e43200209a6196183 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Nov 2018 19:56:35 -0800 Subject: [PATCH 33/46] suppress 'No instance available' messages during shutdown. try a different way of shutting down AudioClient. --- interface/src/Application.cpp | 5 ++++- libraries/audio-client/src/AudioClient.cpp | 1 - libraries/shared/src/DependencyManager.h | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21af28ffcb..ed834a2cc5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2572,6 +2572,8 @@ void Application::cleanupBeforeQuit() { QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false"); qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging; + DependencyManager::prepareToExit(); + if (tracing::enabled()) { auto tracer = DependencyManager::get(); tracer->stopTracing(); @@ -2684,6 +2686,7 @@ void Application::cleanupBeforeQuit() { // destroy Audio so it and its threads have a chance to go down safely // this must happen after QML, as there are unexplained audio crashes originating in qtwebengine + QMetaObject::invokeMethod(DependencyManager::get().data(), "stop"); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -2775,7 +2778,7 @@ Application::~Application() { // quit the thread used by the closure event sender closeEventSender->thread()->quit(); - // Can't log to file passed this point, FileLogger about to be deleted + // Can't log to file past this point, FileLogger about to be deleted qInstallMessageHandler(LogHandler::verboseMessageHandler); _renderEventHandler->deleteLater(); diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 92f7a27853..9bad7e2f45 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -302,7 +302,6 @@ void AudioClient::customDeleter() { #if defined(Q_OS_ANDROID) _shouldRestartInputSetup = false; #endif - stop(); deleteLater(); } diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 978732fd50..bda1077990 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -74,6 +74,9 @@ public: #endif return hashCode; } + + static void prepareToExit() { manager()._exiting = true; } + private: static DependencyManager& manager(); @@ -84,6 +87,8 @@ private: QHash> _instanceHash; QHash _inheritanceHash; + + bool _exiting { false }; }; template @@ -95,9 +100,17 @@ QSharedPointer DependencyManager::get() { instance = qSharedPointerCast(manager().safeGet(hashCode)); #ifndef QT_NO_DEBUG + // debug builds... if (instance.isNull()) { qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name(); } +#else + // for non-debug builds, don't print "No instance available" during shutdown, because + // the act of printing this often causes crashes (because the LogHandler has-been/is-being + // deleted). + if (!manager()._exiting && instance.isNull()) { + qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name(); + } #endif } From 4effd365ed096e94d0c71077e4a1289129e1bdf5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 27 Nov 2018 17:34:17 -0800 Subject: [PATCH 34/46] Change "Autotester" to "nitpick". --- tools/nitpick/src/Test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 47458d00ee..2b862783a7 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -677,7 +677,7 @@ bool Test::createTestAutoScript(const QString& directory) { stream << "if (typeof PATH_TO_THE_REPO_PATH_UTILS_FILE === 'undefined') PATH_TO_THE_REPO_PATH_UTILS_FILE = 'https://raw.githubusercontent.com/highfidelity/hifi_tests/master/tests/utils/branchUtils.js';\n"; stream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);\n"; - stream << "var nitpick = createAutoTester(Script.resolvePath('.'));\n\n"; + stream << "var nitpick = createNitpick(Script.resolvePath('.'));\n\n"; stream << "nitpick.enableAuto();\n\n"; stream << "Script.include('./test.js?raw=true');\n"; @@ -758,7 +758,7 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact "/tests/utils/branchUtils.js\";" << endl; textStream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);" << endl; - textStream << "var nitpick = createAutoTester(Script.resolvePath(\".\"));" << endl << endl; + textStream << "var nitpick = createNitpick(Script.resolvePath(\".\"));" << endl << endl; textStream << "var testsRootPath = nitpick.getTestsRootPath();" << endl << endl; From 59a030a16f3c2b89d47b1007e959dcf052ad546d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 27 Nov 2018 17:41:00 -0800 Subject: [PATCH 35/46] Correct message to user. --- tools/nitpick/src/Test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 2b862783a7..e17978d9d0 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -620,7 +620,7 @@ void Test::createTestAutoScript() { } if (createTestAutoScript(_testDirectory)) { - QMessageBox::information(0, "Success", "'nitpick.js` script has been created"); + QMessageBox::information(0, "Success", "'testAuto.js` script has been created"); } } @@ -748,9 +748,9 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact QTextStream textStream(&allTestsFilename); - textStream << "// This is an automatically generated file, created by auto-tester" << endl; + textStream << "// This is an automatically generated file, created by nitpick" << endl; - // Include 'autoTest.js' + // Include 'nitpick.js' QString branch = nitpick->getSelectedBranch(); QString user = nitpick->getSelectedUser(); From 8be775c2b70239e0c5d046082b84b02eac3875d9 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 28 Nov 2018 10:54:39 -0800 Subject: [PATCH 36/46] don't save joint information for avatar entities --- interface/src/AvatarBookmarks.cpp | 40 +++++++++++++++++++------------ 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 534fb15d93..099171a427 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -247,25 +247,35 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { bookmark.insert(ENTRY_AVATAR_URL, avatarUrl); bookmark.insert(ENTRY_AVATAR_SCALE, avatarScale); - QScriptEngine scriptEngine; QVariantList wearableEntities; auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; - auto avatarEntities = myAvatar->getAvatarEntityData(); - for (auto entityID : avatarEntities.keys()) { - auto entity = entityTree->findEntityByID(entityID); - if (!entity || !isWearableEntity(entity)) { - continue; + + if (entityTree) { + QScriptEngine scriptEngine; + auto avatarEntities = myAvatar->getAvatarEntityData(); + for (auto entityID : avatarEntities.keys()) { + auto entity = entityTree->findEntityByID(entityID); + if (!entity || !isWearableEntity(entity)) { + continue; + } + + QVariantMap avatarEntityData; + + EncodeBitstreamParams params; + auto desiredProperties = entity->getEntityProperties(params); + desiredProperties += PROP_LOCAL_POSITION; + desiredProperties += PROP_LOCAL_ROTATION; + desiredProperties -= PROP_JOINT_ROTATIONS_SET; + desiredProperties -= PROP_JOINT_ROTATIONS; + desiredProperties -= PROP_JOINT_TRANSLATIONS_SET; + desiredProperties -= PROP_JOINT_TRANSLATIONS; + + EntityItemProperties entityProperties = entity->getProperties(desiredProperties); + QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties); + avatarEntityData["properties"] = scriptProperties.toVariant(); + wearableEntities.append(QVariant(avatarEntityData)); } - QVariantMap avatarEntityData; - EncodeBitstreamParams params; - auto desiredProperties = entity->getEntityProperties(params); - desiredProperties += PROP_LOCAL_POSITION; - desiredProperties += PROP_LOCAL_ROTATION; - EntityItemProperties entityProperties = entity->getProperties(desiredProperties); - QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties); - avatarEntityData["properties"] = scriptProperties.toVariant(); - wearableEntities.append(QVariant(avatarEntityData)); } bookmark.insert(ENTRY_AVATAR_ENTITIES, wearableEntities); return bookmark; From 1683179fe5fb75cd6d89bedb90614b283e971d45 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 29 Nov 2018 09:14:10 +1300 Subject: [PATCH 37/46] Remove unused constant --- interface/src/ModelSelector.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index 7e428a294d..3223e3ab9c 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -19,7 +19,6 @@ #include static const QString AVATAR_HEAD_AND_BODY_STRING = "Avatar Body with Head"; -static const QString AVATAR_ATTACHEMENT_STRING = "Avatar Attachment"; static const QString ENTITY_MODEL_STRING = "Entity Model"; ModelSelector::ModelSelector() { From c29f6346d8ad9a237d06a3cab2fb43add240ecc8 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 28 Nov 2018 14:04:14 -0800 Subject: [PATCH 38/46] Clear mixing structures when we stop mixing for node --- assignment-client/src/audio/AudioMixerClientData.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 9a78ba31a2..90698bfac8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -337,6 +337,13 @@ void AudioMixerClientData::removeAgentAvatarAudioStream() { if (it != _audioStreams.end()) { _audioStreams.erase(it); + + // Clear mixing structures so that they get recreated with up to date + // data if the stream comes back + setHasReceivedFirstMix(false); + _streams.skipped.clear(); + _streams.inactive.clear(); + _streams.active.clear(); } } From 59b7cdf318336ded6c26ea1b039cf7fa648c189d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Nov 2018 13:10:15 -0800 Subject: [PATCH 39/46] Fix empty rgb field in Create going black --- scripts/system/html/js/colpick.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index 505dd294d6..e4ad65dfb6 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -309,6 +309,9 @@ For usage and examples: colpick.com/plugin }, // Fix the values if the user enters a negative or high value fixHSB = function (hsb) { + hsb.h = isNaN(hsb.h) ? 0 : hsb.h; + hsb.s = isNaN(hsb.s) ? 0 : hsb.s; + hsb.b = isNaN(hsb.b) ? 0 : hsb.b; return { h: Math.min(360, Math.max(0, hsb.h)), s: Math.min(100, Math.max(0, hsb.s)), @@ -316,6 +319,9 @@ For usage and examples: colpick.com/plugin }; }, fixRGB = function (rgb) { + rgb.r = isNaN(rgb.r) ? 0 : rgb.r; + rgb.g = isNaN(rgb.g) ? 0 : rgb.g; + rgb.b = isNaN(rgb.b) ? 0 : rgb.b; return { r: Math.min(255, Math.max(0, rgb.r)), g: Math.min(255, Math.max(0, rgb.g)), From 87c863584d4bc04af3a38b7d515ffb1ea5b3df25 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 29 Nov 2018 17:43:19 -0800 Subject: [PATCH 40/46] Just to remove conflict. --- tools/nitpick/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index a02980ddfe..7d75d660d7 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -1,6 +1,6 @@ # nitpick -Nitpick is a stand alone application that provides a mechanism for regression testing. The general idea is simple: +Nitpick is a stand alone application that provides a mechanism for regression testing. The general idea is simple: * Each test folder has a script that produces a set of snapshots. * The snapshots are compared to a 'canonical' set of images that have been produced beforehand. * The result, if any test failed, is a zipped folder describing the failure. From 5f9f1ab092a4e36beb78dac77f72a29002c6ccdd Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 30 Nov 2018 14:43:53 -0800 Subject: [PATCH 41/46] All QDir iterators now sort in lexicographical order. --- tools/nitpick/src/AWSInterface.cpp | 10 +++++----- tools/nitpick/src/Test.cpp | 12 ++++++------ tools/nitpick/src/TestRailInterface.cpp | 4 ++-- tools/nitpick/src/TestRunner.cpp | 2 +- tools/nitpick/src/ui/Nitpick.cpp | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp index e43ef8dc75..f525b7e039 100644 --- a/tools/nitpick/src/AWSInterface.cpp +++ b/tools/nitpick/src/AWSInterface.cpp @@ -156,7 +156,7 @@ void AWSInterface::writeTable(QTextStream& stream) { // Note that failures are processed first, then successes QStringList originalNamesFailures; QStringList originalNamesSuccesses; - QDirIterator it1(_snapshotDirectory.toStdString().c_str()); + QDirIterator it1(QDir(_snapshotDirectory, "", QDir::Name)); while (it1.hasNext()) { QString nextDirectory = it1.next(); @@ -204,7 +204,7 @@ void AWSInterface::writeTable(QTextStream& stream) { QDir().rename(originalNamesSuccesses[i], _htmlSuccessesFolder + "/" + newNamesSuccesses[i]); } - QDirIterator it2((_htmlFailuresFolder).toStdString().c_str()); + QDirIterator it2(QDir(_htmlFailuresFolder, "", QDir::Name)); while (it2.hasNext()) { QString nextDirectory = it2.next(); @@ -239,7 +239,7 @@ void AWSInterface::writeTable(QTextStream& stream) { stream << "\t" << "\t" << "\n"; stream << "\t" << "\t" << "

The following tests passed:

"; - QDirIterator it3((_htmlSuccessesFolder).toStdString().c_str()); + QDirIterator it3(QDir(_htmlSuccessesFolder, "", QDir::Name)); while (it3.hasNext()) { QString nextDirectory = it3.next(); @@ -337,7 +337,7 @@ void AWSInterface::updateAWS() { stream << "import boto3\n"; stream << "s3 = boto3.resource('s3')\n\n"; - QDirIterator it1(_htmlFailuresFolder.toStdString().c_str()); + QDirIterator it1(QDir(_htmlFailuresFolder, "", QDir::Name)); while (it1.hasNext()) { QString nextDirectory = it1.next(); @@ -372,7 +372,7 @@ void AWSInterface::updateAWS() { } } - QDirIterator it2(_htmlSuccessesFolder.toStdString().c_str()); + QDirIterator it2(QDir(_htmlSuccessesFolder, "", QDir::Name)); while (it2.hasNext()) { QString nextDirectory = it2.next(); diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index e17978d9d0..976add4200 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -542,7 +542,7 @@ void Test::createAllMDFiles() { createMDFile(_testsRootDirectory); } - QDirIterator it(_testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + QDirIterator it(QDir(_testsRootDirectory, "", QDir::Name), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -636,7 +636,7 @@ void Test::createAllTestAutoScripts() { createTestAutoScript(_testsRootDirectory); } - QDirIterator it(_testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + QDirIterator it(QDir(_testsRootDirectory, "", QDir::Name), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -704,7 +704,7 @@ void Test::createAllRecursiveScripts() { createRecursiveScript(_testsRootDirectory, false); - QDirIterator it(_testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + QDirIterator it(QDir(_testsRootDirectory, "", QDir::Name), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -716,7 +716,7 @@ void Test::createAllRecursiveScripts() { // Only process directories that have sub-directories bool hasNoSubDirectories{ true }; - QDirIterator it2(directory.toStdString().c_str(), QDirIterator::Subdirectories); + QDirIterator it2(QDir(directory, "", QDir::Name), QDirIterator::Subdirectories); while (it2.hasNext()) { QString directory2 = it2.next(); @@ -787,7 +787,7 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact testFound = true; } - QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + QDirIterator it(QDir(topLevelDirectory, "", QDir::Name), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -858,7 +858,7 @@ void Test::createTestsOutline() { int rootDepth { _testDirectory.count('/') }; // Each test is shown as the folder name linking to the matching GitHub URL, and the path to the associated test.md file - QDirIterator it(_testDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + QDirIterator it(QDir(_testDirectory, "", QDir::Name), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); diff --git a/tools/nitpick/src/TestRailInterface.cpp b/tools/nitpick/src/TestRailInterface.cpp index a0c0d74526..f2e895d17e 100644 --- a/tools/nitpick/src/TestRailInterface.cpp +++ b/tools/nitpick/src/TestRailInterface.cpp @@ -275,7 +275,7 @@ void TestRailInterface::processDirectoryPython(const QString& directory, const QString& userGitHub, const QString& branchGitHub) { // Loop over all entries in directory - QDirIterator it(directory.toStdString().c_str()); + QDirIterator it(QDir(directory, "", QDir::Name)); while (it.hasNext()) { QString nextDirectory = it.next(); @@ -855,7 +855,7 @@ QDomElement TestRailInterface::processDirectoryXML(const QString& directory, QDomElement result = element; // Loop over all entries in directory - QDirIterator it(directory.toStdString().c_str()); + QDirIterator it(QDir(directory, "", QDir::Name)); while (it.hasNext()) { QString nextDirectory = it.next(); diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 12bdf87495..d3c05483f9 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -366,7 +366,7 @@ void TestRunner::createSnapshotFolder() { // Note that we cannot use just a `png` filter, as the filenames include periods // Also, delete any `jpg` and `txt` files // The idea is to leave only previous zipped result folders - QDirIterator it(_snapshotFolder.toStdString().c_str()); + QDirIterator it(QDir(_snapshotFolder, "", QDir::Name)); while (it.hasNext()) { QString filename = it.next(); if (filename.right(4) == ".png" || filename.right(4) == ".jpg" || filename.right(4) == ".txt") { diff --git a/tools/nitpick/src/ui/Nitpick.cpp b/tools/nitpick/src/ui/Nitpick.cpp index 201d6e562d..cdd2ff89d9 100644 --- a/tools/nitpick/src/ui/Nitpick.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -36,7 +36,7 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) { _ui.statusLabel->setText(""); _ui.plainTextEdit->setReadOnly(true); - setWindowTitle("Nitpick - v1.1"); + setWindowTitle("Nitpick - v1.2"); // Coming soon to a nitpick near you... //// _helpWindow.textBrowser->setText() From 6491ea23eb327cf83e217a02dbc78d3251e66451 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 30 Nov 2018 18:54:33 -0800 Subject: [PATCH 42/46] Removed unneeded sort order and renamed folder. --- tools/nitpick/src/AWSInterface.cpp | 40 ++++++++++++------------- tools/nitpick/src/AWSInterface.h | 4 +-- tools/nitpick/src/Test.cpp | 18 +++++------ tools/nitpick/src/TestRailInterface.cpp | 4 +-- tools/nitpick/src/TestRunner.cpp | 2 +- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp index f525b7e039..21b88277db 100644 --- a/tools/nitpick/src/AWSInterface.cpp +++ b/tools/nitpick/src/AWSInterface.cpp @@ -22,11 +22,11 @@ AWSInterface::AWSInterface(QObject* parent) : QObject(parent) { } void AWSInterface::createWebPageFromResults(const QString& testResults, - const QString& snapshotDirectory, + const QString& workingDirectory, QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit) { _testResults = testResults; - _snapshotDirectory = snapshotDirectory; + _workingDirectory = workingDirectory; _urlLineEdit = urlLineEdit; _urlLineEdit->setEnabled(false); @@ -44,13 +44,13 @@ void AWSInterface::extractTestFailuresFromZippedFolder() { // the folder will be called `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]` // and, this folder will be in the working directory QStringList parts =_testResults.split('/'); - QString zipFolderName = _snapshotDirectory + "/" + parts[parts.length() - 1].split('.')[0]; + QString zipFolderName = _workingDirectory + "/" + parts[parts.length() - 1].split('.')[0]; if (QDir(zipFolderName).exists()) { QDir dir = zipFolderName; dir.removeRecursively(); } - JlCompress::extractDir(_testResults, _snapshotDirectory); + JlCompress::extractDir(_testResults, _workingDirectory); } void AWSInterface::createHTMLFile() { @@ -60,7 +60,7 @@ void AWSInterface::createHTMLFile() { QString filename = pathComponents[pathComponents.length() - 1]; _resultsFolder = filename.left(filename.length() - 4); - QString resultsPath = _snapshotDirectory + "/" + _resultsFolder + "/"; + QString resultsPath = _workingDirectory + "/" + _resultsFolder + "/"; QDir().mkdir(resultsPath); _htmlFilename = resultsPath + HTML_FILENAME; @@ -156,7 +156,7 @@ void AWSInterface::writeTable(QTextStream& stream) { // Note that failures are processed first, then successes QStringList originalNamesFailures; QStringList originalNamesSuccesses; - QDirIterator it1(QDir(_snapshotDirectory, "", QDir::Name)); + QDirIterator it1(_workingDirectory); while (it1.hasNext()) { QString nextDirectory = it1.next(); @@ -190,10 +190,10 @@ void AWSInterface::writeTable(QTextStream& stream) { newNamesSuccesses.append(originalNamesSuccesses[i].split("--tests.")[1]); } - _htmlFailuresFolder = _snapshotDirectory + "/" + _resultsFolder + "/" + FAILURES_FOLDER; + _htmlFailuresFolder = _workingDirectory + "/" + _resultsFolder + "/" + FAILURES_FOLDER; QDir().mkdir(_htmlFailuresFolder); - _htmlSuccessesFolder = _snapshotDirectory + "/" + _resultsFolder + "/" + SUCCESSES_FOLDER; + _htmlSuccessesFolder = _workingDirectory + "/" + _resultsFolder + "/" + SUCCESSES_FOLDER; QDir().mkdir(_htmlSuccessesFolder); for (int i = 0; i < newNamesFailures.length(); ++i) { @@ -204,7 +204,7 @@ void AWSInterface::writeTable(QTextStream& stream) { QDir().rename(originalNamesSuccesses[i], _htmlSuccessesFolder + "/" + newNamesSuccesses[i]); } - QDirIterator it2(QDir(_htmlFailuresFolder, "", QDir::Name)); + QDirIterator it2(_htmlFailuresFolder); while (it2.hasNext()) { QString nextDirectory = it2.next(); @@ -239,7 +239,7 @@ void AWSInterface::writeTable(QTextStream& stream) { stream << "\t" << "\t" << "\n"; stream << "\t" << "\t" << "

The following tests passed:

"; - QDirIterator it3(QDir(_htmlSuccessesFolder, "", QDir::Name)); + QDirIterator it3(_htmlSuccessesFolder); while (it3.hasNext()) { QString nextDirectory = it3.next(); @@ -320,7 +320,7 @@ void AWSInterface::createEntry(int index, const QString& testResult, QTextStream } void AWSInterface::updateAWS() { - QString filename = _snapshotDirectory + "/updateAWS.py"; + QString filename = _workingDirectory + "/updateAWS.py"; if (QFile::exists(filename)) { QFile::remove(filename); } @@ -337,7 +337,7 @@ void AWSInterface::updateAWS() { stream << "import boto3\n"; stream << "s3 = boto3.resource('s3')\n\n"; - QDirIterator it1(QDir(_htmlFailuresFolder, "", QDir::Name)); + QDirIterator it1(_htmlFailuresFolder); while (it1.hasNext()) { QString nextDirectory = it1.next(); @@ -351,20 +351,20 @@ void AWSInterface::updateAWS() { QStringList parts = nextDirectory.split('/'); QString filename = parts[parts.length() - 3] + "/" + parts[parts.length() - 2] + "/" + parts[parts.length() - 1]; - stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Actual Image.png" << "', 'rb')\n"; stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Actual Image.png" << "', Body=data)\n\n"; - stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Expected Image.png" << "', 'rb')\n"; stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Expected Image.png" << "', Body=data)\n\n"; if (QFile::exists(_htmlFailuresFolder + "/" + parts[parts.length() - 1] + "/Difference Image.png")) { - stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Difference Image.png" << "', 'rb')\n"; @@ -372,7 +372,7 @@ void AWSInterface::updateAWS() { } } - QDirIterator it2(QDir(_htmlSuccessesFolder, "", QDir::Name)); + QDirIterator it2(_htmlSuccessesFolder); while (it2.hasNext()) { QString nextDirectory = it2.next(); @@ -386,20 +386,20 @@ void AWSInterface::updateAWS() { QStringList parts = nextDirectory.split('/'); QString filename = parts[parts.length() - 3] + "/" + parts[parts.length() - 2] + "/" + parts[parts.length() - 1]; - stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Actual Image.png" << "', 'rb')\n"; stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Actual Image.png" << "', Body=data)\n\n"; - stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Expected Image.png" << "', 'rb')\n"; stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Expected Image.png" << "', Body=data)\n\n"; if (QFile::exists(_htmlSuccessesFolder + "/" + parts[parts.length() - 1] + "/Difference Image.png")) { - stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Difference Image.png" << "', 'rb')\n"; @@ -407,7 +407,7 @@ void AWSInterface::updateAWS() { } } - stream << "data = open('" << _snapshotDirectory << "/" << _resultsFolder << "/" << HTML_FILENAME << "', 'rb')\n"; + stream << "data = open('" << _workingDirectory << "/" << _resultsFolder << "/" << HTML_FILENAME << "', 'rb')\n"; stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << _resultsFolder << "/" << HTML_FILENAME << "', Body=data, ContentType='text/html')\n"; diff --git a/tools/nitpick/src/AWSInterface.h b/tools/nitpick/src/AWSInterface.h index f4084f1a14..c5be5f35bb 100644 --- a/tools/nitpick/src/AWSInterface.h +++ b/tools/nitpick/src/AWSInterface.h @@ -26,7 +26,7 @@ public: explicit AWSInterface(QObject* parent = 0); void createWebPageFromResults(const QString& testResults, - const QString& snapshotDirectory, + const QString& workingDirectory, QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit); @@ -49,7 +49,7 @@ public: private: QString _testResults; - QString _snapshotDirectory; + QString _workingDirectory; QString _resultsFolder; QString _htmlFailuresFolder; QString _htmlSuccessesFolder; diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 976add4200..4ae2f7ef9d 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -542,7 +542,7 @@ void Test::createAllMDFiles() { createMDFile(_testsRootDirectory); } - QDirIterator it(QDir(_testsRootDirectory, "", QDir::Name), QDirIterator::Subdirectories); + QDirIterator it(_testsRootDirectory, QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -636,7 +636,7 @@ void Test::createAllTestAutoScripts() { createTestAutoScript(_testsRootDirectory); } - QDirIterator it(QDir(_testsRootDirectory, "", QDir::Name), QDirIterator::Subdirectories); + QDirIterator it(_testsRootDirectory, QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -704,7 +704,7 @@ void Test::createAllRecursiveScripts() { createRecursiveScript(_testsRootDirectory, false); - QDirIterator it(QDir(_testsRootDirectory, "", QDir::Name), QDirIterator::Subdirectories); + QDirIterator it(_testsRootDirectory, QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -716,7 +716,7 @@ void Test::createAllRecursiveScripts() { // Only process directories that have sub-directories bool hasNoSubDirectories{ true }; - QDirIterator it2(QDir(directory, "", QDir::Name), QDirIterator::Subdirectories); + QDirIterator it2(directory, QDirIterator::Subdirectories); while (it2.hasNext()) { QString directory2 = it2.next(); @@ -787,7 +787,7 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact testFound = true; } - QDirIterator it(QDir(topLevelDirectory, "", QDir::Name), QDirIterator::Subdirectories); + QDirIterator it(topLevelDirectory, QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -858,7 +858,7 @@ void Test::createTestsOutline() { int rootDepth { _testDirectory.count('/') }; // Each test is shown as the folder name linking to the matching GitHub URL, and the path to the associated test.md file - QDirIterator it(QDir(_testDirectory, "", QDir::Name), QDirIterator::Subdirectories); + QDirIterator it(_testDirectory, QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); @@ -1052,11 +1052,11 @@ void Test::createWebPage(QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit) { return; } - QString snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store temporary files in", + QString workingDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store temporary files in", nullptr, QFileDialog::ShowDirsOnly); - if (snapshotDirectory.isNull()) { + if (workingDirectory.isNull()) { return; } - _awsInterface.createWebPageFromResults(testResults, snapshotDirectory, updateAWSCheckBox, urlLineEdit); + _awsInterface.createWebPageFromResults(testResults, workingDirectory, updateAWSCheckBox, urlLineEdit); } \ No newline at end of file diff --git a/tools/nitpick/src/TestRailInterface.cpp b/tools/nitpick/src/TestRailInterface.cpp index f2e895d17e..1d7aa0a32f 100644 --- a/tools/nitpick/src/TestRailInterface.cpp +++ b/tools/nitpick/src/TestRailInterface.cpp @@ -275,7 +275,7 @@ void TestRailInterface::processDirectoryPython(const QString& directory, const QString& userGitHub, const QString& branchGitHub) { // Loop over all entries in directory - QDirIterator it(QDir(directory, "", QDir::Name)); + QDirIterator it(directory); while (it.hasNext()) { QString nextDirectory = it.next(); @@ -855,7 +855,7 @@ QDomElement TestRailInterface::processDirectoryXML(const QString& directory, QDomElement result = element; // Loop over all entries in directory - QDirIterator it(QDir(directory, "", QDir::Name)); + QDirIterator it(directory); while (it.hasNext()) { QString nextDirectory = it.next(); diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index d3c05483f9..9b99e114a7 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -366,7 +366,7 @@ void TestRunner::createSnapshotFolder() { // Note that we cannot use just a `png` filter, as the filenames include periods // Also, delete any `jpg` and `txt` files // The idea is to leave only previous zipped result folders - QDirIterator it(QDir(_snapshotFolder, "", QDir::Name)); + QDirIterator it(_snapshotFolder); while (it.hasNext()) { QString filename = it.next(); if (filename.right(4) == ".png" || filename.right(4) == ".jpg" || filename.right(4) == ".txt") { From 508a6587523036cef88741605505af9c77a0dd59 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 1 Dec 2018 18:41:44 -0800 Subject: [PATCH 43/46] Filenames are sorted in memory. --- tools/nitpick/src/AWSInterface.cpp | 43 +++++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp index 21b88277db..11a0f06d07 100644 --- a/tools/nitpick/src/AWSInterface.cpp +++ b/tools/nitpick/src/AWSInterface.cpp @@ -27,7 +27,7 @@ void AWSInterface::createWebPageFromResults(const QString& testResults, QLineEdit* urlLineEdit) { _testResults = testResults; _workingDirectory = workingDirectory; - + _urlLineEdit = urlLineEdit; _urlLineEdit->setEnabled(false); @@ -43,7 +43,7 @@ void AWSInterface::extractTestFailuresFromZippedFolder() { // For a test results zip file called `D:/tt/TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ].zip` // the folder will be called `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]` // and, this folder will be in the working directory - QStringList parts =_testResults.split('/'); + QStringList parts = _testResults.split('/'); QString zipFolderName = _workingDirectory + "/" + parts[parts.length() - 1].split('.')[0]; if (QDir(zipFolderName).exists()) { QDir dir = zipFolderName; @@ -116,7 +116,7 @@ void AWSInterface::writeTitle(QTextStream& stream) { QString date_buildorPR_hostName = tokens[tokens.length() - 1].split("--")[1].split(".")[0]; QString buildorPR = date_buildorPR_hostName.split('(')[1].split(')')[0]; - QString hostName = date_buildorPR_hostName.split('[')[1].split(']')[0]; + QString hostName = date_buildorPR_hostName.split('[')[1].split(']')[0]; QStringList dateList = date_buildorPR_hostName.split('(')[0].split('_')[0].split('-'); QString year = dateList[0]; @@ -189,7 +189,7 @@ void AWSInterface::writeTable(QTextStream& stream) { for (int i = 0; i < originalNamesSuccesses.length(); ++i) { newNamesSuccesses.append(originalNamesSuccesses[i].split("--tests.")[1]); } - + _htmlFailuresFolder = _workingDirectory + "/" + _resultsFolder + "/" + FAILURES_FOLDER; QDir().mkdir(_htmlFailuresFolder); @@ -204,7 +204,11 @@ void AWSInterface::writeTable(QTextStream& stream) { QDir().rename(originalNamesSuccesses[i], _htmlSuccessesFolder + "/" + newNamesSuccesses[i]); } + // Mac does not read folders in lexicographic order, so this step is divided into 2 + // Each test consists of the test name and its index. QDirIterator it2(_htmlFailuresFolder); + QStringList folderNames; + while (it2.hasNext()) { QString nextDirectory = it2.next(); @@ -214,10 +218,17 @@ void AWSInterface::writeTable(QTextStream& stream) { } QStringList pathComponents = nextDirectory.split('/'); - QString filename = pathComponents[pathComponents.length() - 1]; - int splitIndex = filename.lastIndexOf("."); - QString testName = filename.left(splitIndex).replace(".", " / "); - QString testNumber = filename.right(filename.length() - (splitIndex + 1)); + QString folderName = pathComponents[pathComponents.length() - 1]; + + folderNames << folderName; + } + + folderNames.sort(); + for (const auto& folderName : folderNames) { + int splitIndex = folderName.lastIndexOf("."); + QString testName = folderName.left(splitIndex).replace('.', " / "); + + int testNumber = folderName.right(folderName.length() - (splitIndex + 1)).toInt(); // The failures are ordered lexicographically, so we know that we can rely on the testName changing to create a new table if (testName != previousTestName) { @@ -232,7 +243,7 @@ void AWSInterface::writeTable(QTextStream& stream) { openTable(stream); } - createEntry(testNumber.toInt(), filename, stream, true); + createEntry(testNumber, folderName, stream, true); } closeTable(stream); @@ -290,7 +301,7 @@ void AWSInterface::closeTable(QTextStream& stream) { void AWSInterface::createEntry(int index, const QString& testResult, QTextStream& stream, const bool isFailure) { stream << "\t\t\t\n"; stream << "\t\t\t\t

" << QString::number(index) << "

\n"; - + // For a test named `D:/t/fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf/Failure_1--tests.engine.interaction.pick.collision.many.00000` // we need `Failure_1--tests.engine.interaction.pick.collision.many.00000` QStringList resultNameComponents = testResult.split('/'); @@ -302,11 +313,11 @@ void AWSInterface::createEntry(int index, const QString& testResult, QTextStream folder = FAILURES_FOLDER; differenceFileFound = QFile::exists(_htmlFailuresFolder + "/" + resultName + "/Difference Image.png"); } else { - folder = SUCCESSES_FOLDER; + folder = SUCCESSES_FOLDER; differenceFileFound = QFile::exists(_htmlSuccessesFolder + "/" + resultName + "/Difference Image.png"); } - + stream << "\t\t\t\t\n"; stream << "\t\t\t\t\n"; @@ -345,7 +356,7 @@ void AWSInterface::updateAWS() { if (nextDirectory.right(1) == ".") { continue; } - + // nextDirectory looks like `D:/t/TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]/failures/engine.render.effect.bloom.00000` // We need to concatenate the last 3 components, to get `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]/failures/engine.render.effect.bloom.00000` QStringList parts = nextDirectory.split('/'); @@ -426,10 +437,10 @@ void AWSInterface::updateAWS() { [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); #ifdef Q_OS_WIN - QStringList parameters = QStringList() << filename ; + QStringList parameters = QStringList() << filename; process->start(_pythonCommand, parameters); #elif defined Q_OS_MAC - QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; process->start("sh", parameters); #endif -} +} \ No newline at end of file From a4689edee11fb6f1265c00cad09be1b7dd417b0a Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 1 Dec 2018 19:03:59 -0800 Subject: [PATCH 44/46] Added messages for completion of HTML creation. --- tools/nitpick/src/AWSInterface.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp index 11a0f06d07..2e9ba7ad6d 100644 --- a/tools/nitpick/src/AWSInterface.cpp +++ b/tools/nitpick/src/AWSInterface.cpp @@ -36,6 +36,9 @@ void AWSInterface::createWebPageFromResults(const QString& testResults, if (updateAWSCheckBox->isChecked()) { updateAWS(); + QMessageBox::information(0, "Success", "HTML file has been created and copied to AWS"); + } else { + QMessageBox::information(0, "Success", "HTML file has been created"); } } From f153d4fcaeefd245a6bd94886368fd9906024ba3 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sun, 2 Dec 2018 20:13:58 -0800 Subject: [PATCH 45/46] Do not create empty recursive test scripts. --- tools/nitpick/src/Test.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 4ae2f7ef9d..14d08e9822 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -653,7 +653,7 @@ void Test::createAllTestAutoScripts() { } } - QMessageBox::information(0, "Success", "'nitpick.js' scripts have been created"); + QMessageBox::information(0, "Success", "All 'testAuto.js' scripts have been created"); } bool Test::createTestAutoScript(const QString& directory) { @@ -737,16 +737,17 @@ void Test::createAllRecursiveScripts() { } void Test::createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode) { - const QString recursiveTestsFilename("testRecursive.js"); - QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); - if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { + const QString recursiveTestsScriptName("testRecursive.js"); + const QString recursiveTestsFilename(topLevelDirectory + "/" + recursiveTestsScriptName); + QFile recursiveTestsFile(recursiveTestsFilename); + if (!recursiveTestsFile.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), - "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\""); + "Failed to create \"" + recursiveTestsScriptName + "\" in directory \"" + topLevelDirectory + "\""); exit(-1); } - QTextStream textStream(&allTestsFilename); + QTextStream textStream(&recursiveTestsFile); textStream << "// This is an automatically generated file, created by nitpick" << endl; @@ -809,7 +810,15 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact if (interactiveMode && !testFound) { QMessageBox::information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); - allTestsFilename.close(); + recursiveTestsFile.close(); + return; + } + + // If 'directories' is empty, this means that this recursive script has no tests to call, so it is redundant + // The script will be closed and deleted + if (directories.length() == 0) { + recursiveTestsFile.close(); + QFile::remove(recursiveTestsFilename); return; } @@ -821,7 +830,7 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact textStream << endl; textStream << "nitpick.runRecursive();" << endl; - allTestsFilename.close(); + recursiveTestsFile.close(); } void Test::createTestsOutline() { From 15f95aafa52864391d8bc824cc3f622b710188cf Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 4 Dec 2018 16:41:19 -0800 Subject: [PATCH 46/46] WIP. --- tools/nitpick/src/Test.cpp | 50 ++++++++++++++++++++++++++++++++++---- tools/nitpick/src/Test.h | 4 ++- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 14d08e9822..b1254a3c04 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -105,7 +105,7 @@ int Test::compareImageLists() { ++numberOfFailures; if (!isInteractiveMode) { - appendTestResultsToFile(_testResultsFolderPath, testResult, _mismatchWindow.getComparisonImage(), true); + appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), true); } else { _mismatchWindow.exec(); @@ -113,7 +113,7 @@ int Test::compareImageLists() { case USER_RESPONSE_PASS: break; case USE_RESPONSE_FAIL: - appendTestResultsToFile(_testResultsFolderPath, testResult, _mismatchWindow.getComparisonImage(), true); + appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), true); break; case USER_RESPONSE_ABORT: keepOn = false; @@ -124,7 +124,7 @@ int Test::compareImageLists() { } } } else { - appendTestResultsToFile(_testResultsFolderPath, testResult, _mismatchWindow.getComparisonImage(), false); + appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), false); } _progressBar->setValue(i); @@ -134,12 +134,31 @@ int Test::compareImageLists() { return numberOfFailures; } -void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestResult testResult, QPixmap comparisonImage, bool hasFailed) { +int Test::checkTextResults() { + // Create lists of failed and passed tests + QStringList nameFilterFailed; + nameFilterFailed << "*.failed.txt"; + QStringList testsFailed = QDir(_snapshotDirectory).entryList(nameFilterFailed, QDir::Files, QDir::Name); + + QStringList nameFilterPassed; + nameFilterPassed << "*.passed.txt"; + QStringList testsPassed = QDir(_snapshotDirectory).entryList(nameFilterPassed, QDir::Files, QDir::Name); + + // Add results to Test Results folder + foreach(QString currentFilename, testsFailed) { + } + + return testsFailed.length(); +} + +void Test::appendTestResultsToFile(TestResult testResult, QPixmap comparisonImage, bool hasFailed) { + // Critical error if Test Results folder does not exist if (!QDir().exists(_testResultsFolderPath)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + _testResultsFolderPath + " not found"); exit(-1); } + // There are separate subfolders for failures and passes QString resultFolderPath; if (hasFailed) { resultFolderPath = _testResultsFolderPath + "/Failure_" + QString::number(_failureIndex) + "--" + @@ -195,6 +214,22 @@ void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestRe comparisonImage.save(resultFolderPath + "/" + "Difference Image.png"); } +void::Test::appendTestResultsToFile(QString testResultFilename, bool hasFailed) { + QString resultFolderPath; + if (hasFailed) { + resultFolderPath = _testResultsFolderPath + "/Failure_"; + ++_failureIndex; + } else { + resultFolderPath = _testResultsFolderPath + "/Success_"; + ++_successIndex; + } + + if (!QFile::copy(testResultFilename, resultFolderPath)) { +//// QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); + exit(-1); + } +} + void Test::startTestsEvaluation(const bool isRunningFromCommandLine, const bool isRunningInAutomaticTestRun, const QString& snapshotDirectory, @@ -270,9 +305,14 @@ void Test::startTestsEvaluation(const bool isRunningFromCommandLine, nitpick->downloadFiles(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames, (void *)this); } + void Test::finishTestsEvaluation() { + // First - compare the pairs of images int numberOfFailures = compareImageLists(); - + + // Next - check text results + numberOfFailures += checkTextResults(); + if (!_isRunningFromCommandLine && !_isRunningInAutomaticTestRun) { if (numberOfFailures == 0) { QMessageBox::information(0, "Success", "All images are as expected"); diff --git a/tools/nitpick/src/Test.h b/tools/nitpick/src/Test.h index a79252b92a..9ef7c5627a 100644 --- a/tools/nitpick/src/Test.h +++ b/tools/nitpick/src/Test.h @@ -77,6 +77,7 @@ public: void createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode); int compareImageLists(); + int checkTextResults(); QStringList createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory); @@ -84,7 +85,8 @@ public: void includeTest(QTextStream& textStream, const QString& testPathname); - void appendTestResultsToFile(const QString& testResultsFolderPath, TestResult testResult, QPixmap comparisonImage, bool hasFailed); + void appendTestResultsToFile(TestResult testResult, QPixmap comparisonImage, bool hasFailed); + void appendTestResultsToFile(QString testResultFilename, bool hasFailed); bool createTestResultsFolderPath(const QString& directory); QString zipAndDeleteTestResultsFolder();