Continues migration with DDS, Common

This commit is contained in:
torsten committed 2026-07-17 12:41:42 +02:00
1 parent 9b15cee841
commit fa48db111e
668 files changed
+111841 -2

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-10-24
#
# LtsAppDescriptor (lib)
SET(LtsAppDescriptor_SRCS
lts_app_descriptor.cpp
lts_app_descriptor.h
)
NGL_ADD_LIBRARY(WS LtsAppDescriptor SHARED ${LtsAppDescriptor_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(LtsAppDescriptor
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(LtsAppDescriptor
PUBLIC
Qt5::Core
)
NGL_INSTALL_TARGET(LtsAppDescriptor)
# LtsAppDescriptorChecker
SET(LtsAppDescriptorChecker_SRCS
checker/main.cpp
)
NGL_ADD_EXECUTABLE(WS LtsAppDescriptorChecker ${LtsAppDescriptorChecker_SRCS})
NGL_TARGET_LINK_LIBRARIES(LtsAppDescriptorChecker
PRIVATE
LtsAppDescriptor
PUBLIC
Qt5::Core
)
# LtsAppDescriptorEditor => Hat niemand benutzt, wird keiner benutzen, also wird der bis auf Weiteres auch nicht an die neue Syntax angepasst.
#SET(LtsAppDescriptorEditor_SRCS
# lts_app_descriptor_editor.cpp
# lts_app_descriptor_editor.h
#)
#NGL_WRAP_UI(LtsAppDescriptorEditor_SRCS
# lts_app_descriptor_editor.ui
#)
#NGL_ADD_LIBRARY(WS NO_TRANSLATION LtsAppDescriptorEditor SHARED ${LtsAppDescriptorEditor_SRCS})
#NGL_TARGET_INCLUDE_DIRECTORIES(LtsAppDescriptorEditor
# PUBLIC
# ${CMAKE_CURRENT_SOURCE_DIR}/../
#)
#NGL_TARGET_LINK_LIBRARIES(LtsAppDescriptorEditor
# PUBLIC
# Qt5::Core
# Qt5::Widgets
# LtsAppDescriptor
#)
#NGL_INSTALL_TARGET(LtsAppDescriptorEditor) #not visible for end-user
## Executable:
#NGL_ADD_EXECUTABLE(WS NO_TRANSLATION LtsAppDescriptorEditorApp main.cpp)
#NGL_TARGET_LINK_LIBRARIES(LtsAppDescriptorEditorApp LtsAppDescriptorEditor)
+138
View File
@@ -0,0 +1,138 @@
#include <LtsAppDescriptor/lts_app_descriptor.h>
#include <QCoreApplication>
#include <QFile>
#include <QFileInfoList>
#include <QDirIterator>
#include <QTextStream>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <cstdio>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const QStringList args(a.arguments());
if (args.count() != 3)
{
printf("usage: %s <current source directory> <apps.json>\n", args.at(0).toStdString().c_str());
return -1;
}
const QString currentSrcDir(a.arguments().at(1));
const QString appsJsonFilePath(QStringLiteral("%1/%2").arg(currentSrcDir, a.arguments().at(2)));
QFile f(appsJsonFilePath);
if (!f.open(QFile::ReadOnly))
{
printf("LtsAppDescriptorChecker: cannot open apps.json at %s: %s\n", appsJsonFilePath.toStdString().c_str(), f.errorString().toStdString().c_str());
return -2;
}
printf("LtsAppDescriptorChecker: checking %s\n", appsJsonFilePath.toStdString().c_str());
QStringList lastErrors;
QStringList dummy1;
QString dummy2;
LtsAppDescriptor::AppDescriptionVector adv = LtsAppDescriptor::LtsAppDescriptor::getAppDescriptionVector(f.readAll(), lastErrors, dummy1, dummy2);
if (!lastErrors.isEmpty())
{
printf("LtsAppDescriptorChecker: apps.json at %s invalid:\n%s\n", appsJsonFilePath.toStdString().c_str(), lastErrors.join(QStringLiteral("\r\n\r\n")).toStdString().c_str());
return 1;
}
QFileInfoList guiPluginFiles;
QDirIterator it(QStringLiteral("%1/../../Plugins/").arg(currentSrcDir), QDirIterator::Subdirectories);
while (it.hasNext())
{
QString filename(it.next());
QFileInfo file(filename);
if (file.isDir())
continue;
if (file.fileName().endsWith(QStringLiteral("_gui_plugin.h"), Qt::CaseInsensitive))
guiPluginFiles.append(file);
}
QStringList filenames;
filenames.reserve(guiPluginFiles.size());
for (const QFileInfo &fi : qAsConst(guiPluginFiles))
{
filenames += fi.absoluteFilePath();
}
QStringList guiPluginIIDs;
for (const QFileInfo &fi : qAsConst(guiPluginFiles))
{
QFile f2(fi.absoluteFilePath());
if (!f2.open(QFile::ReadOnly))
continue;
QTextStream ts(&f2);
while (!ts.atEnd())
{
QString line(ts.readLine().trimmed().simplified());
static QString iidIdentifier(QStringLiteral("Q_PLUGIN_METADATA"));
if (line.contains(iidIdentifier))
{
QRegularExpression re(QStringLiteral("(?<=gui:3:).*(?=\"\\))"));
QRegularExpressionMatch match = re.match(line);
if (match.hasMatch())
{
QString matched = match.captured(0);
guiPluginIIDs += matched;
}
break;
}
}
}
bool ok = true;
for (const LtsAppDescriptor::AppDescription &appdesc : qAsConst(adv))
{
for (const LtsAppDescriptor::PluginInfo &pi : qAsConst(appdesc.pluginInfos))
{
if (!guiPluginIIDs.contains(pi.iid))
{
printf("LtsAppDescriptorChecker: apps.json at '%s' uses unknown IID '%s'\n", appsJsonFilePath.toStdString().c_str(), pi.iid.toStdString().c_str());
ok = false;
}
}
}
return !ok;
}
+215
View File
@@ -0,0 +1,215 @@
#include "lts_app_descriptor.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonParseError>
#include <QJsonValue>
#include <QCoreApplication>
namespace LtsAppDescriptor
{
static void addOptionToPlugin(PluginInfo &pluginInfo, const PluginInfo::Flag &flag)
{
pluginInfo.flags |= flag;
}
static void addOptionToPlugin(QVector<PluginInfo> &pluginInfos, const PluginInfo::Flag &flag, const QString &pluginName)
{
for (PluginInfo &pi : pluginInfos)
{
if (pi.iid == pluginName)
{
addOptionToPlugin(pi, flag);
return;
}
}
PluginInfo pi;
pi.iid = pluginName;
pi.type = PluginInfo::PluginType::GUI;
addOptionToPlugin(pi, flag);
pluginInfos.append(pi);
}
static bool addOptionsToPlugin(AppDescription &appDesc, const QString &optionIdentifier, const QStringList &ignoredPlugins,
const QJsonObject &optionsObject, const PluginInfo::Flag flag, QStringList &lastErrors,
bool atLeastOnePluginNeeded)
{
bool hasPlugins = false;
auto optionsObjectIt = optionsObject.constFind(optionIdentifier);
if (optionsObjectIt != optionsObject.constEnd())
{
const QJsonArray plugins((*optionsObjectIt).toObject()[QStringLiteral("Plugins")].toArray());
for (const auto &pluginElem : plugins)
{
const QString pluginName = pluginElem.toString();
if (!ignoredPlugins.contains(pluginName))
{
addOptionToPlugin(appDesc.pluginInfos, flag, pluginName);
hasPlugins = true;
}
}
}
if (atLeastOnePluginNeeded && !hasPlugins)
{
lastErrors.append(QCoreApplication::tr("No plugins specified for '%1' option for app '%2'").arg(optionIdentifier, appDesc.appName));
return false;
}
return true;
}
App LtsAppDescriptor::appFromInteger(int i)
{
switch (i)
{
case int(App::Login):
case int(App::Situation):
case int(App::ResourceManager):
case int(App::PlanEditor):
case int(App::BuildingViewer):
case int(App::OC):
case int(App::OrgChart):
case int(App::Scripts):
case int(App::Snapshot):
case int(App::SystemMonitor):
case int(App::Timeline):
case int(App::SymbolEditor):
case int(App::ScriptEditorEssentialsView):
case int(App::BaseDownloader):
case int(App::OnlineHelp):
case int(App::ThpSituationReplay):
case int(App::SituationTablet):
case int(App::SilhouetteEditor):
case int(App::Shootback):
case int(App::SAAs):
return static_cast<App>(i);
}
Q_ASSERT_X(false, "LtsAppDescriptor::appFromInteger", qPrintable(QStringLiteral("Unknown app id: %1").arg(i)));
return App::Login;
}
AppDescriptionVector LtsAppDescriptor::getAppDescriptionVector(const QByteArray &jsonDocument,
QStringList &lastErrors,
const QStringList &ignoredPlugins,
QString &loginPluginIid)
{
AppDescriptionVector appDescriptions;
QJsonParseError parseError;
QJsonDocument appsDoc(QJsonDocument::fromJson(jsonDocument, &parseError));
if (parseError.error != QJsonParseError::NoError)
{
int row = 0;
int column = 0;
QChar x = QLatin1Char('\n');
for (int i = 0; i < jsonDocument.count(); i++)
{
if (i == parseError.offset)
break;
if (QChar::fromLatin1(jsonDocument[i]) == x)
{
row++;
column = 0;
}
else
{
column++;
}
}
lastErrors.append(QCoreApplication::tr("JSON: %1<br>Row: %2, Column: %3").arg(parseError.errorString()).arg(row+1).arg(column+1));
return appDescriptions;
}
const QJsonObject root(appsDoc.object());
loginPluginIid = root[QStringLiteral("LoginPlugin")].toString();
const QJsonArray appArray(root[QStringLiteral("Apps")].toArray());
if (appArray.isEmpty())
{
lastErrors.append(QCoreApplication::tr("Invalid json: Could not find 'Apps' array"));
return appDescriptions;
}
for (const auto &appElem : appArray)
{
AppDescription appDesc;
const QJsonObject appObject = appElem.toObject();
appDesc.id = appFromInteger(appObject.value(QStringLiteral("Id")).toInt(-1));
if (appDesc.id == App::Login)
{
lastErrors.append(QCoreApplication::tr("App '%1': no App Id or invalid App Id given").arg(appDesc.appName));
return appDescriptions;
}
appDesc.appName = appObject.value(QStringLiteral("AppName")).toString();
const QJsonValue valueActive = appObject.value(QStringLiteral("Active"));
if (!valueActive.isUndefined())
{
if (valueActive.type() != QJsonValue::Type::Bool)
{
lastErrors.append(QCoreApplication::tr("App '%1': value App.Active is not a bool (%2)").arg(appDesc.appName).arg((int)valueActive.type()));
return appDescriptions;
}
}
appDesc.active = valueActive.toBool(false);
const QJsonValue valueVisible = appObject.value(QStringLiteral("Visible"));
if (!valueVisible.isUndefined() && valueVisible.type() != QJsonValue::Type::Bool)
{
lastErrors.append(QCoreApplication::tr("App '%1': value App.Visible is not a bool (%2)").arg(appDesc.appName).arg((int)valueVisible.type()));
return appDescriptions;
}
appDesc.visible = valueVisible.toBool(true);
const QJsonArray array(appObject.value(QStringLiteral("ACLs")).toArray());
for (const QJsonValue &value : array)
appDesc.requiredAcls.append(value.toInt());
const QJsonObject optionsObject(appObject.value(QStringLiteral("Options")).toObject());
addOptionsToPlugin(appDesc, QStringLiteral("Payloads"), ignoredPlugins, optionsObject, PluginInfo::Flag::PAYLOAD, lastErrors, false);
addOptionsToPlugin(appDesc, QStringLiteral("Actions"), ignoredPlugins, optionsObject, PluginInfo::Flag::ACTIONS, lastErrors, true );
addOptionsToPlugin(appDesc, QStringLiteral("Main"), ignoredPlugins, optionsObject, PluginInfo::Flag::MAIN, lastErrors, false);
appDescriptions.append(appDesc);
}
return appDescriptions;
}
}
+96
View File
@@ -0,0 +1,96 @@
#pragma once
#include <QVector>
#include <QStringList>
#ifndef LTSAPPDESCRIPTOR_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define LTSAPPDESCRIPTOR_EXPORT
# else
# if defined(MAKE_LTSAPPDESCRIPTOR_LIB)
# define LTSAPPDESCRIPTOR_EXPORT Q_DECL_EXPORT
# else
# define LTSAPPDESCRIPTOR_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace LtsAppDescriptor
{
enum class App
{
Login = -1,
Situation = 0,
ResourceManager = 1,
PlanEditor = 2,
BuildingViewer = 3,
OC = 4,
OrgChart = 5,
Scripts = 6,
Snapshot = 8,
SystemMonitor = 9,
Timeline = 10,
SymbolEditor = 11,
ScriptEditorEssentialsView = 12,
BaseDownloader = 13,
OnlineHelp = 14,
ThpSituationReplay = 15,
SituationTablet = 17,
SilhouetteEditor = 18,
Shootback = 19,
SAAs = 20,
};
struct PluginInfo
{
enum class PluginType
{
UNKNOWN,
DATA,
GUI,
};
enum class Flag
{
UNKNOWN = 1 << 0,
ACTIONS = 1 << 1,
MAIN = 1 << 2,
PAYLOAD = 1 << 3,
OPTION = 1 << 4,
};
PluginType type = PluginType::UNKNOWN;
QString iid;
QFlags<Flag> flags;
QStringList options;
};
struct AppDescription
{
App id = App::Login;
bool active = false;
bool visible = true;
QString appName;
QVector<int> requiredAcls;
QVector<PluginInfo> pluginInfos;
bool isValid() const { return !appName.isEmpty(); }
};
typedef QVector<AppDescription> AppDescriptionVector;
namespace LtsAppDescriptor
{
LTSAPPDESCRIPTOR_EXPORT App appFromInteger(int i);
LTSAPPDESCRIPTOR_EXPORT AppDescriptionVector getAppDescriptionVector(const QByteArray &jsonDocument, QStringList &lastErrors,
const QStringList &ignoredPlugins, QString &loginPluginIid);
}
}
+554
View File
@@ -0,0 +1,554 @@
#include "lts_app_descriptor_editor.h"
#include "ui_lts_app_descriptor_editor.h"
#include <QFile>
#include <QJsonDocument>
#include <QStringListModel>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>
#include <QDebug>
LtsAppDescriptorEditor::LtsAppDescriptorEditor(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui_LtsAppDescriptionEditor)
{
m_ui->setupUi(this);
m_vector = LtsAppDescriptor::AppDescriptionVector();
m_appIndex = QModelIndex();
m_pluginIndex = QModelIndex();
m_fileName = QString();
m_changed = false;
connect(m_ui->lvApps, SIGNAL(clicked(QModelIndex)), this, SLOT(onAppsClicked(QModelIndex)));
connect(m_ui->lvPlugins, SIGNAL(clicked(QModelIndex)), this, SLOT(onPluginsClicked(QModelIndex)));
connect(m_ui->lePluginType, SIGNAL(editingFinished()), this, SLOT(pluginTypeChanged()));
connect(m_ui->pbAddApp, SIGNAL(pressed()), this, SLOT(onAppAddClicked()));
connect(m_ui->pbAddPlugin, SIGNAL(pressed()), this, SLOT(onPluginAddClicked()));
connect(m_ui->pbDeleteApp, SIGNAL(pressed()), this, SLOT(onAppDeleteClicked()));
connect(m_ui->pbDeletePlugin, SIGNAL(pressed()), this, SLOT(onPluginDeletedClicked()));
connect(m_ui->pbUpdate, SIGNAL(pressed()), this, SLOT(onUpdateClicked()));
connect(m_ui->pbNewPlugin, SIGNAL(pressed()), this, SLOT(onNewpluginClicked()));
connect(m_ui->pbNewApp, SIGNAL(pressed()), this, SLOT(onNewAppClicked()));
connect(m_ui->lePluginName, SIGNAL(textChanged(QString)), this, SLOT(enableNewPlugin()));
connect(m_ui->lePluginType, SIGNAL(textChanged(QString)), this, SLOT(enableNewPlugin()));
m_ui->gbPlugins->setEnabled(false);
m_ui->pbDeletePlugin->setEnabled(false);
m_ui->pbDeleteApp->setEnabled(false);
m_ui->pbAddPlugin->setEnabled(false);
m_ui->pbUpdate->setEnabled(false);
m_ui->pbNewPlugin->setEnabled(false);
m_ui->pbNewApp->setEnabled(false);
QTimer::singleShot(0, this, &LtsAppDescriptorEditor::getAppDescriptionVector);
}
LtsAppDescriptorEditor::~LtsAppDescriptorEditor()
{
checkSave();
delete m_ui;
}
void LtsAppDescriptorEditor::getAppDescriptionVector()
{
m_fileName = QFileDialog::getOpenFileName(this, tr("Open JSON"), QLatin1Literal("/shd/CTC/TOOLS/TDS/TDS-source/Lts/Projects/Legatus/resources/"),
tr("JSON File (*.json)"));
if (m_fileName.isEmpty())
return;
QFile file;
file.setFileName(m_fileName);
file.open(QIODevice::ReadOnly | QIODevice::Text);
QString val(QString::fromUtf8(file.readAll()));
file.close();
QStringList errors;
m_vector = LtsAppDescriptor::LtsAppDescriptor::getAppDescriptionVector(val.toUtf8(), errors);
updateAppModel();
}
void LtsAppDescriptorEditor::onAppsClicked(const QModelIndex &index)
{
m_ui->gbPlugins->setEnabled(true);
m_ui->pbDeleteApp->setEnabled(true);
m_ui->pbAddPlugin->setEnabled(true);
m_ui->pbNewApp->setEnabled(true);
m_appIndex = index;
QStringList pluginList;
Q_FOREACH(const LtsAppDescriptor::PluginInfo &reqPlugin, m_vector.at(m_appIndex.row()).requiredPlugins)
{
LtsAppDescriptor::PluginInfo::PluginType pluginType = reqPlugin.type;
QString type;
if (pluginType == LtsAppDescriptor::PluginInfo::PluginType::DATA)
type = QLatin1String("data");
else if(pluginType == LtsAppDescriptor::PluginInfo::PluginType::GUI)
type = QLatin1String("gui");
else
type = QLatin1String("unknown");
if(type == QLatin1String("data"))
pluginList << QString(type + QLatin1String(": ") +reqPlugin.iid);
else
{
QString strFlags;
QFlags<LtsAppDescriptor::PluginInfo::Flag> flags = reqPlugin.flags;
bool actionsFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::ACTIONS);
if(actionsFlag)
strFlags.append(QLatin1String("actions "));
bool mainFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN);
if(mainFlag)
strFlags.append(QLatin1String("main "));
bool payloadFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::PAYLOAD);
if(payloadFlag)
strFlags.append(QLatin1String("payload "));
bool optionalFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::OPTION);
if(optionalFlag)
strFlags.append(QLatin1String("optional "));
pluginList << QString(type + QLatin1String(": ") + reqPlugin.iid + QLatin1String(" [ ") + strFlags + QLatin1String("]"));
}
}
updatePluginModel(pluginList);
m_ui->chbAppActive->setChecked(m_vector.at(m_appIndex.row()).active);
m_ui->leAppName->setText(m_vector.at(m_appIndex.row()).appName);
}
void LtsAppDescriptorEditor::onPluginsClicked(const QModelIndex &index)
{
m_pluginIndex = index;
m_ui->pbDeletePlugin->setEnabled(true);
m_ui->pbUpdate->setEnabled(true);
m_ui->pbNewPlugin->setEnabled(true);
const LtsAppDescriptor::PluginInfo plugin = m_vector.at(m_appIndex.row()).requiredPlugins.at(m_pluginIndex.row());
QString pluginName = plugin.iid;
m_ui->lePluginName->setText(pluginName);
LtsAppDescriptor::PluginInfo::PluginType pluginType = plugin.type;
QString type;
if (pluginType == LtsAppDescriptor::PluginInfo::PluginType::DATA)
type = QLatin1String("data");
else if(pluginType == LtsAppDescriptor::PluginInfo::PluginType::GUI)
type = QLatin1String("gui");
else
type = QLatin1String("unknown");
m_ui->lePluginType->setText(type);
if(type == QLatin1String("gui"))
{
m_ui->chbActions->setEnabled(true);
m_ui->chbMain->setEnabled(true);
m_ui->chbPayload->setEnabled(true);
QFlags<LtsAppDescriptor::PluginInfo::Flag> flags = plugin.flags;
bool actionsFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::ACTIONS);
m_ui->chbActions->setChecked(actionsFlag);
bool mainFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN);
m_ui->chbMain->setChecked(mainFlag);
bool payloadFlag = flags.testFlag(LtsAppDescriptor::PluginInfo::Flag::PAYLOAD);
m_ui->chbPayload->setChecked(payloadFlag);
}
else
{
m_ui->chbActions->setChecked(false);
m_ui->chbActions->setEnabled(false);
m_ui->chbMain->setChecked(false);
m_ui->chbMain->setEnabled(false);
m_ui->chbPayload->setChecked(false);
m_ui->chbPayload->setEnabled(false);
}
}
void LtsAppDescriptorEditor::pluginTypeChanged()
{
if(m_ui->lePluginType->text().isEmpty())
return;
if(m_ui->lePluginType->text() == QLatin1String("gui"))
{
m_ui->chbActions->setEnabled(true);
m_ui->chbMain->setEnabled(true);
m_ui->chbPayload->setEnabled(true);
}
else if(m_ui->lePluginType->text() == QLatin1String("data"))
{
m_ui->chbActions->setChecked(false);
m_ui->chbActions->setEnabled(false);
m_ui->chbMain->setChecked(false);
m_ui->chbMain->setEnabled(false);
m_ui->chbPayload->setChecked(false);
m_ui->chbPayload->setEnabled(false);
}
else
{
QMessageBox msgBox(QMessageBox::Information,
tr("Error"),
tr("Plugin Type must either be \"gui\" or \"data\"."));
msgBox.exec();
m_ui->lePluginType->setText(QString());
}
}
void LtsAppDescriptorEditor::onAppAddClicked()
{
m_changed = true;
if(m_ui->leAppName->text().isEmpty())
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("The App needs to have a name."));
msgBox.exec();
return;
}
QStringList appList;
Q_FOREACH(const LtsAppDescriptor::AppDescription &appDesc, m_vector)
{
appList << appDesc.appName;
}
if(appList.contains(m_ui->leAppName->text(),Qt::CaseInsensitive))
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("There already exists an app named \"%1\".").arg(m_ui->leAppName->text()));
msgBox.exec();
return;
}
LtsAppDescriptor::AppDescription newApp;
newApp.appName = m_ui->leAppName->text();
newApp.active = m_ui->chbAppActive->isChecked();
m_vector.append(newApp);
updateAppModel();
}
void LtsAppDescriptorEditor::onPluginAddClicked()
{
m_changed = true;
if(m_ui->lePluginType->text().isEmpty())
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("The Plugin needs to contain a type."));
msgBox.exec();
return;
}
if(m_ui->lePluginName->text().isEmpty())
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("The Plugin needs to have a name."));
msgBox.exec();
return;
}
QStringList pluginList;
Q_FOREACH(const LtsAppDescriptor::PluginInfo &pluginDesc, m_vector.at(m_appIndex.row()).requiredPlugins)
{
pluginList << pluginDesc.iid;
}
if(pluginList.contains(m_ui->lePluginName->text(),Qt::CaseInsensitive))
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("There already exists an plugin named \"%1\".").arg(m_ui->lePluginName->text()));
msgBox.exec();
return;
}
LtsAppDescriptor::PluginInfo newPlugin;
newPlugin.iid = m_ui->lePluginName->text();
if(m_ui->lePluginType->text() == QLatin1String("gui"))
newPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::GUI;
else if(m_ui->lePluginType->text() == QLatin1String("data"))
newPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::DATA;
else
newPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::UNKNOWN;
if(m_ui->chbActions->isChecked())
newPlugin.flags |= LtsAppDescriptor::PluginInfo::Flag::ACTIONS;
if(m_ui->chbMain->isChecked())
newPlugin.flags |= LtsAppDescriptor::PluginInfo::Flag::MAIN;
if(m_ui->chbPayload->isChecked())
newPlugin.flags |= LtsAppDescriptor::PluginInfo::Flag::PAYLOAD;
m_vector[m_appIndex.row()].requiredPlugins.append(newPlugin);
onAppsClicked(m_appIndex);
onNewpluginClicked();
}
void LtsAppDescriptorEditor::onAppDeleteClicked()
{
m_changed = true;
if(!m_appIndex.isValid()) return;
QMessageBox msgBox(tr("Warning"),
tr("The App \n\"%1\" \nwill be removed. Continue?").arg(m_appIndex.data().toString()),
QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No | QMessageBox::Escape,
QMessageBox::NoButton);
if (msgBox.exec() == QMessageBox::No)
return;
m_vector.remove(m_appIndex.row());
updateAppModel();
}
void LtsAppDescriptorEditor::onPluginDeletedClicked()
{
m_changed = true;
if(!m_pluginIndex.isValid()) return;
QMessageBox msgBox(tr("Warning"),
tr("The Plugin \n\"%1\" \nwill be removed. Continue?").arg(m_pluginIndex.data().toString()),
QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No | QMessageBox::Escape,
QMessageBox::NoButton);
if (msgBox.exec() == QMessageBox::No)
return;
m_vector[m_appIndex.row()].requiredPlugins.remove(m_pluginIndex.row());
m_pluginIndex = QModelIndex();
m_ui->lePluginName->setText(QString());
m_ui->lePluginType->setText(QString());
m_ui->chbActions->setChecked(false);
m_ui->chbMain->setChecked(false);
m_ui->chbPayload->setChecked(false);
m_ui->pbDeletePlugin->setEnabled(false);
m_ui->pbUpdate->setEnabled(false);
m_ui->pbNewPlugin->setEnabled(false);
onAppsClicked(m_appIndex);
}
void LtsAppDescriptorEditor::onUpdateClicked()
{
m_changed = true;
if(m_ui->lePluginType->text().isEmpty())
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("The Plugin needs to contain a type."));
msgBox.exec();
return;
}
if(m_ui->lePluginName->text().isEmpty())
{
QMessageBox msgBox(QMessageBox::Critical,
tr("Error"),
tr("The Plugin needs to have a name."));
msgBox.exec();
return;
}
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].iid = m_ui->lePluginName->text();
if(m_ui->lePluginType->text() == QLatin1String("gui"))
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].type = LtsAppDescriptor::PluginInfo::PluginType::GUI;
else if(m_ui->lePluginType->text() == QLatin1String("data"))
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].type = LtsAppDescriptor::PluginInfo::PluginType::DATA;
else
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].type = LtsAppDescriptor::PluginInfo::PluginType::UNKNOWN;
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].flags = QFlags<LtsAppDescriptor::PluginInfo::Flag>();
if(m_ui->chbActions->isChecked())
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].flags |= LtsAppDescriptor::PluginInfo::Flag::ACTIONS;
if(m_ui->chbMain->isChecked())
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].flags |= LtsAppDescriptor::PluginInfo::Flag::MAIN;
if(m_ui->chbPayload->isChecked())
m_vector[m_appIndex.row()].requiredPlugins[m_pluginIndex.row()].flags |= LtsAppDescriptor::PluginInfo::Flag::PAYLOAD;
onAppsClicked(m_appIndex);
onNewpluginClicked();
}
void LtsAppDescriptorEditor::onNewpluginClicked()
{
m_ui->lePluginName->setText(QString());
m_ui->lePluginType->setText(QString());
m_ui->chbActions->setEnabled(true);
m_ui->chbMain->setEnabled(true);
m_ui->chbPayload->setEnabled(true);
m_ui->chbActions->setChecked(false);
m_ui->chbMain->setChecked(false);
m_ui->chbPayload->setChecked(false);
m_ui->pbUpdate->setEnabled(false);
m_ui->pbNewPlugin->setEnabled(false);
m_ui->pbDeletePlugin->setEnabled(false);
if(m_pluginIndex.isValid())
m_ui->lvPlugins->selectionModel()->select(m_pluginIndex,QItemSelectionModel::Deselect);
m_pluginIndex = QModelIndex();
}
void LtsAppDescriptorEditor::onNewAppClicked()
{
updatePluginModel(QStringList());
m_ui->gbPlugins->setEnabled(false);
m_ui->pbDeletePlugin->setEnabled(false);
m_ui->pbDeleteApp->setEnabled(false);
m_ui->pbAddPlugin->setEnabled(false);
m_ui->pbUpdate->setEnabled(false);
m_ui->pbNewPlugin->setEnabled(false);
m_ui->leAppName->setText(QString());
m_ui->chbAppActive->setChecked(false);
m_ui->lePluginName->setText(QString());
m_ui->lePluginType->setText(QString());
m_ui->chbActions->setChecked(false);
m_ui->chbMain->setChecked(false);
m_ui->chbPayload->setChecked(false);
m_ui->pbNewApp->setEnabled(false);
if(m_appIndex.isValid())
m_ui->lvApps->selectionModel()->select(m_appIndex,QItemSelectionModel::Deselect);
m_appIndex = QModelIndex();
}
void LtsAppDescriptorEditor::updateAppModel()
{
onNewAppClicked();
QStringList appList;
Q_FOREACH(const LtsAppDescriptor::AppDescription &appDesc, m_vector)
{
appList << appDesc.appName;
}
if (!m_ui->lvApps->model())
m_ui->lvApps->setModel(new QStringListModel(this));
QStringListModel *m = qobject_cast<QStringListModel*>(m_ui->lvApps->model());
if (!m)
return;
m->setStringList(appList);
}
void LtsAppDescriptorEditor::updatePluginModel(const QStringList &list)
{
if (!m_ui->lvPlugins->model())
m_ui->lvPlugins->setModel(new QStringListModel(this));
QStringListModel *m = qobject_cast<QStringListModel*>(m_ui->lvPlugins->model());
if (!m)
return;
m->setStringList(list);
}
void LtsAppDescriptorEditor::checkSave()
{
if(m_changed)
{
QMessageBox msgBox(tr("Warning"),
tr("The Data has been modified.\nDo you want to save your changes?"),
QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No | QMessageBox::Escape,
QMessageBox::NoButton);
if (msgBox.exec() == QMessageBox::Yes)
onSaveAsClicked();
}
}
void LtsAppDescriptorEditor::onSaveAsClicked()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save JSON"), QLatin1Literal("/shd/CTC/TOOLS/TDS/TDS-source/Lts/Projects/Legatus/resources/"),
tr("JSON File (*.json)"));
if(fileName.isEmpty())
return;
QByteArray jsonByteArray;
jsonByteArray = LtsAppDescriptor::LtsAppDescriptor::createJson(m_vector);
QFile f(fileName);
f.open(QIODevice::WriteOnly);
f.write(jsonByteArray);
f.close();
m_changed = false;
QMessageBox msgBox(QMessageBox::Information,
tr("Success"),
tr("Your file has been saved."));
msgBox.exec();
}
void LtsAppDescriptorEditor::onSaveClicked()
{
const QByteArray jsonByteArray(LtsAppDescriptor::LtsAppDescriptor::createJson(m_vector));
QFile f(m_fileName);
f.open(QIODevice::WriteOnly);
f.write(jsonByteArray);
f.close();
m_changed = false;
QMessageBox msgBox(QMessageBox::Information,
tr("Success"),
tr("Your file has been saved."));
msgBox.exec();
}
void LtsAppDescriptorEditor::onOpenClicked()
{
checkSave();
getAppDescriptionVector();
m_changed = false;
}
void LtsAppDescriptorEditor::onNewClicked()
{
checkSave();
m_ui->chbActions->setChecked(false);
m_ui->chbMain->setChecked(false);
m_ui->chbPayload->setChecked(false);
m_ui->chbAppActive->setChecked(false);
m_ui->leAppName->setText(QString());
m_ui->lePluginName->setText(QString());
m_ui->lePluginType->setText(QString());
m_ui->gbPlugins->setEnabled(false);
m_vector = LtsAppDescriptor::AppDescriptionVector();
updateAppModel();
updatePluginModel(QStringList());
}
void LtsAppDescriptorEditor::enableNewPlugin()
{
m_ui->pbNewPlugin->setEnabled(true);
}
void LtsAppDescriptorEditor::onQuitClicked()
{
QApplication::quit();
}
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#include <QtWidgets/QWidget>
#include <QModelIndex>
#include "lts_app_descriptor.h"
#ifndef LTSAPPDESCRIPTOREDITOR_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define LTSAPPDESCRIPTOREDITOR_EXPORT
# else
# if defined(MAKE_LTSAPPDESCRIPTOREDITOR_LIB)
# define LTSAPPDESCRIPTOREDITOR_EXPORT Q_DECL_EXPORT
# else
# define LTSAPPDESCRIPTOREDITOR_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
class Ui_LtsAppDescriptionEditor;
class LTSAPPDESCRIPTOREDITOR_EXPORT LtsAppDescriptorEditor : public QWidget
{
Q_OBJECT
public:
explicit LtsAppDescriptorEditor(QWidget *parent = 0);
~LtsAppDescriptorEditor();
private:
Ui_LtsAppDescriptionEditor *m_ui;
LtsAppDescriptor::AppDescriptionVector m_vector;
QModelIndex m_appIndex;
QModelIndex m_pluginIndex;
QString m_fileName;
bool m_changed;
void getAppDescriptionVector();
void setupMainWindow();
void updateAppModel();
void updatePluginModel(const QStringList &list);
void checkSave();
private slots:
void onAppsClicked(const QModelIndex &index);
void onPluginsClicked(const QModelIndex &index);
void pluginTypeChanged();
void onAppAddClicked();
void onPluginAddClicked();
void onAppDeleteClicked();
void onPluginDeletedClicked();
void onUpdateClicked();
void onNewpluginClicked();
void onNewAppClicked();
void enableNewPlugin();
public slots:
void onSaveClicked();
void onSaveAsClicked();
void onOpenClicked();
void onNewClicked();
void onQuitClicked();
};
+434
View File
@@ -0,0 +1,434 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LtsAppDescriptionEditor</class>
<widget class="QWidget" name="LtsAppDescriptionEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>865</width>
<height>337</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string/>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="3" colspan="2">
<widget class="QLabel" name="Plugins">
<property name="text">
<string>Required Plugins:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="AppLabel">
<property name="text">
<string>App:</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="4" colspan="3">
<widget class="QListView" name="lvApps">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
</widget>
</item>
<item row="5" column="7">
<widget class="QPushButton" name="pbNewPlugin">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>New</string>
</property>
</widget>
</item>
<item row="2" column="3" colspan="2">
<widget class="QLabel" name="AppName">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Name:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="6">
<widget class="QPushButton" name="pbDeletePlugin">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="1" column="7" rowspan="4" colspan="3">
<widget class="QGroupBox" name="gbPlugins">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>New Plugin Requirements</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="PluginType">
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lePluginType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>210</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>gui/data</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="PluginName">
<property name="text">
<string>IID:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lePluginName">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>210</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Name of the Plugin</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="PluginFlags">
<property name="text">
<string>Flags:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="chbActions">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Actions</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="chbMain">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Main</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="chbPayload">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Payload</string>
</property>
</widget>
</item>
<item row="6" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QLabel" name="AppActive">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Active:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="pbDeleteApp">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="4" column="3" colspan="4">
<widget class="QListView" name="lvPlugins">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
</widget>
</item>
<item row="5" column="9">
<widget class="QPushButton" name="pbUpdate">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QLineEdit" name="leAppName">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>Name of the App</string>
</property>
</widget>
</item>
<item row="5" column="8">
<widget class="QPushButton" name="pbAddPlugin">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="pbNewApp">
<property name="text">
<string>New</string>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QCheckBox" name="chbAppActive">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="pbAddApp">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>List of Apps</string>
</property>
</widget>
</item>
<item row="1" column="6" rowspan="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>lvApps</tabstop>
<tabstop>pbNewApp</tabstop>
<tabstop>pbAddApp</tabstop>
<tabstop>pbDeleteApp</tabstop>
<tabstop>chbAppActive</tabstop>
<tabstop>leAppName</tabstop>
<tabstop>lvPlugins</tabstop>
<tabstop>pbDeletePlugin</tabstop>
<tabstop>pbNewPlugin</tabstop>
<tabstop>lePluginType</tabstop>
<tabstop>lePluginName</tabstop>
<tabstop>chbPayload</tabstop>
<tabstop>chbMain</tabstop>
<tabstop>chbActions</tabstop>
<tabstop>pbAddPlugin</tabstop>
<tabstop>pbUpdate</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+56
View File
@@ -0,0 +1,56 @@
#include "lts_app_descriptor_editor.h"
#include <QAction>
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
QMenu *fileMenu = mainWindow->menuBar()->addMenu(QObject::tr("&File"));
QAction *openAct = new QAction(QObject::tr("&Open"), mainWindow);
openAct->setShortcuts(QKeySequence::Open);
openAct->setStatusTip(QObject::tr("Open an existing file"));
fileMenu->addAction(openAct);
QAction *newAct = new QAction(QObject::tr("&New"), mainWindow);
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip(QObject::tr("Create a new App"));
fileMenu->addAction(newAct);
QAction *saveAct = new QAction(QObject::tr("&Save"), mainWindow);
saveAct->setShortcuts(QKeySequence::Save);
saveAct->setStatusTip(QObject::tr("Save modified file"));
fileMenu->addAction(saveAct);
QAction *saveAsAct = new QAction(QObject::tr("&SaveAs"), mainWindow);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
saveAsAct->setStatusTip(QObject::tr("Save modified file as"));
fileMenu->addAction(saveAsAct);
QAction *quitAct = new QAction(QObject::tr("&Quit"), mainWindow);
quitAct->setShortcuts(QKeySequence::Quit);
quitAct->setStatusTip(QObject::tr("Quit the Application"));
fileMenu->addAction(quitAct);
LtsAppDescriptorEditor *editor = new LtsAppDescriptorEditor(mainWindow);
mainWindow->setCentralWidget(editor);
QObject::connect(openAct, &QAction::triggered, editor, &LtsAppDescriptorEditor::onOpenClicked);
QObject::connect(newAct, &QAction::triggered, editor, &LtsAppDescriptorEditor::onNewClicked);
QObject::connect(saveAct, &QAction::triggered, editor, &LtsAppDescriptorEditor::onSaveClicked);
QObject::connect(saveAsAct, &QAction::triggered, editor, &LtsAppDescriptorEditor::onSaveAsClicked);
QObject::connect(quitAct, &QAction::triggered, editor, &LtsAppDescriptorEditor::onQuitClicked);
mainWindow->show();
int ret = a.exec();
delete mainWindow;
return ret;
}