diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 989b560e4e..51ef6e17e3 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -218,10 +218,10 @@ Rectangle { id: nameCard // Properties displayName: styleData.value - userName: model && model.userName - audioLevel: model && model.audioLevel + userName: model ? model.userName : "" + audioLevel: model ? model.audioLevel : 0.0 visible: !isCheckBox && !isButton - uuid: model && model.sessionId + uuid: model ? model.sessionId : "" selected: styleData.selected isAdmin: model && model.admin // Size @@ -241,9 +241,9 @@ Rectangle { id: actionCheckBox visible: isCheckBox anchors.centerIn: parent - checked: model[styleData.role] + checked: model ? model[styleData.role] : false // If this is a "Personal Mute" checkbox, disable the checkbox if the "Ignore" checkbox is checked. - enabled: !(styleData.role === "personalMute" && model["ignore"]) + enabled: !(styleData.role === "personalMute" && (model ? model["ignore"] : true)) boxSize: 24 onClicked: { var newValue = !model[styleData.role] @@ -416,6 +416,22 @@ Rectangle { } } } + // Timer used when selecting table rows that aren't yet present in the model + // (i.e. when selecting avatars using edit.js or sphere overlays) + Timer { + property bool selected // Selected or deselected? + property int userIndex // The userIndex of the avatar we want to select + id: selectionTimer + onTriggered: { + if (selected) { + table.selection.clear(); // for now, no multi-select + table.selection.select(userIndex); + table.positionViewAtRow(userIndex, ListView.Visible); + } else { + table.selection.deselect(userIndex); + } + } + } function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml var data = optionalData || userModelData, length = data.length; @@ -453,19 +469,30 @@ Rectangle { case 'select': var sessionIds = message.params[0]; var selected = message.params[1]; + var alreadyRefreshed = message.params[2]; var userIndex = findSessionIndex(sessionIds[0]); if (sessionIds.length > 1) { letterbox("", "", 'Only one user can be selected at a time.'); } else if (userIndex < 0) { - letterbox("", "", 'The last editor is not among this list of users.'); - } else { - if (selected) { - table.selection.clear(); // for now, no multi-select - table.selection.select(userIndex); - table.positionViewAtRow(userIndex, ListView.Visible); + // If we've already refreshed the PAL and the avatar still isn't present in the model... + if (alreadyRefreshed === true) { + letterbox('', '', 'The last editor of this object is either you or not among this list of users.'); } else { - table.selection.deselect(userIndex); + pal.sendToScript({method: 'refresh', params: message.params}); } + } else { + // If we've already refreshed the PAL and found the avatar in the model + if (alreadyRefreshed === true) { + // Wait a little bit before trying to actually select the avatar in the table + selectionTimer.interval = 250; + } else { + // If we've found the avatar in the model and didn't need to refresh, + // select the avatar in the table immediately + selectionTimer.interval = 0; + } + selectionTimer.selected = selected; + selectionTimer.userIndex = userIndex; + selectionTimer.start(); } break; // Received an "updateUsername()" request from the JS diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 085d4f5e27..6dc2486ffb 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -134,7 +134,7 @@ EntityListTool = function(opts) { Window.alert('There were no recent users of the ' + selectionManager.selections.length + ' selected objects.'); } else { // No need to subscribe if we're just sending. - Messages.sendMessage('com.highfidelity.pal', JSON.stringify({method: 'select', params: [dedupped, true]}), 'local'); + Messages.sendMessage('com.highfidelity.pal', JSON.stringify({method: 'select', params: [dedupped, true, false]}), 'local'); } } else if (data.type == "delete") { deleteSelectedEntities(); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 3b34eed268..f148ad5fdb 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -233,7 +233,7 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like break; case 'refresh': removeOverlays(); - populateUserList(); + populateUserList(message.params); UserActivityLogger.palAction("refresh", ""); break; case 'updateGain': @@ -271,7 +271,7 @@ function addAvatarNode(id) { color: color(selected, false, 0.0), ignoreRayIntersection: false}, selected, true); } -function populateUserList() { +function populateUserList(selectData) { var data = []; AvatarList.getAvatarIdentifiers().sort().forEach(function (id) { // sorting the identifiers is just an aid for debugging var avatar = AvatarList.getAvatar(id); @@ -295,7 +295,11 @@ function populateUserList() { data.push(avatarPalDatum); print('PAL data:', JSON.stringify(avatarPalDatum)); }); - pal.sendToQml({method: 'users', params: data}); + pal.sendToQml({ method: 'users', params: data }); + if (selectData) { + selectData[2] = true; + pal.sendToQml({ method: 'select', params: selectData }); + } } // The function that handles the reply from the server @@ -388,7 +392,7 @@ function removeOverlays() { function handleClick(pickRay) { ExtendedOverlay.applyPickRay(pickRay, function (overlay) { // Don't select directly. Tell qml, who will give us back a list of ids. - var message = {method: 'select', params: [[overlay.key], !overlay.selected]}; + var message = {method: 'select', params: [[overlay.key], !overlay.selected, false]}; pal.sendToQml(message); return true; });