forked from qt-creator/qt-creator
Android: add service editor to manifest editor
Task-number: QTCREATORBUG-23937 Change-Id: Iec0435721504df744ec985bd3e5cefcc0700e852 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
@@ -40,6 +40,7 @@ add_qtc_plugin(Android
|
||||
androidsdkmanagerwidget.cpp androidsdkmanagerwidget.h androidsdkmanagerwidget.ui
|
||||
androidsdkmodel.cpp androidsdkmodel.h
|
||||
androidsdkpackage.cpp androidsdkpackage.h
|
||||
androidservicewidget.cpp androidservicewidget.h androidservicewidget_p.h
|
||||
androidsettingswidget.cpp androidsettingswidget.h androidsettingswidget.ui
|
||||
androidsignaloperation.cpp androidsignaloperation.h
|
||||
androidtoolchain.cpp androidtoolchain.h
|
||||
|
@@ -13,6 +13,8 @@ HEADERS += \
|
||||
androidmanifesteditoriconwidget.h \
|
||||
androidrunconfiguration.h \
|
||||
androidruncontrol.h \
|
||||
androidservicewidget.h \
|
||||
androidservicewidget_p.h \
|
||||
androidsettingswidget.h \
|
||||
androidtoolchain.h \
|
||||
androiderrormessage.h \
|
||||
@@ -60,6 +62,7 @@ SOURCES += \
|
||||
androidmanifesteditoriconwidget.cpp \
|
||||
androidrunconfiguration.cpp \
|
||||
androidruncontrol.cpp \
|
||||
androidservicewidget.cpp \
|
||||
androidsettingswidget.cpp \
|
||||
androidtoolchain.cpp \
|
||||
androiderrormessage.cpp \
|
||||
|
@@ -93,6 +93,9 @@ Project {
|
||||
"androidsdkmodel.h",
|
||||
"androidsdkpackage.cpp",
|
||||
"androidsdkpackage.h",
|
||||
"androidservicewidget.cpp",
|
||||
"androidservicewidget.h",
|
||||
"androidservicewidget_p.h",
|
||||
"androidsettingswidget.cpp",
|
||||
"androidsettingswidget.h",
|
||||
"androidsettingswidget.ui",
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "androidconstants.h"
|
||||
#include "androidmanifestdocument.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidservicewidget.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/infobar.h>
|
||||
@@ -68,6 +69,7 @@
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListView>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QSpinBox>
|
||||
@@ -253,6 +255,9 @@ void AndroidManifestEditorWidget::initializePage()
|
||||
|
||||
formLayout->addRow(QString(), m_iconButtons);
|
||||
|
||||
m_services = new AndroidServiceWidget(this);
|
||||
formLayout->addRow(tr("Android services:"), m_services);
|
||||
|
||||
applicationGroupBox->setLayout(formLayout);
|
||||
|
||||
connect(m_appNameLineEdit, &QLineEdit::textEdited,
|
||||
@@ -264,6 +269,12 @@ void AndroidManifestEditorWidget::initializePage()
|
||||
connect(m_styleExtractMethod,
|
||||
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, setDirtyFunc);
|
||||
connect(m_services, &AndroidServiceWidget::servicesModified,
|
||||
this, setDirtyFunc);
|
||||
connect(m_services, &AndroidServiceWidget::servicesModified,
|
||||
this, &AndroidManifestEditorWidget::clearInvalidServiceInfo);
|
||||
connect(m_services, &AndroidServiceWidget::servicesInvalid,
|
||||
this, &AndroidManifestEditorWidget::setInvalidServiceInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -539,6 +550,14 @@ AndroidManifestEditorWidget::EditorPage AndroidManifestEditorWidget::activePage(
|
||||
return AndroidManifestEditorWidget::EditorPage(currentIndex());
|
||||
}
|
||||
|
||||
bool servicesValid(const QList<AndroidServiceData> &services)
|
||||
{
|
||||
for (auto &&x : services)
|
||||
if (!x.isValid())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
|
||||
{
|
||||
EditorPage prevPage = activePage();
|
||||
@@ -547,6 +566,11 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
|
||||
return true;
|
||||
|
||||
if (page == Source) {
|
||||
if (!servicesValid(m_services->services())) {
|
||||
QMessageBox::critical(nullptr, tr("Service Definition Invalid"),
|
||||
tr("Cannot switch to source when there are invalid services."));
|
||||
return false;
|
||||
}
|
||||
syncToEditor();
|
||||
} else {
|
||||
if (!syncToWidgets())
|
||||
@@ -567,8 +591,14 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
|
||||
|
||||
void AndroidManifestEditorWidget::preSave()
|
||||
{
|
||||
if (activePage() != Source)
|
||||
if (activePage() != Source) {
|
||||
if (!servicesValid(m_services->services())) {
|
||||
QMessageBox::critical(nullptr, tr("Service Definition Invalid"),
|
||||
tr("Cannot save when there are invalid services."));
|
||||
return;
|
||||
}
|
||||
syncToEditor();
|
||||
}
|
||||
|
||||
// no need to emit changed() since this is called as part of saving
|
||||
updateInfoBar();
|
||||
@@ -710,6 +740,25 @@ void AndroidManifestEditorWidget::hideInfoBar()
|
||||
m_timerParseCheck.stop();
|
||||
}
|
||||
|
||||
static const char kServicesInvalid[] = "AndroidServiceDefinitionInvalid";
|
||||
|
||||
void AndroidManifestEditorWidget::setInvalidServiceInfo()
|
||||
{
|
||||
Core::Id id(kServicesInvalid);
|
||||
if (m_textEditorWidget->textDocument()->infoBar()->containsInfo(id))
|
||||
return;
|
||||
Core::InfoBarEntry info(id,
|
||||
tr("Services invalid. "
|
||||
"Manifest cannot be saved. Correct the service definitions before saving."));
|
||||
m_textEditorWidget->textDocument()->infoBar()->addInfo(info);
|
||||
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::clearInvalidServiceInfo()
|
||||
{
|
||||
m_textEditorWidget->textDocument()->infoBar()->removeInfo(Core::Id(kServicesInvalid));
|
||||
}
|
||||
|
||||
void setApiLevel(QComboBox *box, const QDomElement &element, const QString &attribute)
|
||||
{
|
||||
if (!element.isNull() && element.hasAttribute(attribute)) {
|
||||
@@ -810,6 +859,33 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
|
||||
m_permissionsModel->setPermissions(permissions);
|
||||
updateAddRemovePermissionButtons();
|
||||
|
||||
QList<AndroidServiceData> services;
|
||||
QDomElement serviceElem = applicationElement.firstChildElement(QLatin1String("service"));
|
||||
while (!serviceElem.isNull()) {
|
||||
AndroidServiceData service;
|
||||
service.setClassName(serviceElem.attribute(QLatin1String("android:name")));
|
||||
QString process = serviceElem.attribute(QLatin1String("android:process"));
|
||||
service.setRunInExternalProcess(!process.isEmpty());
|
||||
service.setExternalProcessName(process);
|
||||
QDomElement serviceMetadataElem = serviceElem.firstChildElement(QLatin1String("meta-data"));
|
||||
while (!serviceMetadataElem.isNull()) {
|
||||
QString metadataName = serviceMetadataElem.attribute(QLatin1String("android:name"));
|
||||
if (metadataName == QLatin1String("android.app.lib_name")) {
|
||||
QString metadataValue = serviceMetadataElem.attribute(QLatin1String("android:value"));
|
||||
service.setRunInExternalLibrary(metadataValue != QLatin1String("-- %%INSERT_APP_LIB_NAME%% --"));
|
||||
service.setExternalLibraryName(metadataValue);
|
||||
}
|
||||
else if (metadataName == QLatin1String("android.app.arguments")) {
|
||||
QString metadataValue = serviceMetadataElem.attribute(QLatin1String("android:value"));
|
||||
service.setServiceArguments(metadataValue);
|
||||
}
|
||||
serviceMetadataElem = serviceMetadataElem.nextSiblingElement(QLatin1String("meta-data"));
|
||||
}
|
||||
services << service;
|
||||
serviceElem = serviceElem.nextSiblingElement(QLatin1String("service"));
|
||||
}
|
||||
m_services->setServices(services);
|
||||
|
||||
m_iconButtons->loadIcons();
|
||||
|
||||
m_stayClean = false;
|
||||
@@ -988,13 +1064,19 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
if (reader.isEndElement()) {
|
||||
parseNewServices(writer);
|
||||
writer.writeCurrentToken(reader);
|
||||
m_services->servicesSaved();
|
||||
return;
|
||||
} else if (reader.isStartElement()) {
|
||||
if (reader.name() == QLatin1String("activity"))
|
||||
parseActivity(reader, writer);
|
||||
else if (reader.name() == QLatin1String("service"))
|
||||
parseService(reader, writer);
|
||||
else
|
||||
parseUnknownElement(reader, writer);
|
||||
} else if (reader.isWhitespace()) {
|
||||
/* no copying of whitespace */
|
||||
} else {
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
@@ -1003,6 +1085,144 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
|
||||
}
|
||||
}
|
||||
|
||||
static int findService(const QString &name, const QList<AndroidServiceData> &data)
|
||||
{
|
||||
for (int i = 0; i < data.size(); ++i) {
|
||||
if (data[i].className() == name)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void writeServiceMetadataElement(const char *name,
|
||||
const char *attributeName,
|
||||
const char *value,
|
||||
QXmlStreamWriter &writer)
|
||||
{
|
||||
writer.writeStartElement(QLatin1String("meta-data"));
|
||||
writer.writeAttribute(QLatin1String("android:name"), QLatin1String(name));
|
||||
writer.writeAttribute(QLatin1String(attributeName), QLatin1String(value));
|
||||
writer.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
static void writeServiceMetadataElement(const char *name,
|
||||
const char *attributeName,
|
||||
const QString &value,
|
||||
QXmlStreamWriter &writer)
|
||||
{
|
||||
writer.writeStartElement(QLatin1String("meta-data"));
|
||||
writer.writeAttribute(QLatin1String("android:name"), QLatin1String(name));
|
||||
writer.writeAttribute(QLatin1String(attributeName), value);
|
||||
writer.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
static void addServiceArgumentsAndLibName(const AndroidServiceData &service, QXmlStreamWriter &writer)
|
||||
{
|
||||
if (!service.isRunInExternalLibrary() && !service.serviceArguments().isEmpty())
|
||||
writeServiceMetadataElement("android.app.arguments", "android:value", service.serviceArguments(), writer);
|
||||
if (service.isRunInExternalLibrary() && !service.externalLibraryName().isEmpty())
|
||||
writeServiceMetadataElement("android.app.lib_name", "android:value", service.externalLibraryName(), writer);
|
||||
else
|
||||
writeServiceMetadataElement("android.app.lib_name", "android:value", "-- %%INSERT_APP_LIB_NAME%% --", writer);
|
||||
}
|
||||
|
||||
static void addServiceMetadata(QXmlStreamWriter &writer)
|
||||
{
|
||||
writeServiceMetadataElement("android.app.qt_sources_resource_id", "android:resource", "@array/qt_sources", writer);
|
||||
writeServiceMetadataElement("android.app.repository", "android:value", "default", writer);
|
||||
writeServiceMetadataElement("android.app.qt_libs_resource_id", "android:resource", "@array/qt_libs", writer);
|
||||
writeServiceMetadataElement("android.app.bundled_libs_resource_id", "android:resource", "@array/bundled_libs", writer);
|
||||
writeServiceMetadataElement("android.app.bundle_local_qt_libs", "android:value", "-- %%BUNDLE_LOCAL_QT_LIBS%% --", writer);
|
||||
writeServiceMetadataElement("android.app.use_local_qt_libs", "android:value", "-- %%USE_LOCAL_QT_LIBS%% --", writer);
|
||||
writeServiceMetadataElement("android.app.libs_prefix", "android:value", "/data/local/tmp/qt/", writer);
|
||||
writeServiceMetadataElement("android.app.load_local_libs_resource_id", "android:resource", "@array/load_local_libs", writer);
|
||||
writeServiceMetadataElement("android.app.load_local_jars", "android:value", "-- %%INSERT_LOCAL_JARS%% --", writer);
|
||||
writeServiceMetadataElement("android.app.static_init_classes", "android:value", "-- %%INSERT_INIT_CLASSES%% --", writer);
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::parseService(QXmlStreamReader &reader, QXmlStreamWriter &writer)
|
||||
{
|
||||
Q_ASSERT(reader.isStartElement());
|
||||
const auto &services = m_services->services();
|
||||
QString serviceName = reader.attributes().value(QLatin1String("android:name")).toString();
|
||||
int serviceIndex = findService(serviceName, services);
|
||||
const AndroidServiceData* serviceFound = (serviceIndex >= 0) ? &services[serviceIndex] : nullptr;
|
||||
if (serviceFound && serviceFound->isValid()) {
|
||||
writer.writeStartElement(reader.name().toString());
|
||||
writer.writeAttribute(QLatin1String("android:name"), serviceFound->className());
|
||||
if (serviceFound->isRunInExternalProcess())
|
||||
writer.writeAttribute(QLatin1String("android:process"), serviceFound->externalProcessName());
|
||||
}
|
||||
|
||||
reader.readNext();
|
||||
|
||||
bool bundleTagFound = false;
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
if (reader.isEndElement()) {
|
||||
if (serviceFound && serviceFound->isValid()) {
|
||||
addServiceArgumentsAndLibName(*serviceFound, writer);
|
||||
if (serviceFound->isRunInExternalProcess() && !bundleTagFound)
|
||||
addServiceMetadata(writer);
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
return;
|
||||
} else if (reader.isStartElement()) {
|
||||
if (serviceFound && !serviceFound->isValid())
|
||||
parseUnknownElement(reader, writer, true);
|
||||
else if (reader.name() == QLatin1String("meta-data")) {
|
||||
QString metaTagName = reader.attributes().value(QLatin1String("android:name")).toString();
|
||||
if (serviceFound) {
|
||||
if (metaTagName == QLatin1String("android.app.bundle_local_qt_libs"))
|
||||
bundleTagFound = true;
|
||||
if (metaTagName == QLatin1String("android.app.arguments"))
|
||||
parseUnknownElement(reader, writer, true);
|
||||
else if (metaTagName == QLatin1String("android.app.lib_name"))
|
||||
parseUnknownElement(reader, writer, true);
|
||||
else if (serviceFound->isRunInExternalProcess()
|
||||
|| metaTagName == QLatin1String("android.app.background_running"))
|
||||
parseUnknownElement(reader, writer);
|
||||
else
|
||||
parseUnknownElement(reader, writer, true);
|
||||
} else
|
||||
parseUnknownElement(reader, writer, true);
|
||||
} else
|
||||
parseUnknownElement(reader, writer, true);
|
||||
} else if (reader.isWhitespace()) {
|
||||
/* no copying of whitespace */
|
||||
} else {
|
||||
if (serviceFound)
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
reader.readNext();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::parseNewServices(QXmlStreamWriter &writer)
|
||||
{
|
||||
const auto &services = m_services->services();
|
||||
for (const auto &x : services) {
|
||||
if (x.isNewService() && x.isValid()) {
|
||||
writer.writeStartElement(QLatin1String("service"));
|
||||
writer.writeAttribute(QLatin1String("android:name"), x.className());
|
||||
if (x.isRunInExternalProcess()) {
|
||||
writer.writeAttribute(QLatin1String("android:process"),
|
||||
x.externalProcessName());
|
||||
}
|
||||
addServiceArgumentsAndLibName(x, writer);
|
||||
if (x.isRunInExternalProcess())
|
||||
addServiceMetadata(writer);
|
||||
writer.writeStartElement(QLatin1String("meta-data"));
|
||||
writer.writeAttribute(QLatin1String("android:name"), QLatin1String("android.app.background_running"));
|
||||
writer.writeAttribute(QLatin1String("android:value"), QLatin1String("true"));
|
||||
writer.writeEndElement();
|
||||
writer.writeEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer)
|
||||
{
|
||||
Q_ASSERT(reader.isStartElement());
|
||||
@@ -1180,19 +1400,23 @@ QString AndroidManifestEditorWidget::parseComment(QXmlStreamReader &reader, QXml
|
||||
return commentText;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer)
|
||||
void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer,
|
||||
bool ignore)
|
||||
{
|
||||
Q_ASSERT(reader.isStartElement());
|
||||
if (!ignore)
|
||||
writer.writeCurrentToken(reader);
|
||||
reader.readNext();
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
if (reader.isEndElement()) {
|
||||
if (!ignore)
|
||||
writer.writeCurrentToken(reader);
|
||||
return;
|
||||
} else if (reader.isStartElement()) {
|
||||
parseUnknownElement(reader, writer);
|
||||
parseUnknownElement(reader, writer, ignore);
|
||||
} else {
|
||||
if (!ignore)
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
reader.readNext();
|
||||
|
@@ -54,6 +54,7 @@ namespace Internal {
|
||||
class AndroidManifestEditor;
|
||||
class AndroidManifestEditorIconContainerWidget;
|
||||
class AndroidManifestEditorWidget;
|
||||
class AndroidServiceWidget;
|
||||
|
||||
class PermissionsModel: public QAbstractListModel
|
||||
{
|
||||
@@ -136,10 +137,15 @@ private:
|
||||
|
||||
void updateInfoBar(const QString &errorMessage, int line, int column);
|
||||
void hideInfoBar();
|
||||
void setInvalidServiceInfo();
|
||||
void clearInvalidServiceInfo();
|
||||
|
||||
void updateTargetComboBox();
|
||||
|
||||
void parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseApplication(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseService(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseNewServices(QXmlStreamWriter &writer);
|
||||
void parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
bool parseMetaData(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseUsesSdk(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
@@ -147,7 +153,7 @@ private:
|
||||
QXmlStreamWriter &writer,
|
||||
const QSet<QString> &permissions);
|
||||
QString parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer, bool ignore=false);
|
||||
|
||||
bool m_dirty; // indicates that we need to call syncToEditor()
|
||||
bool m_stayClean;
|
||||
@@ -178,6 +184,8 @@ private:
|
||||
QPushButton *m_removePermissionButton;
|
||||
QComboBox *m_permissionsComboBox;
|
||||
|
||||
// Services
|
||||
AndroidServiceWidget *m_services;
|
||||
QTimer m_timerParseCheck;
|
||||
TextEditor::TextEditorWidget *m_textEditorWidget;
|
||||
AndroidManifestEditor *m_editor;
|
||||
|
410
src/plugins/android/androidservicewidget.cpp
Normal file
410
src/plugins/android/androidservicewidget.cpp
Normal file
@@ -0,0 +1,410 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "androidservicewidget.h"
|
||||
#include "androidservicewidget_p.h"
|
||||
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
bool AndroidServiceData::isValid() const
|
||||
{
|
||||
return !m_className.isEmpty()
|
||||
&& (!m_isRunInExternalProcess || !m_externalProcessName.isEmpty())
|
||||
&& (!m_isRunInExternalLibrary || !m_externalLibName.isEmpty())
|
||||
&& (m_isRunInExternalLibrary || !m_serviceArguments.isEmpty());
|
||||
}
|
||||
|
||||
void AndroidServiceData::setClassName(const QString &className)
|
||||
{
|
||||
m_className = className;
|
||||
}
|
||||
|
||||
QString AndroidServiceData::className() const
|
||||
{
|
||||
return m_className;
|
||||
}
|
||||
|
||||
void AndroidServiceData::setRunInExternalProcess(bool isRunInExternalProcess)
|
||||
{
|
||||
m_isRunInExternalProcess = isRunInExternalProcess;
|
||||
if (!m_isRunInExternalProcess) {
|
||||
m_isRunInExternalLibrary = false;
|
||||
m_externalProcessName.clear();
|
||||
m_externalLibName.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool AndroidServiceData::isRunInExternalProcess() const
|
||||
{
|
||||
return m_isRunInExternalProcess;
|
||||
}
|
||||
|
||||
void AndroidServiceData::setExternalProcessName(const QString &externalProcessName)
|
||||
{
|
||||
if (m_isRunInExternalProcess)
|
||||
m_externalProcessName = externalProcessName;
|
||||
}
|
||||
|
||||
QString AndroidServiceData::externalProcessName() const
|
||||
{
|
||||
return m_externalProcessName;
|
||||
}
|
||||
|
||||
void AndroidServiceData::setRunInExternalLibrary(bool isRunInExternalLibrary)
|
||||
{
|
||||
if (m_isRunInExternalProcess)
|
||||
m_isRunInExternalLibrary = isRunInExternalLibrary;
|
||||
if (!m_isRunInExternalLibrary)
|
||||
m_externalLibName.clear();
|
||||
else
|
||||
m_serviceArguments.clear();
|
||||
}
|
||||
|
||||
bool AndroidServiceData::isRunInExternalLibrary() const
|
||||
{
|
||||
return m_isRunInExternalLibrary;
|
||||
}
|
||||
|
||||
void AndroidServiceData::setExternalLibraryName(const QString &externalLibraryName)
|
||||
{
|
||||
if (m_isRunInExternalLibrary)
|
||||
m_externalLibName = externalLibraryName;
|
||||
}
|
||||
|
||||
QString AndroidServiceData::externalLibraryName() const
|
||||
{
|
||||
return m_externalLibName;
|
||||
}
|
||||
|
||||
void AndroidServiceData::setServiceArguments(const QString &serviceArguments)
|
||||
{
|
||||
if (!m_isRunInExternalLibrary)
|
||||
m_serviceArguments = serviceArguments;
|
||||
}
|
||||
|
||||
QString AndroidServiceData::serviceArguments() const
|
||||
{
|
||||
return m_serviceArguments;
|
||||
}
|
||||
|
||||
void AndroidServiceData::setNewService(bool isNewService)
|
||||
{
|
||||
m_isNewService = isNewService;
|
||||
}
|
||||
|
||||
bool AndroidServiceData::isNewService() const
|
||||
{
|
||||
return m_isNewService;
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::AndroidServiceModel::setServices(const QList<AndroidServiceData> &androidServices)
|
||||
{
|
||||
beginResetModel();
|
||||
m_services = androidServices;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
const QList<AndroidServiceData> &AndroidServiceWidget::AndroidServiceModel::services()
|
||||
{
|
||||
return m_services;
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::AndroidServiceModel::addService()
|
||||
{
|
||||
int rowIndex = m_services.size();
|
||||
beginInsertRows(QModelIndex(), rowIndex, rowIndex);
|
||||
AndroidServiceData service;
|
||||
service.setNewService(true);
|
||||
m_services.push_back(service);
|
||||
endInsertRows();
|
||||
invalidDataChanged();
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::AndroidServiceModel::removeService(int row)
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_services.removeAt(row);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::AndroidServiceModel::servicesSaved()
|
||||
{
|
||||
for (auto && x : m_services)
|
||||
x.setNewService(false);
|
||||
}
|
||||
|
||||
int AndroidServiceWidget::AndroidServiceModel::rowCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return m_services.count();
|
||||
}
|
||||
|
||||
int AndroidServiceWidget::AndroidServiceModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
Qt::ItemFlags AndroidServiceWidget::AndroidServiceModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() == 0)
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
||||
else if (index.column() == 1)
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
||||
else if (index.column() == 2 && index.row() <= m_services.count()) {
|
||||
if (m_services[index.row()].isRunInExternalProcess())
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
||||
return Qt::ItemIsSelectable;
|
||||
} else if (index.column() == 3 && index.row() <= m_services.count()) {
|
||||
if (m_services[index.row()].isRunInExternalProcess())
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
||||
return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
||||
} else if (index.column() == 4 && index.row() <= m_services.count()) {
|
||||
if (m_services[index.row()].isRunInExternalLibrary())
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
||||
return Qt::ItemIsSelectable;
|
||||
} else if (index.column() == 5 && index.row() <= m_services.count()) {
|
||||
if (!m_services[index.row()].isRunInExternalLibrary())
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
||||
return Qt::ItemIsSelectable;
|
||||
}
|
||||
return Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
QVariant AndroidServiceWidget::AndroidServiceModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::ToolTipRole && orientation == Qt::Horizontal) {
|
||||
if (section == 0)
|
||||
return tr("The name of the class implementing the service");
|
||||
else if (section == 1)
|
||||
return tr("Checked if the service is run in an external process");
|
||||
else if (section == 2)
|
||||
return tr("The name of the external process.\n"
|
||||
"Prefix with : if the process is private, use a lowercase name if the process is global.");
|
||||
else if (section == 3)
|
||||
return tr("Checked if the service is in a separate dynamic library");
|
||||
else if (section == 4)
|
||||
return tr("The name of the separate dynamic library");
|
||||
else if (section == 5)
|
||||
return tr("The arguments for telling the app to run the service instead of the main activity");
|
||||
} else if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||
if (section == 0)
|
||||
return tr("Service class name");
|
||||
else if (section == 1)
|
||||
return tr("Run in external process");
|
||||
else if (section == 2)
|
||||
return tr("Process name");
|
||||
else if (section == 3)
|
||||
return tr("Run in external library");
|
||||
else if (section == 4)
|
||||
return tr("Library name");
|
||||
else if (section == 5)
|
||||
return tr("Service arguments");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QVariant AndroidServiceWidget::AndroidServiceModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!(index.row() >= 0 && index.row() < m_services.count()))
|
||||
return {};
|
||||
if (role == Qt::CheckStateRole) {
|
||||
if (index.column() == 3)
|
||||
return m_services[index.row()].isRunInExternalLibrary() ? Qt::Checked : Qt::Unchecked;
|
||||
else if (index.column() == 1 && index.row() <= m_services.count())
|
||||
return m_services[index.row()].isRunInExternalProcess() ? Qt::Checked : Qt::Unchecked;
|
||||
return QVariant();
|
||||
} else if (role == Qt::DisplayRole) {
|
||||
if (index.column() == 0)
|
||||
return m_services[index.row()].className();
|
||||
else if (index.column() == 1)
|
||||
return tr("Run in external process");
|
||||
else if (index.column() == 2)
|
||||
return m_services[index.row()].externalProcessName();
|
||||
else if (index.column() == 3)
|
||||
return tr("Run in external library");
|
||||
else if (index.column() == 4)
|
||||
return m_services[index.row()].externalLibraryName();
|
||||
else if (index.column() == 5)
|
||||
return m_services[index.row()].serviceArguments();
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
if (index.column() == 0 && m_services[index.row()].className().isEmpty())
|
||||
return tr("The class name must be set");
|
||||
else if (index.column() == 2 && m_services[index.row()].isRunInExternalProcess())
|
||||
return tr("The process name must be set for a service run in an external process");
|
||||
else if (index.column() == 4 && m_services[index.row()].isRunInExternalLibrary())
|
||||
return tr("The library name must be set for a service run in an external library");
|
||||
else if (index.column() == 5 && !m_services[index.row()].isRunInExternalLibrary())
|
||||
return tr("The service arguments must be set for a service not run in an external library");
|
||||
} else if (role == Qt::EditRole) {
|
||||
if (index.column() == 0)
|
||||
return m_services[index.row()].className();
|
||||
else if (index.column() == 2)
|
||||
return m_services[index.row()].externalProcessName();
|
||||
else if (index.column() == 4)
|
||||
return m_services[index.row()].externalLibraryName();
|
||||
else if (index.column() == 5)
|
||||
return m_services[index.row()].serviceArguments();
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
if (index.column() == 0) {
|
||||
if (m_services[index.row()].className().isEmpty())
|
||||
return Utils::Icons::WARNING.icon();
|
||||
} else if (index.column() == 2) {
|
||||
if (m_services[index.row()].isRunInExternalProcess()
|
||||
&& m_services[index.row()].externalProcessName().isEmpty())
|
||||
return Utils::Icons::WARNING.icon();
|
||||
} else if (index.column() == 4) {
|
||||
if (m_services[index.row()].isRunInExternalLibrary()
|
||||
&& m_services[index.row()].externalLibraryName().isEmpty())
|
||||
return Utils::Icons::WARNING.icon();
|
||||
} else if (index.column() == 5) {
|
||||
if (!m_services[index.row()].isRunInExternalLibrary()
|
||||
&& m_services[index.row()].serviceArguments().isEmpty())
|
||||
return Utils::Icons::WARNING.icon();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool AndroidServiceWidget::AndroidServiceModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!(index.row() >= 0 && index.row() < m_services.count()))
|
||||
return {};
|
||||
if (role == Qt::CheckStateRole) {
|
||||
if (index.column() == 1)
|
||||
m_services[index.row()].setRunInExternalProcess((value == Qt::Checked) ? true : false);
|
||||
else if (index.column() == 3)
|
||||
m_services[index.row()].setRunInExternalLibrary((value == Qt::Checked) ? true : false);
|
||||
dataChanged(createIndex(index.row(), 0), createIndex(index.row(), 5));
|
||||
if (m_services[index.row()].isValid())
|
||||
validDataChanged();
|
||||
else
|
||||
invalidDataChanged();
|
||||
} else if (role == Qt::EditRole) {
|
||||
if (index.column() == 0) {
|
||||
QString className = value.toString();
|
||||
if (!className.isEmpty() && className[0] != QChar('.'))
|
||||
className.push_front(QChar('.'));
|
||||
m_services[index.row()].setClassName(className);
|
||||
m_services[index.row()].setNewService(true);
|
||||
} else if (index.column() == 2) {
|
||||
m_services[index.row()].setExternalProcessName(value.toString());
|
||||
} else if (index.column() == 4) {
|
||||
m_services[index.row()].setExternalLibraryName(value.toString());
|
||||
} else if (index.column() == 5) {
|
||||
m_services[index.row()].setServiceArguments(value.toString());
|
||||
}
|
||||
dataChanged(index, index);
|
||||
if (m_services[index.row()].isValid())
|
||||
validDataChanged();
|
||||
else
|
||||
invalidDataChanged();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AndroidServiceWidget::AndroidServiceWidget(QWidget *parent) : QWidget(parent),
|
||||
m_model(new AndroidServiceModel), m_tableView(new QTableView(this))
|
||||
{
|
||||
m_tableView->setModel(m_model.data());
|
||||
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
QSizePolicy sizePolicy;
|
||||
sizePolicy.setHorizontalPolicy(QSizePolicy::Expanding);
|
||||
m_tableView->setSizePolicy(sizePolicy);
|
||||
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
auto layout = new QHBoxLayout(this);
|
||||
layout->addWidget(m_tableView, 1);
|
||||
auto buttonLayout = new QGridLayout();
|
||||
auto addButton = new QPushButton(this);
|
||||
addButton->setText(tr("Add"));
|
||||
buttonLayout->addWidget(addButton, 0, 0);
|
||||
m_removeButton = new QPushButton(this);
|
||||
m_removeButton->setText(tr("Remove"));
|
||||
m_removeButton->setEnabled(false);
|
||||
buttonLayout->addWidget(m_removeButton, 1, 0);
|
||||
layout->addLayout(buttonLayout);
|
||||
layout->setAlignment(buttonLayout, Qt::AlignTop);
|
||||
connect(addButton, &QAbstractButton::clicked,
|
||||
this, &AndroidServiceWidget::addService);
|
||||
connect(m_removeButton, &QAbstractButton::clicked,
|
||||
this, &AndroidServiceWidget::removeService);
|
||||
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
[this](const QItemSelection &selected, const QItemSelection &/*deselected*/) {
|
||||
if (!selected.isEmpty())
|
||||
m_removeButton->setEnabled(true);
|
||||
});
|
||||
connect(m_model.data(), &AndroidServiceWidget::AndroidServiceModel::validDataChanged,
|
||||
[this] {servicesModified();});
|
||||
connect(m_model.data(), &AndroidServiceWidget::AndroidServiceModel::invalidDataChanged,
|
||||
[this] {servicesInvalid();});
|
||||
}
|
||||
|
||||
AndroidServiceWidget::~AndroidServiceWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::setServices(const QList<AndroidServiceData> &androidServices)
|
||||
{
|
||||
m_removeButton->setEnabled(false);
|
||||
m_model->setServices(androidServices);
|
||||
}
|
||||
|
||||
const QList<AndroidServiceData> &AndroidServiceWidget::services()
|
||||
{
|
||||
return m_model->services();
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::servicesSaved()
|
||||
{
|
||||
m_model->servicesSaved();
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::addService()
|
||||
{
|
||||
m_model->addService();
|
||||
}
|
||||
|
||||
void AndroidServiceWidget::removeService()
|
||||
{
|
||||
auto selections = m_tableView->selectionModel()->selectedRows();
|
||||
for (const auto &x : selections) {
|
||||
m_model->removeService(x.row());
|
||||
m_removeButton->setEnabled(false);
|
||||
servicesModified();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
89
src/plugins/android/androidservicewidget.h
Normal file
89
src/plugins/android/androidservicewidget.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
class QPushButton;
|
||||
class QTableView;
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
struct AndroidServiceData
|
||||
{
|
||||
public:
|
||||
bool isValid() const;
|
||||
void setClassName(const QString &className);
|
||||
QString className() const;
|
||||
void setRunInExternalProcess(bool isRunInExternalProcess);
|
||||
bool isRunInExternalProcess() const;
|
||||
void setExternalProcessName(const QString &externalProcessName);
|
||||
QString externalProcessName() const;
|
||||
void setRunInExternalLibrary(bool isRunInExternalLibrary);
|
||||
bool isRunInExternalLibrary() const ;
|
||||
void setExternalLibraryName(const QString &externalLibraryName);
|
||||
QString externalLibraryName() const;
|
||||
void setServiceArguments(const QString &serviceArguments);
|
||||
QString serviceArguments() const;
|
||||
void setNewService(bool isNewService);
|
||||
bool isNewService() const;
|
||||
private:
|
||||
QString m_className;
|
||||
bool m_isRunInExternalProcess = false;
|
||||
QString m_externalProcessName;
|
||||
bool m_isRunInExternalLibrary = false;
|
||||
QString m_externalLibName;
|
||||
QString m_serviceArguments;
|
||||
bool m_isNewService = false;
|
||||
};
|
||||
|
||||
class AndroidServiceWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AndroidServiceWidget(QWidget *parent = nullptr);
|
||||
~AndroidServiceWidget();
|
||||
void setServices(const QList<AndroidServiceData> &androidServices);
|
||||
const QList<AndroidServiceData> &services();
|
||||
void servicesSaved();
|
||||
private:
|
||||
void addService();
|
||||
void removeService();
|
||||
signals:
|
||||
void servicesModified();
|
||||
void servicesInvalid();
|
||||
private:
|
||||
class AndroidServiceModel;
|
||||
QScopedPointer<AndroidServiceModel> m_model;
|
||||
QTableView *m_tableView;
|
||||
QPushButton *m_removeButton;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
59
src/plugins/android/androidservicewidget_p.h
Normal file
59
src/plugins/android/androidservicewidget_p.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "androidservicewidget.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidServiceWidget::AndroidServiceModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void setServices(const QList<AndroidServiceData> &androidServices);
|
||||
const QList<AndroidServiceData> &services();
|
||||
void addService();
|
||||
void removeService(int row);
|
||||
void servicesSaved();
|
||||
signals:
|
||||
void validDataChanged();
|
||||
void invalidDataChanged();
|
||||
private:
|
||||
int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
private:
|
||||
QList<AndroidServiceData> m_services;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
Reference in New Issue
Block a user