Merge branch 'feature/qml_whitelist_tablet' of https://github.com/jherico/hifi into commerce_QmlWhitelist

This commit is contained in:
Zach Fox 2017-11-14 10:07:44 -08:00
commit 5290ee3b4e
15 changed files with 268 additions and 322 deletions

View file

@ -307,7 +307,6 @@ table .headers + .headers td {
margin-right: 20px;
}
#visit-domain-link,
.blue-link {
font-size: 14px;
text-decoration-line: underline;

View file

@ -39,7 +39,7 @@
<li><a href="/settings/">Settings</a></li>
</ul>
<ul class="nav navbar-right navbar-nav">
<li><a id="visit-domain-link" target="_blank" style="display: none;">Visit domain in VR</a></li>
<li><a id="visit-domain-link" class="blue-link" target="_blank" style="display: none;">Visit domain in VR</a></li>
<li><a href="#" id="restart-server"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
</ul>
</div>

View file

@ -31,6 +31,12 @@ label {
color: #373A3C;
}
.wizard-link {
font-size: 16px;
font-weight: normal;
color: #2F80ED;
}
#admin-row {
margin-top: 20px;
margin-bottom: 20px;
@ -84,6 +90,14 @@ label {
height: 169px;
}
#visit-domain-row {
margin-bottom: 68px;
#congratulation-text {
margin-bottom: 59px;
}
#visit-domain-checkbox {
margin-bottom: 23px;
}
#visit-domain-checkbox label {
margin: 0 0;
}

View file

@ -60,8 +60,7 @@
</div>
<div id="admin-row" class="row">
<p class="col-md-6">
<span id="admin-description" class="step-info"><b>Add your High Fidelity username</b> and any other usernames to grant administrator privileges.</span>
<span class='glyphicon glyphicon-info-sign' data-toggle="tooltip" title="Users who will have all the permissions for this domain."></span>
<span class="step-info"><span id="admin-description"><b>Add your High Fidelity username</b> and any other usernames</span> to grant <span class='wizard-link' data-toggle="tooltip" title="Users who will have all the permissions for this domain.">administrator privileges</span></span>
</p>
<div class="col-md-6">
<input id="admin-usernames" type="text" class="form-control">
@ -78,7 +77,7 @@
<div class="row">
<div class="col-md-12">
<p id="connect-question" class="step-info">
Who can connect to your domain?
Who can <a href='#' class='wizard-link perms-link'>connect</a> to your domain?
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='You can set this to allow a user to connect to this domain.'></span>
</p>
</div>
@ -87,25 +86,21 @@
<p class="col-md-2">
<label>
<input id="connect-none" name="connect-radio" type="radio" value="none" checked> None
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Only the admins of this domain'></span>
</label>
</p>
<p class="col-md-3">
<label>
<input id="connect-friends" name="connect-radio" type="radio" value="friends"> Friends
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are your Friends in High Fidelity'></span>
</label>
</p>
<p class="col-md-5">
<label>
<input id="connect-logged-in" name="connect-radio" type="radio" value="logged-in"> Users logged in to High Fidelity
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are currently logged into High Fidelity'></span>
<input id="connect-logged-in" name="connect-radio" type="radio" value="logged-in"> Users logged into High Fidelity
</label>
</p>
<p class="col-md-2">
<label>
<input id="connect-everyone" name="connect-radio" type="radio" value="everyone"> Everyone
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title="Users who aren't logged into High Fidelity"></span>
</label>
</p>
</div>
@ -113,7 +108,7 @@
<div class="row">
<div class="col-md-12">
<p class="step-info">
Who can rez items in your domain?
Who can <a href='#' class='wizard-link perms-link'>rez items</a> in your domain?
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='You can set this to allow a user to create entities in this domain.'></span>
</p>
</div>
@ -122,33 +117,32 @@
<p class="col-md-2">
<label>
<input id="rez-none" name="rez-radio" type="radio" value="none" checked> None
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Only the admins of this domain'></span>
</label>
</p>
<p class="col-md-3">
<label>
<input id="rez-friends" name="rez-radio" type="radio" value="friends"> Friends
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are your Friends in High Fidelity'></span>
<input id="rez-friends" name="rez-radio" type="radio" value="friends" disabled> Friends
</label>
</p>
<p class="col-md-5">
<label>
<input id="rez-logged-in" name="rez-radio" type="radio" value="logged-in"> Users logged in to High Fidelity
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are currently logged into High Fidelity'></span>
<input id="rez-logged-in" name="rez-radio" type="radio" value="logged-in" disabled> Users logged into High Fidelity
</label>
</p>
<p class="col-md-2">
<label>
<input id="rez-everyone" name="rez-radio" type="radio" value="everyone"> Everyone
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title="Users who aren't logged into High Fidelity"></span>
<input id="rez-everyone" name="rez-radio" type="radio" value="everyone" disabled> Everyone
</label>
</p>
</div>
<div class="row">
<div class="col-md-3 col-md-offset-9">
<dd class="col-md-3">
<button type="button" class="btn btn-md btn-block btn-default back-button">Back</button>
</dd>
<dd class="col-md-3 col-md-offset-6">
<button id="save-permissions" type="button" class="btn btn-md btn-block btn-primary">Next</button>
</div>
</dd>
</div>
</div>
@ -188,35 +182,37 @@
</dl>
<dl class="row">
<dd class="col-md-3 col-md-offset-9">
<dd class="col-md-3">
<button type="button" class="btn btn-md btn-block btn-default back-button">Back</button>
</dd>
<dd class="col-md-3 col-md-offset-6">
<button id="save-username-password" type="button" class="btn btn-md btn-block btn-primary">Finish</button>
</dd>
</dl>
</div>
<div class="wizard-step cloud-only col-md-7 col-centered" style="display: none;">
<div class="wizard-step cloud-only col-xs-12 col-sm-12 col-md-9 col-lg-7 col-centered" style="display: none;">
<div class="row">
<div class="col-xs-4 col-centered">
<div class="col-xs-12" align="center">
<img id="checkmark-image" src="../images/checkmark.svg">
</div>
</div>
<div class="row">
<div class="col-md-12">
<div id="congratulation-text" class="row">
<div class="col-xs-12">
<p class="step-info">Congratulations! You have successfully setup and configured your cloud hosted domain.</p>
</div>
</div>
<div id="visit-domain-row" class="row">
<div class="col-md-12">
<label><input id="go-to-domain" class="form-check-input" type="checkbox"> Visit domain in VR now</label>
</div>
</div>
<dl class="row">
<dd class="col-md-5 col-md-offset-7">
<button id="explore-settings" type="button" class="btn btn-md btn-block btn-primary">Explore all domain server settings</button>
</dd>
<div class="col-xs-12">
<div class="pull-right">
<div id="visit-domain-checkbox">
<label><input id="go-to-domain" class="form-check-input" type="checkbox"> Visit domain in VR now</label>
</div>
<button id="explore-settings" type="button" class="btn btn-md btn-primary">Explore all domain server settings</button>
</div>
</div>
</dl>
</div>

View file

@ -2,6 +2,8 @@ var Metaverse = {
accessToken: null
}
var currentStepNumber;
$(document).ready(function(){
Strings.ADD_PLACE_NOT_CONNECTED_MESSAGE = "You must have an access token to query your High Fidelity places.<br><br>" +
"Please go back and connect your account.";
@ -9,6 +11,22 @@ $(document).ready(function(){
$('#connect-account-btn').attr('href', URLs.METAVERSE_URL + "/user/tokens/new?for_domain_server=true");
$('[data-toggle="tooltip"]').tooltip();
$('.perms-link').on('click', function() {
var modal_body = '<div>';
modal_body += '<b>None</b> - No one will have permissions. Only you and the users your have given administrator privileges to will have permissions.</br></br>';
modal_body += '<b>Friends</b> - Users who are your Friends in High Fidelity.</br></br>';
modal_body += '<b>Users logged into High Fidelity</b> - Users who are currently logged into High Fidelity.</br></br>';
modal_body += '<b>Everyone</b> - Anyone who uses High Fidelity.';
modal_body += '</div>';
dialog = bootbox.dialog({
title: "User definition",
message: modal_body,
closeButton: true
});
return false;
});
$('body').on('click', '.next-button', function() {
goToNextStep();
@ -56,6 +74,36 @@ $(document).ready(function(){
exploreSettings();
});
$('input[type=radio][name=connect-radio]').change(function() {
var inputs = $('input[type=radio][name=rez-radio]');
var disabled = [];
switch (this.value) {
case 'none':
disabled = inputs.splice(1);
break;
case 'friends':
disabled = inputs.splice(2);
break;
case 'logged-in':
disabled = inputs.splice(3);
break;
case 'everyone':
disabled = inputs.splice(4);
break;
}
$.each(inputs, function() {
$(this).prop('disabled', false);
});
$.each(disabled, function() {
if ($(this).prop('checked')) {
$(inputs.last()).prop('checked', true);
}
$(this).prop('disabled', true);
});
});
reloadSettings(function(success) {
if (success) {
getDomainFromAPI();
@ -73,12 +121,12 @@ $(document).ready(function(){
});
function setupWizardSteps() {
var stepsCompleted = Settings.data.values.wizard.steps_completed;
currentStepNumber = Settings.data.values.wizard.steps_completed;
var steps = null;
if (Settings.data.values.wizard.cloud_domain) {
$('.desktop-only').remove();
$('.wizard-step').find('.back-button').hide();
$('.wizard-step:first').find('.back-button').hide();
steps = $('.wizard-step');
$(steps).each(function(i) {
@ -86,7 +134,7 @@ function setupWizardSteps() {
});
$('#permissions-description').html('You <span id="username-display"></span>have been assigned administrator privileges to this domain.');
$('#admin-description').html('Add more High Fidelity usernames to grant administrator privileges.');
$('#admin-description').html('Add more High Fidelity usernames');
} else {
$('.cloud-only').remove();
$('#save-permissions').text("Finish");
@ -96,12 +144,12 @@ function setupWizardSteps() {
$(this).children(".step-title").text("Step " + (i + 1) + " of " + steps.length);
});
if (stepsCompleted == 0) {
if (currentStepNumber == 0) {
$('#skip-wizard-button').show();
}
}
var currentStep = steps[stepsCompleted];
var currentStep = steps[currentStepNumber];
$(currentStep).show();
}
@ -204,7 +252,7 @@ function goToNextStep() {
currentStep.hide();
nextStep.show();
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1;
currentStepNumber += 1;
postSettings({
"wizard": {
@ -233,7 +281,7 @@ function goToPreviousStep() {
currentStep.hide();
previousStep.show();
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) - 1;
currentStepNumber -= 1;
postSettings({
"wizard": {
@ -439,7 +487,7 @@ function saveUsernamePassword() {
return;
}
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1;
currentStepNumber += 1;
var formJSON = {
"security": {

View file

@ -45,11 +45,13 @@ OriginalDesktop.Desktop {
Toolbar {
id: sysToolbar;
objectName: "com.highfidelity.interface.toolbar.system";
property var tablet: Tablets.getTablet("com.highfidelity.interface.tablet.system");
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
x: sysToolbar.x
y: 50
shown: true
buttonModel: tablet.buttons;
shown: tablet.toolbarMode;
}
Settings {

View file

@ -113,21 +113,6 @@ Rectangle {
}
}
onVisibleChanged: {
if (!visible) {
titleBarText.text = "Certificate";
popText.text = "PROOF OF PURCHASE";
root.certificateId = "";
root.itemName = "--";
root.itemOwner = "--";
root.itemEdition = "--";
root.dateOfPurchase = "--";
root.marketplaceUrl = "";
root.isMyCert = false;
errorText.text = "";
}
}
// This object is always used in a popup.
// This MouseArea is used to prevent a user from being
// able to click on a button/mouseArea underneath the popup.
@ -420,6 +405,18 @@ Rectangle {
case 'inspectionCertificate_setCertificateId':
root.certificateId = message.certificateId;
break;
case 'inspectionCertificate_resetCert':
titleBarText.text = "Certificate";
popText.text = "PROOF OF PURCHASE";
root.certificateId = "";
root.itemName = "--";
root.itemOwner = "--";
root.itemEdition = "--";
root.dateOfPurchase = "--";
root.marketplaceUrl = "";
root.isMyCert = false;
errorText.text = "";
break;
default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
}

View file

@ -11,6 +11,8 @@ Window {
horizontalSpacers: horizontal
verticalSpacers: !horizontal
}
property var tabletProxy;
property var buttonModel: ListModel {}
hideBackground: true
resizable: false
destroyOnCloseButton: false
@ -23,24 +25,32 @@ Window {
activator: Item {}
property bool horizontal: true
property real buttonSize: 50;
property var buttons: []
property var container: horizontal ? row : column
Settings {
category: "toolbar/" + window.objectName
property alias x: window.x
property alias y: window.y
}
Component {
id: buttonComponent
ToolbarButton {
id: toolbarButton
property var proxy: modelData;
onClicked: proxy.clicked()
Component.onCompleted: updateProperties()
onHorizontalChanged: {
var newParent = horizontal ? row : column;
for (var i in buttons) {
var child = buttons[i];
child.parent = newParent;
if (horizontal) {
child.y = 0
} else {
child.x = 0
Connections {
target: proxy;
onPropertiesChanged: updateProperties();
}
function updateProperties() {
Object.keys(proxy.properties).forEach(function (key) {
if (toolbarButton[key] !== proxy.properties[key]) {
toolbarButton[key] = proxy.properties[key];
}
});
}
}
}
@ -52,97 +62,22 @@ Window {
Row {
id: row
visible: window.horizontal
spacing: 6
Repeater {
model: buttonModel
delegate: buttonComponent
}
}
Column {
id: column
visible: !window.horizontal
spacing: 6
}
Component { id: toolbarButtonBuilder; ToolbarButton { } }
}
function findButtonIndex(name) {
if (!name) {
return -1;
}
for (var i in buttons) {
var child = buttons[i];
if (child.objectName === name) {
return i;
Repeater {
model: buttonModel
delegate: buttonComponent
}
}
return -1;
}
function findButton(name) {
var index = findButtonIndex(name);
if (index < 0) {
return;
}
return buttons[index];
}
function sortButtons() {
var children = [];
for (var i = 0; i < container.children.length; i++) {
children[i] = container.children[i];
}
children.sort(function (a, b) {
if (a.sortOrder === b.sortOrder) {
// subsort by stableOrder, because JS sort is not stable in qml.
return a.stableOrder - b.stableOrder;
} else {
return a.sortOrder - b.sortOrder;
}
});
container.children = children;
}
function addButton(properties) {
properties = properties || {}
// If a name is specified, then check if there's an existing button with that name
// and return it if so. This will allow multiple clients to listen to a single button,
// and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded
var result = findButton(properties.objectName);
if (result) {
for (var property in properties) {
result[property] = properties[property];
}
return result;
}
properties.toolbar = this;
properties.opacity = 0;
result = toolbarButtonBuilder.createObject(container, properties);
buttons.push(result);
result.opacity = 1;
sortButtons();
fadeIn(null);
return result;
}
function removeButton(name) {
var index = findButtonIndex(name);
if (index < -1) {
console.warn("Tried to remove non-existent button " + name);
return;
}
buttons[index].destroy();
buttons.splice(index, 1);
if (buttons.length === 0) {
fadeOut(null);
}
}
}

View file

@ -25,7 +25,8 @@ StateImage {
property string activeHoverIcon: button.activeIcon
property int sortOrder: 100
property int stableSortOrder: 0
property int stableOrder: 0
property var uuid;
signal clicked()

View file

@ -2259,6 +2259,10 @@ void Application::initializeUi() {
qmlRegisterType<ResourceImageItem>("Hifi", 1, 0, "ResourceImageItem");
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
{
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
tabletScriptingInterface->getTablet(SYSTEM_TABLET);
}
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create();

View file

@ -106,6 +106,9 @@ void OffscreenUi::create() {
myContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags());
myContext->setContextProperty("fileDialogHelper", new FileDialogHelper());
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
qRegisterMetaType<TabletProxy*>();
qRegisterMetaType<TabletButtonProxy*>();
myContext->setContextProperty("Tablets", tabletScriptingInterface.data());
TabletProxy* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
myContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
}

View file

@ -32,6 +32,14 @@ const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system";
const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
const QString TabletScriptingInterface::QML = "hifi/tablet/TabletRoot.qml";
static QString getUsername() {
QString username = "Unknown user";
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {
username = accountManager->getAccountInfo().getUsername();
}
return username;
}
static Setting::Handle<QStringList> tabletSoundsButtonClick("TabletSounds", QStringList { "/sounds/Button06.wav",
"/sounds/Button04.wav",
@ -39,6 +47,51 @@ static Setting::Handle<QStringList> tabletSoundsButtonClick("TabletSounds", QStr
"/sounds/Tab01.wav",
"/sounds/Tab02.wav" });
TabletButtonListModel::TabletButtonListModel() {
}
TabletButtonListModel::~TabletButtonListModel() {
}
enum ButtonDeviceRole {
ButtonProxyRole = Qt::UserRole,
};
QHash<int, QByteArray> TabletButtonListModel::_roles{
{ ButtonProxyRole, "buttonProxy" },
};
Qt::ItemFlags TabletButtonListModel::_flags{ Qt::ItemIsSelectable | Qt::ItemIsEnabled };
QVariant TabletButtonListModel::data(const QModelIndex& index, int role) const {
if (!index.isValid() || index.row() >= rowCount() || role != ButtonProxyRole) {
return QVariant();
}
return QVariant::fromValue(_buttons.at(index.row()).data());
}
TabletButtonProxy* TabletButtonListModel::addButton(const QVariant& properties) {
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
beginResetModel();
_buttons.push_back(tabletButtonProxy);
endResetModel();
return tabletButtonProxy.data();
}
void TabletButtonListModel::removeButton(TabletButtonProxy* button) {
auto itr = std::find(_buttons.begin(), _buttons.end(), button);
if (itr == _buttons.end()) {
qCWarning(uiLogging) << "TabletProxy::removeButton() could not find button " << button;
return;
}
beginResetModel();
_buttons.erase(itr);
endResetModel();
}
TabletScriptingInterface::TabletScriptingInterface() {
qmlRegisterType<TabletScriptingInterface>("TabletScriptingInterface", 1, 0, "TabletEnums");
}
@ -232,15 +285,6 @@ TabletProxy::~TabletProxy() {
disconnect(this, &TabletProxy::tabletShownChanged, this, &TabletProxy::onTabletShown);
}
QVariant TabletProxy::getButtons() {
Q_ASSERT(QThread::currentThread() == qApp->thread());
QVariantList result;
for (const auto& button : _tabletButtonProxies) {
result.push_back(QVariant::fromValue(button.data()));
}
return result;
}
void TabletProxy::setToolbarMode(bool toolbarMode) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setToolbarMode", Q_ARG(bool, toolbarMode));
@ -256,8 +300,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (toolbarMode) {
addButtonsToToolbar();
// create new desktop window
auto tabletRootWindow = new TabletRootWindow();
tabletRootWindow->initQml(QVariantMap());
@ -272,11 +314,7 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
// forward qml surface events to interface js
connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml);
} else {
removeButtonsFromToolbar();
if (_currentPathLoaded == TABLET_HOME_SOURCE_URL) {
// Tablet QML now pulls buttons from Tablet proxy
} else {
if (_currentPathLoaded != TABLET_HOME_SOURCE_URL) {
loadHomeScreen(true);
}
//check if running scripts window opened and save it for reopen in Tablet
@ -290,44 +328,8 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
_desktopWindow = nullptr;
}
}
}
#if 0
static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) {
Q_ASSERT(QThread::currentThread() == qApp->thread());
if (buttonProxy == NULL){
qCCritical(uiLogging) << __FUNCTION__ << "buttonProxy is NULL";
return;
}
QVariant resultVar;
qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "adding button " << buttonProxy;
bool hasResult = QMetaObject::invokeMethod(qmlTablet, "addButtonProxy", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, buttonProxy->getProperties()));
if (!hasResult) {
qCWarning(uiLogging) << __FUNCTION__ << " has no result";
return;
}
QObject* qmlButton = qvariant_cast<QObject *>(resultVar);
if (!qmlButton) {
qCWarning(uiLogging) << "TabletScriptingInterface addButtonProxyToQmlTablet result not a QObject";
return;
}
QObject::connect(qmlButton, SIGNAL(clicked()), buttonProxy, SLOT(clickedSlot()));
buttonProxy->setQmlButton(qobject_cast<QQuickItem*>(qmlButton));
}
#endif
static QString getUsername() {
QString username = "Unknown user";
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {
return accountManager->getAccountInfo().getUsername();
} else {
return "Unknown user";
}
emit toolbarModeChanged();
}
void TabletProxy::initialScreen(const QVariant& url) {
@ -702,20 +704,7 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) {
return result;
}
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
_tabletButtonProxies.push_back(tabletButtonProxy);
if (!_toolbarMode && _qmlTabletRoot) {
// Tablet now pulls buttons from the tablet proxy
// FIXME emit a signal so that the tablet can refresh buttons if they change
} else if (_toolbarMode) {
auto toolbarProxy = DependencyManager::get<TabletScriptingInterface>()->getSystemToolbarProxy();
if (toolbarProxy) {
// copy properties from tablet button proxy to toolbar button proxy.
auto toolbarButtonProxy = toolbarProxy->addButton(tabletButtonProxy->getProperties());
tabletButtonProxy->setToolbarButtonProxy(toolbarButtonProxy);
}
}
return tabletButtonProxy.data();
return _buttons.addButton(properties);
}
bool TabletProxy::onHomeScreen() {
@ -734,35 +723,7 @@ void TabletProxy::removeButton(TabletButtonProxy* tabletButtonProxy) {
return;
}
auto tablet = getQmlTablet();
if (!tablet) {
qCCritical(uiLogging) << "Could not find tablet in TabletRoot.qml";
}
QSharedPointer<TabletButtonProxy> buttonProxy;
{
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
if (iter == _tabletButtonProxies.end()) {
qCWarning(uiLogging) << "TabletProxy::removeButton() could not find button " << tabletButtonProxy;
return;
}
buttonProxy = *iter;
_tabletButtonProxies.erase(iter);
}
if (!_toolbarMode && _qmlTabletRoot) {
buttonProxy->setQmlButton(nullptr);
if (tablet) {
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties()));
}
} else if (_toolbarMode) {
auto toolbarProxy = DependencyManager::get<TabletScriptingInterface>()->getSystemToolbarProxy();
// remove button from toolbarProxy
if (toolbarProxy) {
toolbarProxy->removeButton(buttonProxy->getUuid().toString());
buttonProxy->setToolbarButtonProxy(nullptr);
}
}
_buttons.removeButton(tabletButtonProxy);
}
void TabletProxy::emitScriptEvent(const QVariant& msg) {
@ -801,27 +762,6 @@ void TabletProxy::desktopWindowClosed() {
gotoHomeScreen();
}
void TabletProxy::addButtonsToToolbar() {
Q_ASSERT(QThread::currentThread() == thread());
ToolbarProxy* toolbarProxy = DependencyManager::get<TabletScriptingInterface>()->getSystemToolbarProxy();
for (auto& buttonProxy : _tabletButtonProxies) {
// copy properties from tablet button proxy to toolbar button proxy.
buttonProxy->setToolbarButtonProxy(toolbarProxy->addButton(buttonProxy->getProperties()));
}
// make the toolbar visible
toolbarProxy->writeProperty("visible", QVariant(true));
}
void TabletProxy::removeButtonsFromToolbar() {
Q_ASSERT(QThread::currentThread() == thread());
ToolbarProxy* toolbarProxy = DependencyManager::get<TabletScriptingInterface>()->getSystemToolbarProxy();
for (auto& buttonProxy : _tabletButtonProxies) {
// remove button from toolbarProxy
toolbarProxy->removeButton(buttonProxy->getUuid().toString());
buttonProxy->setToolbarButtonProxy(nullptr);
}
}
QQuickItem* TabletProxy::getQmlTablet() const {
if (!_qmlTabletRoot) {
@ -891,25 +831,6 @@ TabletButtonProxy::~TabletButtonProxy() {
}
}
void TabletButtonProxy::setQmlButton(QQuickItem* qmlButton) {
Q_ASSERT(QThread::currentThread() == qApp->thread());
if (_qmlButton) {
QObject::disconnect(_qmlButton, &QQuickItem::destroyed, this, nullptr);
}
_qmlButton = qmlButton;
if (_qmlButton) {
QObject::connect(_qmlButton, &QQuickItem::destroyed, this, [this] { _qmlButton = nullptr; });
}
}
void TabletButtonProxy::setToolbarButtonProxy(QObject* toolbarButtonProxy) {
Q_ASSERT(QThread::currentThread() == thread());
_toolbarButtonProxy = toolbarButtonProxy;
if (_toolbarButtonProxy) {
QObject::connect(_toolbarButtonProxy, SIGNAL(clicked()), this, SLOT(clickedSlot()));
}
}
QVariantMap TabletButtonProxy::getProperties() {
if (QThread::currentThread() != thread()) {
QVariantMap result;
@ -926,20 +847,19 @@ void TabletButtonProxy::editProperties(const QVariantMap& properties) {
return;
}
bool changed = false;
QVariantMap::const_iterator iter = properties.constBegin();
while (iter != properties.constEnd()) {
const auto& key = iter.key();
const auto& value = iter.value();
if (!_properties.contains(key) || _properties[key] != value) {
_properties[iter.key()] = iter.value();
if (_qmlButton) {
QMetaObject::invokeMethod(_qmlButton, "changeProperty", Qt::AutoConnection, Q_ARG(QVariant, QVariant(iter.key())), Q_ARG(QVariant, iter.value()));
}
_properties[key] = value;
changed = true;
}
++iter;
}
if (_toolbarButtonProxy) {
QMetaObject::invokeMethod(_toolbarButtonProxy, "editProperties", Qt::AutoConnection, Q_ARG(QVariantMap, properties));
if (changed) {
emit propertiesChanged();
}
}

View file

@ -12,13 +12,16 @@
#include <mutex>
#include <atomic>
#include <QObject>
#include <QVariant>
#include <QtCore/QObject>
#include <QtCore/QUuid>
#include <QtCore/QVariant>
#include <QtCore/QAbstractListModel>
#include <QtScript/QScriptValue>
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QQuickItem>
#include <QUuid>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValueIterator>
#include <QtQuick/QQuickItem>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
@ -90,6 +93,31 @@ protected:
bool _toolbarMode { false };
};
class TabletButtonListModel : public QAbstractListModel {
Q_OBJECT
public:
TabletButtonListModel();
~TabletButtonListModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override { Q_UNUSED(parent); return (int)_buttons.size(); }
QHash<int, QByteArray> roleNames() const override { return _roles; }
Qt::ItemFlags flags(const QModelIndex& index) const override { return _flags; }
QVariant data(const QModelIndex& index, int role) const override;
protected:
friend class TabletProxy;
TabletButtonProxy* addButton(const QVariant& properties);
void removeButton(TabletButtonProxy* button);
using List = std::list<QSharedPointer<TabletButtonProxy>>;
static QHash<int, QByteArray> _roles;
static Qt::ItemFlags _flags;
std::vector<QSharedPointer<TabletButtonProxy>> _buttons;
};
Q_DECLARE_METATYPE(TabletButtonListModel*);
/**jsdoc
* @class TabletProxy
* @property name {string} READ_ONLY: name of this tablet
@ -99,9 +127,10 @@ protected:
class TabletProxy : public QObject {
Q_OBJECT
Q_PROPERTY(QString name READ getName)
Q_PROPERTY(bool toolbarMode READ getToolbarMode WRITE setToolbarMode)
Q_PROPERTY(bool toolbarMode READ getToolbarMode WRITE setToolbarMode NOTIFY toolbarModeChanged)
Q_PROPERTY(bool landscape READ getLandscape WRITE setLandscape)
Q_PROPERTY(bool tabletShown MEMBER _tabletShown NOTIFY tabletShownChanged)
Q_PROPERTY(TabletButtonListModel* buttons READ getButtons CONSTANT)
public:
TabletProxy(QObject* parent, const QString& name);
~TabletProxy();
@ -196,8 +225,6 @@ public:
Q_INVOKABLE bool isPathLoaded(const QVariant& path);
Q_INVOKABLE QVariant getButtons();
QQuickItem* getTabletRoot() const { return _qmlTabletRoot; }
OffscreenQmlSurface* getTabletSurface();
@ -206,6 +233,7 @@ public:
QQuickItem* getQmlMenu() const;
TabletButtonListModel* getButtons() { return &_buttons; }
signals:
/**jsdoc
* Signaled when this tablet receives an event from the html/js embedded in the tablet
@ -238,20 +266,20 @@ signals:
*/
void tabletShownChanged();
void toolbarModeChanged();
protected slots:
void desktopWindowClosed();
void emitWebEvent(const QVariant& msg);
void onTabletShown();
protected:
void loadHomeScreen(bool forceOntoHomeScreen);
void addButtonsToToolbar();
void removeButtonsFromToolbar();
bool _initialScreen { false };
QVariant _initialPath { "" };
QVariant _currentPathLoaded { "" };
QString _name;
std::vector<QSharedPointer<TabletButtonProxy>> _tabletButtonProxies;
QQuickItem* _qmlTabletRoot { nullptr };
OffscreenQmlSurface* _qmlOffscreenSurface { nullptr };
QmlWindowClass* _desktopWindow { nullptr };
@ -262,6 +290,8 @@ protected:
State _state { State::Uninitialized };
bool _landscape { false };
bool _showRunningScripts { false };
TabletButtonListModel _buttons;
};
Q_DECLARE_METATYPE(TabletProxy*);
@ -273,15 +303,11 @@ Q_DECLARE_METATYPE(TabletProxy*);
class TabletButtonProxy : public QObject {
Q_OBJECT
Q_PROPERTY(QUuid uuid READ getUuid)
Q_PROPERTY(QVariantMap properties READ getProperties NOTIFY propertiesChanged)
public:
TabletButtonProxy(const QVariantMap& properties);
~TabletButtonProxy();
Q_INVOKABLE void setQmlButton(QQuickItem* qmlButton);
void setToolbarButtonProxy(QObject* toolbarButtonProxy);
QUuid getUuid() const { return _uuid; }
/**jsdoc
@ -298,9 +324,6 @@ public:
*/
Q_INVOKABLE void editProperties(const QVariantMap& properties);
public slots:
void clickedSlot() { emit clicked(); }
signals:
/**jsdoc
* Signaled when this button has been clicked on by the user.
@ -308,12 +331,11 @@ signals:
* @returns {Signal}
*/
void clicked();
void propertiesChanged();
protected:
QUuid _uuid;
int _stableOrder;
QQuickItem* _qmlButton { nullptr };
QObject* _toolbarButtonProxy { nullptr };
QVariantMap _properties;
};

View file

@ -128,6 +128,12 @@
} else {
ContextOverlay.isInMarketplaceInspectionMode = false;
}
if (!onCommerceScreen) {
tablet.sendToQml({
method: 'inspectionCertificate_resetCert'
});
}
}
function openWallet() {

View file

@ -13,7 +13,6 @@
#include <PathUtils.h>
QTEST_MAIN(PathUtilsTests)
void PathUtilsTests::testPathUtils() {