forked from qt-creator/qt-creator
Android: Remove Service management from AndroidManifestEditorWidget
Any manipulation of an AndroidManifest.xml document in the AndroidManifestEditor would heavily modify present <service/> entries. Even if the Service widget is not used. Furthermore, the service handling code would filter out any present white space. A visual XML editor must keep any present information (ideally also formatting and white spaces) intact and should only apply the minimal amount of change when saving. This can be challenging if the loaded AndroidManifest.xml has before been hand-edited. Implementing and maintaining a visual XML editor requires much effort. It has to be considered if such effort is reasonable for a specialist feature like creating Android services, especially since the "Manifest elements reference" is very well documented on developer.android.com and the Qt- specific parts in the Qt docs. This change removes the service management from the AndroidManifestEditorWidget. A good, text-based XML editor that considers the AndroidManifest schema is a valid substitute. Fixes: QTCREATORBUG-28024 Change-Id: I73ce5b5c548c5bee6fb7fe2d50d83e0ca3937208 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
@@ -39,7 +39,6 @@ add_qtc_plugin(Android
|
||||
androidsdkmanagerwidget.cpp androidsdkmanagerwidget.h
|
||||
androidsdkmodel.cpp androidsdkmodel.h
|
||||
androidsdkpackage.cpp androidsdkpackage.h
|
||||
androidservicewidget.cpp androidservicewidget.h androidservicewidget_p.h
|
||||
androidsettingswidget.cpp androidsettingswidget.h
|
||||
androidsignaloperation.cpp androidsignaloperation.h
|
||||
androidtoolchain.cpp androidtoolchain.h
|
||||
|
@@ -86,9 +86,6 @@ Project {
|
||||
"androidsdkmodel.h",
|
||||
"androidsdkpackage.cpp",
|
||||
"androidsdkpackage.h",
|
||||
"androidservicewidget.cpp",
|
||||
"androidservicewidget.h",
|
||||
"androidservicewidget_p.h",
|
||||
"androidsettingswidget.cpp",
|
||||
"androidsettingswidget.h",
|
||||
"androidsignaloperation.cpp",
|
||||
|
@@ -8,7 +8,6 @@
|
||||
#include "androidmanifesteditor.h"
|
||||
#include "androidmanifesteditoriconcontainerwidget.h"
|
||||
#include "androidmanifesteditorwidget.h"
|
||||
#include "androidservicewidget.h"
|
||||
#include "androidtr.h"
|
||||
#include "splashscreencontainerwidget.h"
|
||||
|
||||
@@ -47,7 +46,6 @@
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListView>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QScrollArea>
|
||||
@@ -445,18 +443,10 @@ QGroupBox *AndroidManifestEditorWidget::createAdvancedGroupBox(QWidget *parent)
|
||||
m_iconButtons = new AndroidManifestEditorIconContainerWidget(otherGroupBox, m_textEditorWidget);
|
||||
m_advanvedTabWidget->addTab(m_iconButtons, Tr::tr("Application icon"));
|
||||
|
||||
m_services = new AndroidServiceWidget(otherGroupBox);
|
||||
m_advanvedTabWidget->addTab(m_services, Tr::tr("Android services"));
|
||||
|
||||
m_splashButtons = new SplashScreenContainerWidget(otherGroupBox,
|
||||
m_textEditorWidget);
|
||||
m_advanvedTabWidget->addTab(m_splashButtons, Tr::tr("Splash screen"));
|
||||
|
||||
connect(m_services, &AndroidServiceWidget::servicesModified, this, [this] { setDirty(); });
|
||||
connect(m_services, &AndroidServiceWidget::servicesModified,
|
||||
this, &AndroidManifestEditorWidget::clearInvalidServiceInfo);
|
||||
connect(m_services, &AndroidServiceWidget::servicesInvalid,
|
||||
this, &AndroidManifestEditorWidget::setInvalidServiceInfo);
|
||||
connect(m_splashButtons, &SplashScreenContainerWidget::splashScreensModified,
|
||||
this, [this] { setDirty(); });
|
||||
connect(m_iconButtons, &AndroidManifestEditorIconContainerWidget::iconsModified,
|
||||
@@ -534,14 +524,6 @@ 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();
|
||||
@@ -550,12 +532,6 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
|
||||
return true;
|
||||
|
||||
if (page == Source) {
|
||||
if (!servicesValid(m_services->services())) {
|
||||
QMessageBox::critical(nullptr, Tr::tr("Service Definition Invalid"),
|
||||
Tr::tr("Cannot switch to source when there are invalid services."));
|
||||
m_advanvedTabWidget->setCurrentIndex(1);
|
||||
return false;
|
||||
}
|
||||
syncToEditor();
|
||||
} else {
|
||||
if (!syncToWidgets())
|
||||
@@ -577,11 +553,6 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
|
||||
void AndroidManifestEditorWidget::preSave()
|
||||
{
|
||||
if (activePage() != Source) {
|
||||
if (!servicesValid(m_services->services())) {
|
||||
QMessageBox::critical(nullptr, Tr::tr("Service Definition Invalid"),
|
||||
Tr::tr("Cannot save when there are invalid services."));
|
||||
return;
|
||||
}
|
||||
syncToEditor();
|
||||
}
|
||||
|
||||
@@ -728,25 +699,6 @@ void AndroidManifestEditorWidget::hideInfoBar()
|
||||
m_timerParseCheck.stop();
|
||||
}
|
||||
|
||||
static const char kServicesInvalid[] = "AndroidServiceDefinitionInvalid";
|
||||
|
||||
void AndroidManifestEditorWidget::setInvalidServiceInfo()
|
||||
{
|
||||
Id id(kServicesInvalid);
|
||||
if (m_textEditorWidget->textDocument()->infoBar()->containsInfo(id))
|
||||
return;
|
||||
InfoBarEntry info(id,
|
||||
Tr::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(Id(kServicesInvalid));
|
||||
}
|
||||
|
||||
void setApiLevel(QComboBox *box, const QDomElement &element, const QString &attribute)
|
||||
{
|
||||
if (!element.isNull() && element.hasAttribute(attribute)) {
|
||||
@@ -886,33 +838,6 @@ 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_splashButtons->loadImages();
|
||||
|
||||
@@ -1092,19 +1017,13 @@ 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);
|
||||
}
|
||||
@@ -1162,139 +1081,6 @@ void AndroidManifestEditorWidget::parseSplashScreen(QXmlStreamWriter &writer)
|
||||
writer);
|
||||
}
|
||||
|
||||
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 writeMetadataElement(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 addServiceArgumentsAndLibName(const AndroidServiceData &service, QXmlStreamWriter &writer)
|
||||
{
|
||||
if (!service.isRunInExternalLibrary() && !service.serviceArguments().isEmpty())
|
||||
writeMetadataElement("android.app.arguments", "android:value", service.serviceArguments(), writer);
|
||||
if (service.isRunInExternalLibrary() && !service.externalLibraryName().isEmpty())
|
||||
writeMetadataElement("android.app.lib_name", "android:value", service.externalLibraryName(), writer);
|
||||
else
|
||||
writeMetadataElement("android.app.lib_name", "android:value", "-- %%INSERT_APP_LIB_NAME%% --", writer);
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::addServiceMetadata(QXmlStreamWriter &writer)
|
||||
{
|
||||
// The values below are no longer needed in Qt 6.2+, don't add them
|
||||
const Target *target = androidTarget(m_textEditorWidget->textDocument()->filePath());
|
||||
if (target) {
|
||||
const QtSupport::QtVersion *qt = QtSupport::QtKitAspect::qtVersion(target->kit());
|
||||
if (qt && qt->qtVersion() >= QVersionNumber(6, 2))
|
||||
return;
|
||||
}
|
||||
writeMetadataElement("android.app.qt_sources_resource_id", "android:resource", "@array/qt_sources", writer);
|
||||
writeMetadataElement("android.app.repository", "android:value", "default", writer);
|
||||
writeMetadataElement("android.app.qt_libs_resource_id", "android:resource", "@array/qt_libs", writer);
|
||||
writeMetadataElement("android.app.bundled_libs_resource_id", "android:resource", "@array/bundled_libs", writer);
|
||||
writeMetadataElement("android.app.bundle_local_qt_libs", "android:value", "-- %%BUNDLE_LOCAL_QT_LIBS%% --", writer);
|
||||
writeMetadataElement("android.app.use_local_qt_libs", "android:value", "-- %%USE_LOCAL_QT_LIBS%% --", writer);
|
||||
writeMetadataElement("android.app.libs_prefix", "android:value", "/data/local/tmp/qt/", writer);
|
||||
writeMetadataElement("android.app.load_local_libs_resource_id", "android:resource", "@array/load_local_libs", writer);
|
||||
writeMetadataElement("android.app.load_local_jars", "android:value", "-- %%INSERT_LOCAL_JARS%% --", writer);
|
||||
writeMetadataElement("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());
|
||||
@@ -1326,7 +1112,7 @@ void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlSt
|
||||
if (reader.name() == QLatin1String("meta-data")) {
|
||||
QString metaTagName = reader.attributes().value(QLatin1String("android:name")).toString();
|
||||
if (metaTagName.startsWith(QLatin1String("android.app.splash_screen")))
|
||||
parseUnknownElement(reader, writer, true);
|
||||
parseUnknownElement(reader, writer);
|
||||
else
|
||||
found = parseMetaData(reader, writer) || found; // ORDER MATTERS
|
||||
} else
|
||||
@@ -1474,23 +1260,19 @@ QString AndroidManifestEditorWidget::parseComment(QXmlStreamReader &reader, QXml
|
||||
return commentText;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer,
|
||||
bool ignore)
|
||||
void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer)
|
||||
{
|
||||
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, ignore);
|
||||
parseUnknownElement(reader, writer);
|
||||
} else {
|
||||
if (!ignore)
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
reader.readNext();
|
||||
|
@@ -33,7 +33,6 @@ namespace Android::Internal {
|
||||
class AndroidManifestEditor;
|
||||
class AndroidManifestEditorIconContainerWidget;
|
||||
class AndroidManifestEditorWidget;
|
||||
class AndroidServiceWidget;
|
||||
class SplashScreenContainerWidget;
|
||||
|
||||
class PermissionsModel: public QAbstractListModel
|
||||
@@ -114,14 +113,10 @@ private:
|
||||
|
||||
void updateInfoBar(const QString &errorMessage, int line, int column);
|
||||
void hideInfoBar();
|
||||
void setInvalidServiceInfo();
|
||||
void clearInvalidServiceInfo();
|
||||
|
||||
void parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseApplication(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseSplashScreen(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);
|
||||
@@ -129,15 +124,13 @@ private:
|
||||
QXmlStreamWriter &writer,
|
||||
const QSet<QString> &permissions);
|
||||
QString parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer, bool ignore=false);
|
||||
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||
|
||||
QGroupBox *createPermissionsGroupBox(QWidget *parent);
|
||||
QGroupBox *createPackageFormLayout(QWidget *parent);
|
||||
QGroupBox *createApplicationGroupBox(QWidget *parent);
|
||||
QGroupBox *createAdvancedGroupBox(QWidget *parent);
|
||||
|
||||
void addServiceMetadata(QXmlStreamWriter &writer);
|
||||
|
||||
bool m_dirty = false; // indicates that we need to call syncToEditor()
|
||||
bool m_stayClean = false;
|
||||
int m_errorLine;
|
||||
@@ -170,8 +163,6 @@ private:
|
||||
QPushButton *m_removePermissionButton;
|
||||
QComboBox *m_permissionsComboBox;
|
||||
|
||||
// Services
|
||||
AndroidServiceWidget *m_services;
|
||||
QTimer m_timerParseCheck;
|
||||
TextEditor::TextEditorWidget *m_textEditorWidget;
|
||||
AndroidManifestEditor *m_editor;
|
||||
|
@@ -1,382 +0,0 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "androidservicewidget.h"
|
||||
#include "androidservicewidget_p.h"
|
||||
#include "androidtr.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());
|
||||
}
|
||||
|
||||
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();
|
||||
emit 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::tr("The name of the class implementing the service.");
|
||||
else if (section == 1)
|
||||
return Tr::tr("Checked if the service is run in an external process.");
|
||||
else if (section == 2)
|
||||
return Tr::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::tr("Checked if the service is in a separate dynamic library.");
|
||||
else if (section == 4)
|
||||
return Tr::tr("The name of the separate dynamic library.");
|
||||
else if (section == 5)
|
||||
return Tr::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::tr("Service class name.");
|
||||
else if (section == 1)
|
||||
return Tr::tr("Run in external process.");
|
||||
else if (section == 2)
|
||||
return Tr::tr("Process name.");
|
||||
else if (section == 3)
|
||||
return Tr::tr("Run in external library.");
|
||||
else if (section == 4)
|
||||
return Tr::tr("Library name.");
|
||||
else if (section == 5)
|
||||
return Tr::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::tr("Run in external process.");
|
||||
else if (index.column() == 2)
|
||||
return m_services[index.row()].externalProcessName();
|
||||
else if (index.column() == 3)
|
||||
return Tr::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::tr("The class name must be set.");
|
||||
else if (index.column() == 2 && m_services[index.row()].isRunInExternalProcess())
|
||||
return Tr::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::tr("The library name must be set for a service 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();
|
||||
}
|
||||
}
|
||||
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);
|
||||
emit dataChanged(createIndex(index.row(), 0), createIndex(index.row(), 5));
|
||||
if (m_services[index.row()].isValid())
|
||||
emit validDataChanged();
|
||||
else
|
||||
emit 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());
|
||||
}
|
||||
emit dataChanged(index, index);
|
||||
if (m_services[index.row()].isValid())
|
||||
emit validDataChanged();
|
||||
else
|
||||
emit 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::tr("Add"));
|
||||
buttonLayout->addWidget(addButton, 0, 0);
|
||||
m_removeButton = new QPushButton(this);
|
||||
m_removeButton->setText(Tr::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, [this](const QItemSelection &selected) {
|
||||
if (!selected.isEmpty())
|
||||
m_removeButton->setEnabled(true);
|
||||
});
|
||||
connect(m_model.data(), &AndroidServiceWidget::AndroidServiceModel::validDataChanged,
|
||||
this, [this] { emit servicesModified(); });
|
||||
connect(m_model.data(), &AndroidServiceWidget::AndroidServiceModel::invalidDataChanged,
|
||||
this, [this] { emit 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);
|
||||
emit servicesModified();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
@@ -1,69 +0,0 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPushButton;
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
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
|
@@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#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