Files
qt5-legatus-legacy/Lts/Plugins/Evaluations/Gui/SchemaEdit/evl_edit_schema.cpp
T
2026-08-13 18:33:10 +02:00

1281 lines
39 KiB
C++
Executable File

/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*
* Created by Philipp Last, NLSE, 02.01.2018
*/
#include "evl_edit_schema.h"
#include "ui_evl_edit_schema.h"
#include "evl_new_comment_dialog.h"
#include <LtsSession/lts_session_data.h>
#include <Evaluations/evl_translation.h>
#include <QMenu>
#include <QTimer>
#include <QInputDialog>
#include <QKeyEvent>
#include <QTreeView>
namespace Evaluations
{
// ToDo: merge with ppm::beautifyTreeView ??
/*
* Column widths are adjusted to the displayed content. Keeps all items expanded
* after identifying the optimal column width if 'keepExpanded' is true.
*/
static void beautifyTreeView(QTreeView *tv, QAbstractItemModel *pModel, const QModelIndex &parent = QModelIndex(), bool keepExpanded = true)
{
if (!parent.isValid())
tv->expandAll();
else
tv->expand(parent);
int colCount = pModel->columnCount(parent);
for (int i = 0; i < colCount; ++i)
tv->resizeColumnToContents(i);
tv->header()->resizeSection(0, tv->columnWidth(0) + tv->iconSize().width() + 10);
if (!keepExpanded)
{
if (!parent.isValid())
tv->collapseAll();
else
tv->collapse(parent);
}
}
// ToDo: From participant_tree_edit_handler.cpp. Merge??!
/*
* If 'expand' is true all subnodes of the currently selected node will be expanded.
* If 'expand' is false all subnodes of the currently selected node will be collapsed.
*/
void expandNodeChildren(QTreeView *pTreeView, const QModelIndex &index, bool expand)
{
if (!index.isValid())
return;
int childCount = index.model()->rowCount(index);
for (int i = 0; i < childCount; i++)
{
const QModelIndex &child = index.model()->index(i, 0, index);
// Recursively call the function for each child node.
expandNodeChildren(pTreeView, child, expand);
}
if (expand)
pTreeView->expand(index);
else
pTreeView->collapse(index);
}
// -------------------------------------------------------------------------------------------------------
EditSchemaDialog::EditSchemaDialog(bool ocMode, bool runningOnTablet, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_ocMode(ocMode)
, m_runningOnTablet(runningOnTablet)
, m_session(session)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ui(new Ui::EditSchemaDialog)
, m_logger(getLogger("EditSchemaDialog"))
{
m_ui->setupUi(this);
if (ocMode)
setOnlineHelpFilename(QStringLiteral("OC-Exercise_Evaluations"));
else
setOnlineHelpFilename(QStringLiteral("Situation-O-C_Evaluation_Schemes"));
}
bool EditSchemaDialog::init(const std::shared_ptr<OcSituationClient::Interface::Ftc> &ocFtc,
const std::shared_ptr<Interface::Ftc> &evlFtc,
const std::shared_ptr<Interface::Dtc> &evlDtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<FileManagement::Interface::Ftc> &flmFtc,
const std::shared_ptr<FileManagement::Interface::Dtc> &flmDtc,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmGui)
{
m_ocFtc = ocFtc;
m_evlFtc = evlFtc;
m_evlDtc = evlDtc;
m_opmDtc = opmDtc;
m_flmFtc = flmFtc;
m_flmDtc = flmDtc;
m_flmGui = flmGui;
m_pModel = new TreeModelSchema(this, m_logger);
m_ui->m_treeViewSchema->setModel(m_pModel);
m_ui->m_treeViewSchema->installEventFilter(this);
connect(m_ui->m_treeViewSchema->selectionModel(), &QItemSelectionModel::currentChanged, this, &EditSchemaDialog::onTreeViewModelIndexChanged);
connect(m_ui->m_treeViewSchema, &QTreeView::customContextMenuRequested, this, &EditSchemaDialog::onShowContextMenu);
connect(m_ui->m_treeViewSchema, &QTreeView::doubleClicked, this, &EditSchemaDialog::onTreeViewDoubleClicked);
// Subscribe for changes / new schemata
connect(m_evlDtc.get(), &Evaluations::Interface::Dtc::evaluationSchemaChanged, this, &EditSchemaDialog::onNotifyAboutSchema, Qt::UniqueConnection);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
if (m_ocMode)
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setText(tr("Apply"));
m_ui->m_treeViewSchema->setDragEnabled(false);
connect(m_ui->m_pushButton_SendComment, &QPushButton::clicked, this, &EditSchemaDialog::onSendComment);
connect(m_ui->m_pushButton_SendAllComments, &QPushButton::clicked, this, &EditSchemaDialog::onSendAllComments);
connect(m_ui->m_pushButton_NewComment, &QPushButton::clicked, this, &EditSchemaDialog::onAddNewComment);
connect(m_ui->m_pushButton_EditComment, &QPushButton::clicked, this, &EditSchemaDialog::onTreeViewDoubleClicked);
connect(m_ui->m_pushButton_RemoveComment, &QPushButton::clicked, this, &EditSchemaDialog::onRemoveSelectedElement);
connect(m_ui->m_pushButton_RequestSchema, &QPushButton::clicked, this, &EditSchemaDialog::onRequestSchema);
m_ui->m_pushButton_SendComment->setEnabled(false);
m_ui->m_pushButton_SendAllComments->setEnabled(false);
m_ui->m_pushButton_NewComment->setEnabled(false);
m_ui->m_pushButton_EditComment->setEnabled(false);
m_ui->m_pushButton_RemoveComment->setEnabled(false);
m_ui->m_pushButton_CreateNewSchema->hide();
m_ui->m_pushButton_AddElement->hide();
m_ui->m_pushButton_AddFolder->hide();
m_ui->m_pushButton_AddRootFolder->hide();
m_ui->m_pushButton_Modify->hide();
m_ui->m_pushButton_Remove->hide();
m_ui->m_pushButton_SendSchema->hide();
m_ui->m_pushButton_LoadSchemaDebug->hide();
m_ui->m_pushButton_SaveToLibrary->hide();
m_ui->m_pushButton_LoadFromLibrary->hide();
m_ui->line->hide();
m_ui->line_2->hide();
}
else
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setText(tr("Save"));
connect(m_pModel, &TreeModelSchema::signalSuccessfulDropPerformed, this, &EditSchemaDialog::onDropActionFinished);
connect(m_pModel, &TreeModelSchema::signalTriedToDropFolderToElement, this, &EditSchemaDialog::onTriedToDropFolderToElement);
connect(m_ui->m_pushButton_SaveToLibrary, &QPushButton::clicked, this, &EditSchemaDialog::onSaveToLibrary);
connect(m_ui->m_pushButton_LoadFromLibrary, &QPushButton::clicked, this, &EditSchemaDialog::onLoadFromLibrary);
connect(m_ui->m_pushButton_SendSchema, &QPushButton::clicked, this, &EditSchemaDialog::onSendSchema);
connect(m_ui->m_pushButton_LoadSchemaDebug, &QPushButton::clicked, this, &EditSchemaDialog::DebugonLoadSchema);
connect(m_ui->m_pushButton_CreateNewSchema, &QPushButton::clicked, this, &EditSchemaDialog::onCreateNewSchema);
connect(m_ui->m_pushButton_AddElement, &QPushButton::clicked, this, &EditSchemaDialog::onAddElement);
connect(m_ui->m_pushButton_AddFolder, &QPushButton::clicked, this, &EditSchemaDialog::onAddFolder);
connect(m_ui->m_pushButton_AddRootFolder, &QPushButton::clicked, this, &EditSchemaDialog::onAddRootFolder);
connect(m_ui->m_pushButton_Modify, &QPushButton::clicked, this, &EditSchemaDialog::onModifySelectedEntry);
connect(m_ui->m_pushButton_Remove, &QPushButton::clicked, this, &EditSchemaDialog::onRemoveSelectedElement);
m_ui->m_pushButton_NewComment->hide();
m_ui->m_pushButton_SendComment->hide();
m_ui->m_pushButton_SendAllComments->hide();
m_ui->m_pushButton_EditComment->hide();
m_ui->m_pushButton_RemoveComment->hide();
m_ui->m_pushButton_RequestSchema->hide();
m_ui->m_labelComments->hide();
m_ui->line_3->hide();
m_ui->line_4->hide();
#ifdef LTS_DEBUG
// createExampleSchema();
// beautifyTreeView(m_ui->m_treeViewSchema, m_pModel);
#else
m_ui->m_pushButton_LoadSchemaDebug->hide();
#endif
}
loadLatestSchema();
onTreeViewModelIndexChanged(QModelIndex());
return true;
}
/*
* If O/C mode: Loads latest schema which has send to training area-flag set.
* Otherwise : Simply loads the latest schema.
*/
void EditSchemaDialog::loadLatestSchema()
{
m_mapSchemata = m_evlDtc->evaluationSchemas();
if (!m_mapSchemata.size())
{
FATAL_LOG(m_logger) << "No evaluation schema available! Something is really wrong, there should always be at least one default evaluation schema available (created by the evaluation service)!";
return;
}
if (m_ocMode)
{
// Load latest schema with send to training area-flag
auto itE = m_mapSchemata.cend();
auto itB = m_mapSchemata.cbegin();
while (itE != itB)
{
--itE;
if ((*itE).sendToTa())
{
loadSchema((*itE).id());
break;
}
}
// Re-add previously added comments of this OC to the current schema
const QMap<qint32, Evaluations::EvaluationComment> mapComments = m_evlDtc->evaluationComments();
for (const Evaluations::EvaluationComment &c : mapComments)
{
if (c.schemaId() != m_loadedSchemaId)
continue;
if (c.senderOperatorId() != LtsSessionData::LtsSessionData::getInstance()->getOperatorId())
continue;
ItemComment comment(QString::fromStdString(c.text()),
c.senderOperatorId(),
c.receiverOperatorId().is_set() ? c.receiverOperatorId().get() : 0,
c.elementId(),
QDateTime::fromMSecsSinceEpoch(c.ts()));
m_pModel->insertComment(comment);
}
updateCommentLabel();
}
else
loadSchema(m_mapSchemata.last().id());
}
void EditSchemaDialog::handleUnsentComments()
{
if (m_pModel->cntSentComments() != m_pModel->cntComments())
{
LtsWidgets::Button button =
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("There are unsent comments within the currently loaded schema. Do you wish to send them before requesting a new schema?"),
tr("Warning"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::Yes)
onSendAllComments();
}
}
void EditSchemaDialog::onRequestSchema()
{
/*
* ToDo: Funkverbindung pruefen. Keine Verbindung -> nachfolgende Meldung
*/
bool con = true;
if (!con)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("No Tetra radio, request failed!"));
return;
}
handleUnsentComments();
loadLatestSchema();
/*
* Mit der aktuellen Architektur eigentlich nicht mehr notwendig, aktuelle
* Schemes liegen eh immer auf dem DDS?
*
* Handbuch GefÜbZH 2.3.2.4.1: "Eine neue Anforderung kann [...]
* nach Ablauf eines Wartezeitbegrenzers gestartet werden."
*/
m_ui->m_pushButton_RequestSchema->setEnabled(false);
QTimer::singleShot(3000, this, [this]()
{
m_ui->m_pushButton_RequestSchema->setEnabled(true);
});
}
void EditSchemaDialog::onNotifyAboutSchema(const Evaluations::EvaluationSchema &data, DataModification modType)
{
if (m_ocMode && !data.sendToTa())
return;
QJsonParseError jError;
const QJsonDocument doc(QJsonDocument::fromJson(data.schemadata().c_str(), &jError));
if (jError.error != QJsonParseError::NoError)
{
WARNING_LOG(m_logger) << "Could not parse schema with database id " << data.id();
return;
}
if (m_loadedSchemaId == data.id())
return;
/*
* Likely that we caused the changed event by editing and sending a schema...
* Do not bother user with messagebox since the models are identical
*/
if (doc == m_pModel->toJsonDocument())
{
// However, take the new database id which has increased
m_loadedSchemaId = data.id();
retranslate();
return;
}
if (modType == DataModification::eAdded || modType == DataModification::eModified)
{
LtsWidgets::Button button =
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("A new schema is available. Do you wish to load this schema?"),
tr("Information"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::Yes)
{
handleUnsentComments();
m_loadedSchemaId = data.id();
m_pModel->fromQJsonDocument(doc);
expandNodeChildren(m_ui->m_treeViewSchema, QModelIndex(), true);
updateCommentLabel();
}
}
}
void EditSchemaDialog::loadSchema(qint32 schemaId)
{
if (m_mapSchemata.size())
{
QJsonParseError jError;
const QJsonDocument doc(QJsonDocument::fromJson(m_mapSchemata[schemaId].schemadata().c_str(), &jError));
if (jError.error != QJsonParseError::NoError)
{
WARNING_LOG(m_logger) << "Could not load schema with database id " << m_mapSchemata.last().id();
return;
}
m_loadedSchemaId = schemaId;
m_pModel->fromQJsonDocument(doc);
beautifyTreeView(m_ui->m_treeViewSchema, m_pModel);
/*
for (auto it = mapComments.begin(); it != mapComments.end(); ++it)
{
const Evaluations::EvaluationSchema &s = it.value();
}
*/
}
}
void EditSchemaDialog::DebugonLoadSchema()
{
if (!m_mapSchemata.size())
{
LtsWidgets::LtsMessageDialog::showMessage(this, QStringLiteral("(DEBUG) No schemes in db available."));
return;
}
m_mapSchemata = m_evlDtc->evaluationSchemas();
qint32 id = QInputDialog::getInt(this, QStringLiteral("Insert database id of desired schema"), QStringLiteral("Database id"), m_mapSchemata.last().id(), m_mapSchemata.first().id(), m_mapSchemata.last().id());
loadSchema(id);
}
bool EditSchemaDialog::eventFilter(QObject *object, QEvent *event)
{
if (object == m_ui->m_treeViewSchema && event->type() == QEvent::KeyPress)
{
QKeyEvent *pKeyEvent = static_cast<QKeyEvent *>(event);
if (pKeyEvent->key() == Qt::Key_Delete)
onRemoveSelectedElement();
}
return LtsWidgets::LtsDialog::eventFilter(object, event);
}
void EditSchemaDialog::onAddFolder()
{
addEntry(true);
}
void EditSchemaDialog::onAddRootFolder()
{
addEntry(true, true);
}
void EditSchemaDialog::onAddElement()
{
addEntry(false);
}
void EditSchemaDialog::addEntry(bool isFolder, bool isNewRoot)
{
bool inputNotCancelled;
QString strText = QInputDialog::getText(this, tr("EXCON"), isFolder ? tr("Folder name:") : tr("Element name:"), QLineEdit::Normal, isFolder ? tr("New Folder") : tr("New element"), &inputNotCancelled);
if (!inputNotCancelled)
return;
if (strText.isEmpty())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("You have to enter a description."));
return;
}
ElementData e(strText, isFolder);
const QModelIndex idx = isNewRoot ? QModelIndex() : m_ui->m_treeViewSchema->currentIndex();
m_pModel->insertElementData(idx, e);
beautifyTreeView(m_ui->m_treeViewSchema, m_pModel, idx);
slotChangesMade();
}
void EditSchemaDialog::onRemoveSelectedElement()
{
const QModelIndex idx = m_ui->m_treeViewSchema->currentIndex();
if (!idx.isValid())
return;
/*
* If dialog is opened in ocMode only comments can be removed, not folders or elements.
* Furthermore, only comments which have not been sent can be removed.
*/
if (m_ocMode)
removeComment(idx);
else
removeEntry(idx);
}
void EditSchemaDialog::removeEntry(const QModelIndex &idx)
{
bool isLastRoot = ((!idx.parent().isValid()) && (m_pModel->rowCount() == 1)); // Root nodes may be removed as long the user is not removing the last root node (would result in an empty schema)
if (isLastRoot)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("You can not remove the last root node."));
return;
}
LtsWidgets::Button button = LtsWidgets::Button::Yes;
if (m_pModel->hasChildren(idx))
{
button = LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Selected folder contains elements. Do you really want to remove the selected folder?"),
tr("Information"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
}
if (button == LtsWidgets::Button::Yes)
{
m_pModel->removeRow(idx, true);
slotChangesMade();
}
}
void EditSchemaDialog::removeComment(const QModelIndex &idx)
{
// O/C can only remove comments which have not been sent yet
QVariant v = m_pModel->dataAsVariant(idx);
if (v.canConvert<Evaluations::ItemComment>())
{
ItemComment c = v.value<Evaluations::ItemComment>();
if (c.isSent())
return;
m_pModel->removeComment(idx);
updateCommentLabel();
}
}
void EditSchemaDialog::saveSchema(bool sendToTa)
{
EvlSchemaModifyRequest req;
bool schemaChanged = hasUnsavedChanges();
req.id(schemaChanged ? 0 : m_loadedSchemaId);
req.sendToTa(sendToTa);
QJsonDocument doc = m_pModel->toJsonDocument();
req.schemadata(doc.toJson().constData());
m_requestHelper->addRequest([this, req, schemaChanged]()
{
bool success = m_evlFtc->evlSchemaModifyRequest(req, this);
if (success && schemaChanged)
__unchange__();
return success;
});
m_requestHelper->startRequests();
}
void EditSchemaDialog::onSendSchema()
{
saveSchema(true);
}
void EditSchemaDialog::onCreateNewSchema()
{
if (hasUnsavedChanges())
{
LtsWidgets::Button button =
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Current schema has been modified. Do you want to save these changes?"),
tr("Information"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::Yes)
apply();
}
// Cancel button of 'QInputDialog' can not be hide. Hence, we simply use default text.
bool inputNotCancelled;
QString strFolderName = QInputDialog::getText(this, tr("EXCON"), tr("New root folder name:"), QLineEdit::Normal, tr("<folder name>"), &inputNotCancelled);
if (strFolderName.isEmpty())
strFolderName = tr("<folder name>");
m_pModel->resetModel();
QModelIndex root;
ElementData e(strFolderName);
m_pModel->insertElementData(root, e);
slotChangesMade();
}
EditSchemaDialog::~EditSchemaDialog()
{
delete m_ui;
}
void EditSchemaDialog::retranslate()
{
translate(m_ui, QString::number(m_loadedSchemaId), (m_loadedSchemaId < 1), m_ocMode ? tr("O/C Evaluations") : tr("O/C Evaluation Schemes"));
}
void EditSchemaDialog::onSendAllComments()
{
QModelIndex root;
m_pModel->iterateModel(root, [this](const QModelIndex & idx, const QVariant & v)
{
Q_UNUSED(v);
sendComment(idx);
});
updateCommentLabel();
}
void EditSchemaDialog::onSendComment()
{
QModelIndex idx = m_ui->m_treeViewSchema->currentIndex();
sendComment(idx);
}
EvlCommentModifyRequest EditSchemaDialog::createEvlCommentModifyRequest(const ItemComment &c) const
{
EvlCommentModifyRequest req;
req.id(0);
req.ts(c.getTimeStamp().toMSecsSinceEpoch());
req.senderOperatorId(c.senderId());
if (c.hasReceiverId())
req.receiverOperatorId(c.receiverId());
req.text(c.getText().toStdString());
req.hierarchy(c.getHierarchy().toStdString());
req.schemaId(m_loadedSchemaId);
req.elementId(c.elementId());
return req;
}
OcSituationClient::SendEvaluationRequest EditSchemaDialog::createSendEvaluationRequest(const ItemComment &c) const
{
OcSituationClient::SendEvaluationRequest req;
req.timeStamp(c.getTimeStamp().toMSecsSinceEpoch());
req.senderOperatorId(c.senderId());
if (c.hasReceiverId())
req.receiverOperatorId(c.receiverId());
req.text(c.getText().toStdString());
req.hierarchy(c.getHierarchy().toStdString());
req.schemaId(m_loadedSchemaId);
//req.(c.elementId());
return req;
}
void EditSchemaDialog::markCommentAsSent(const QPersistentModelIndex &idx)
{
QVariant v = m_pModel->dataAsVariant(idx);
ItemComment c = v.value<Evaluations::ItemComment>();
c.markAsSent();
m_pModel->updateComment(idx, c);
// Store it additionally to our local database
EvlCommentModifyRequest req = createEvlCommentModifyRequest(c);
m_requestHelper->addRequest([this, req]()
{
return m_evlFtc->evlCommentModifyRequest(req, this);
});
updateCommentLabel();
m_ui->m_pushButton_SendComment->setEnabled(false);
m_ui->m_pushButton_EditComment->setEnabled(false);
m_ui->m_pushButton_RemoveComment->setEnabled(false);
}
void EditSchemaDialog::onSendEvaluationReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (!replyObject.error())
{
// No error, finally mark comment as sent
markCommentAsSent(m_vecCommentsInSendState.front());
m_requestHelper->startRequests();
}
m_vecCommentsInSendState.pop_front();
}
void EditSchemaDialog::sendComment(const QModelIndex &idx)
{
QVariant v = m_pModel->dataAsVariant(idx);
if (v.canConvert<Evaluations::ItemComment>())
{
ItemComment c = v.value<Evaluations::ItemComment>();
if (c.isSent())
return;
// Provide possibility to test oc stuff on workstation
if (!m_runningOnTablet)
{
markCommentAsSent(idx);
return;
}
OcSituationClient::SendEvaluationRequest req = createSendEvaluationRequest(c);
m_requestHelper->addRequest([this, &idx, req]()
{
bool commentSent = m_ocFtc->sendEvaluationRequest(req, this);
if (commentSent)
{
// We come back to this in 'onSendEvaluationReply'
m_vecCommentsInSendState.push_back(idx);
}
return commentSent;
});
// Debug purposes
/*
EvlCommentModifyRequest req = createEvlCommentModifyRequest(c);
m_requestHelper->addRequest([this, req]()
{
return m_evlFtc->evlCommentModifyRequest(req, this);
});
*/
m_requestHelper->startRequests();
}
}
void EditSchemaDialog::updateCommentLabel()
{
m_ui->m_labelComments->setText(QString(tr("Sent comments: %1/%2")).arg(QString::number(m_pModel->cntSentComments()), QString::number(m_pModel->cntComments())));
m_ui->m_pushButton_SendAllComments->setEnabled(m_pModel->cntSentComments() < m_pModel->cntComments());
if (m_pModel->cntSentComments() == m_pModel->cntComments())
__unchange__();
}
void EditSchemaDialog::onAddNewComment()
{
if (m_commentDlg)
m_commentDlg->deleteLater();
m_commentDlg = new EvlNewCommentDialog(m_opmDtc, this);
connect(m_commentDlg, &EvlNewCommentDialog::accepted, this, &EditSchemaDialog::onCommentAccepted);
m_commentDlg->show();
}
void EditSchemaDialog::onCommentAccepted()
{
{
if (m_commentDlg->comment().isEmpty())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("No text entered. Comment has not been added!"));
return;
}
QModelIndex idx = m_ui->m_treeViewSchema->currentIndex();
QVector<QString> vecHierachy = m_pModel->getSelectedIndexHierarchy(idx);
QString strHierarchy;
for (int i = 0; i < vecHierachy.size() - 1; ++i)
strHierarchy += vecHierachy[i] + QStringLiteral(", ");
strHierarchy += vecHierachy.last();
ElementData e = m_pModel->getSelectedIndexDataAsElement(idx);
ItemComment c(m_commentDlg->comment(), LtsSessionData::LtsSessionData::getInstance()->getOperatorId(), m_commentDlg->selectedReceiverId(), e.m_id, strHierarchy);
QModelIndex idxNewComment = m_pModel->insertComment(idx, c);
if (m_commentDlg->autoSend())
sendComment(idxNewComment);
updateCommentLabel();
slotChangesMade();
}
}
void EditSchemaDialog::onTreeViewDoubleClicked()
{
if (m_ocMode)
onEditComment();
else
onModifySelectedEntry();
}
void EditSchemaDialog::onEditComment()
{
QModelIndex idx = m_ui->m_treeViewSchema->currentIndex();
QVariant v = m_pModel->dataAsVariant(idx);
if (v.canConvert<Evaluations::ItemComment>())
{
ItemComment c = v.value<Evaluations::ItemComment>();
if (c.isSent())
return;
if (m_commentDlg)
m_commentDlg->deleteLater();
m_commentDlg = new EvlNewCommentDialog(m_opmDtc, this);
m_commentDlg->setAsEditComment(c.getText());
connect(m_commentDlg, &EvlNewCommentDialog::accepted, this, &EditSchemaDialog::onCommentEditAccepted);
m_commentDlg->show();
}
}
void EditSchemaDialog::onCommentEditAccepted()
{
QModelIndex idx = m_ui->m_treeViewSchema->currentIndex();
QVariant v = m_pModel->dataAsVariant(idx);
if (v.canConvert<Evaluations::ItemComment>())
{
ItemComment c = v.value<Evaluations::ItemComment>();
c.setText(m_commentDlg->comment());
m_pModel->updateComment(idx, c);
}
}
void EditSchemaDialog::onModifySelectedEntry()
{
QModelIndex idx = m_ui->m_treeViewSchema->currentIndex();
ElementData e = m_pModel->getSelectedIndexDataAsElement(idx);
bool inputNotCancelled;
QString strText = QInputDialog::getText(this, tr("EXCON"), e.isFolder() ? tr("Modify folder name:") : tr("Modify element name:"), QLineEdit::Normal, e.getText(), &inputNotCancelled);
if (!inputNotCancelled)
return;
if (strText.isEmpty())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("You have to enter a description."));
return;
}
e.setText(strText);
m_pModel->updateElementData(idx, e);
slotChangesMade();
}
void EditSchemaDialog::onTreeViewModelIndexChanged(const QModelIndex &curr)
{
bool indexValid = curr.isValid();
if (m_ocMode)
{
m_ui->m_pushButton_SendComment->setEnabled(false);
m_ui->m_pushButton_NewComment->setEnabled(false);
m_ui->m_pushButton_EditComment->setEnabled(false);
m_ui->m_pushButton_RemoveComment->setEnabled(false);
if (indexValid)
{
QVariant v = m_pModel->dataAsVariant(curr);
if (v.canConvert<Evaluations::ElementData>())
m_ui->m_pushButton_NewComment->setEnabled(!v.value<Evaluations::ElementData>().isFolder());
else if (v.canConvert<Evaluations::ItemComment>())
{
if (!v.value<Evaluations::ItemComment>().isSent())
{
m_ui->m_pushButton_SendComment->setEnabled(true);
m_ui->m_pushButton_EditComment->setEnabled(true);
m_ui->m_pushButton_RemoveComment->setEnabled(true);
}
}
}
}
else
{
ElementData e = m_pModel->getSelectedIndexDataAsElement(curr);
m_ui->m_pushButton_AddElement->setEnabled(indexValid && e.isFolder());
m_ui->m_pushButton_AddFolder->setEnabled(indexValid && e.isFolder());
m_ui->m_pushButton_Modify->setEnabled(indexValid);
m_ui->m_pushButton_Remove->setEnabled(indexValid);
if (indexValid)
m_ui->m_treeViewSchema->selectionModel()->setCurrentIndex(curr, QItemSelectionModel::SelectCurrent);
}
}
void EditSchemaDialog::onTriedToDropFolderToElement()
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("It is not possible to append folders to elements."));
}
void EditSchemaDialog::onDropActionFinished(const QModelIndex &parent)
{
beautifyTreeView(m_ui->m_treeViewSchema, m_pModel, parent);
slotChangesMade();
}
bool EditSchemaDialog::apply()
{
if (m_ocMode)
onSendAllComments();
else
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Do you want to update the training area?"), QString(),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
bool sendToTA = (button == LtsWidgets::Button::Yes);
saveSchema(sendToTA);
}
return true;
}
void EditSchemaDialog::onLoadFromLibrary()
{
QByteArray content;
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::EvaluationSchema}, m_session->exerciseId());
if (fileId > 0)
{
QJsonParseError jError;
const QJsonDocument doc(QJsonDocument::fromJson(content, &jError));
if (jError.error != QJsonParseError::NoError)
{
WARNING_LOG(m_logger) << "Could not parse schema !";
return;
}
if (!m_pModel->fromQJsonDocument(doc))
{
WARNING_LOG(m_logger) << "Could not load schema !";
return;
}
beautifyTreeView(m_ui->m_treeViewSchema, m_pModel);
slotChangesMade();
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Loading schema from library failed!"));
}
}
bool EditSchemaDialog::onSaveToLibrary()
{
QByteArray byteArray = m_pModel->toJsonDocument().toJson();
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::EvaluationSchema, m_session->exerciseId(), byteArray);
if (fileId > 0)
{
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
return true;
}
else
ERROR_LOG(m_logger) << "Could not save file in library ";
return false;
}
void EditSchemaDialog::onShowContextMenu(const QPoint &position)
{
QTreeView *tv = qobject_cast<QTreeView *>(sender());
if (!tv)
return;
const QModelIndex idx = tv->currentIndex();
if (!idx.isValid())
return;
QMenu menu;
if (!m_ocMode)
{
ElementData d = m_pModel->getSelectedIndexDataAsElement(idx);
if (d.isFolder())
{
QAction *pActionAddElement = new QAction(tr("Add element"), &menu);
connect(pActionAddElement, &QAction::triggered, this, &EditSchemaDialog::onAddElement);
menu.addAction(pActionAddElement);
QAction *pActionAddFolder = new QAction(tr("Add folder"), &menu);
connect(pActionAddFolder, &QAction::triggered, this, &EditSchemaDialog::onAddFolder);
menu.addAction(pActionAddFolder);
}
QAction *pActionRemove = new QAction(tr("Remove"), &menu);
connect(pActionRemove, &QAction::triggered, this, &EditSchemaDialog::onRemoveSelectedElement);
menu.addAction(pActionRemove);
}
else
{
QVariant v = m_pModel->dataAsVariant(idx);
if (v.canConvert<Evaluations::ElementData>() && !v.value<Evaluations::ElementData>().isFolder())
{
QAction *pActionNewComment = new QAction(tr("New comment"), &menu);
connect(pActionNewComment, &QAction::triggered, this, &EditSchemaDialog::onAddNewComment);
menu.addAction(pActionNewComment);
}
else if (v.canConvert<Evaluations::ItemComment>())
{
ItemComment c = v.value<Evaluations::ItemComment>();
if (c.isSent())
return;
QAction *pActionSendComment = new QAction(tr("Send comment"), &menu);
connect(pActionSendComment, &QAction::triggered, this, &EditSchemaDialog::onSendComment);
menu.addAction(pActionSendComment);
QAction *pActionEditComment = new QAction(tr("Edit comment"), &menu);
connect(pActionEditComment, &QAction::triggered, this, &EditSchemaDialog::onEditComment);
menu.addAction(pActionEditComment);
QAction *pActionRemove = new QAction(tr("Remove comment"), &menu);
connect(pActionRemove, &QAction::triggered, this, &EditSchemaDialog::onRemoveSelectedElement);
menu.addAction(pActionRemove);
}
}
if (m_pModel->rowCount(idx) != 0)
{
menu.addSeparator();
if (tv->isExpanded(idx))
{
QAction *collapseAction = new QAction(tr("Collapse"), &menu);
connect(collapseAction, &QAction::triggered, this, [tv, idx]() { tv->collapse(idx);});
menu.addAction(collapseAction);
QAction *collapseAllAction = new QAction(tr("Collapse all"), &menu);
connect(collapseAllAction, &QAction::triggered, this, [tv, idx]() { expandNodeChildren(tv, idx, false); });
menu.addAction(collapseAllAction);
}
else
{
QAction *expandAction = new QAction(tr("Expand"), &menu);
connect(expandAction, &QAction::triggered, this, [tv, idx]() { tv->expand(idx);});
menu.addAction(expandAction);
}
QAction *expandAllAction = new QAction(tr("Expand all"), &menu);
connect(expandAllAction, &QAction::triggered, this, [tv, idx]() { expandNodeChildren(tv, idx, true); });
menu.addAction(expandAllAction);
}
menu.exec(tv->viewport()->mapToGlobal(position));
}
/*
* Excerpt (not all entries) from Figure 2.9 in GUEZSE60_T13_1501H_ABT-Handbuch.doc
* included for developing purposes.
*/
void EditSchemaDialog::createExampleSchema()
{
QModelIndex root;
// 1. Doku
ElementData e(QStringLiteral("Dokumentation"));
QModelIndex idxDoku = m_pModel->insertElementData(root, e);
// 1.1 Taktik
e.setText(QStringLiteral("Taktik"));
QModelIndex idxDokuTaktik = m_pModel->insertElementData(idxDoku, e);
e.setText(QStringLiteral("Stellungen"));
QModelIndex idxDokuTaktikStellungen = m_pModel->insertElementData(idxDokuTaktik, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Erkundung"));
m_pModel->insertElementData(idxDokuTaktikStellungen, e);
e.setText(QStringLiteral("Ausbau"));
m_pModel->insertElementData(idxDokuTaktikStellungen, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Verhalten"));
QModelIndex idxDokuTaktikVerhalten = m_pModel->insertElementData(idxDokuTaktik, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Geländeausnutzung"));
m_pModel->insertElementData(idxDokuTaktikVerhalten, e);
e.setText(QStringLiteral("Tarnung"));
m_pModel->insertElementData(idxDokuTaktikVerhalten, e);
e.setText(QStringLiteral("Geräuschdisziplin"));
m_pModel->insertElementData(idxDokuTaktikVerhalten, e);
e.setText(QStringLiteral("Beleuchtungsdisziplin"));
m_pModel->insertElementData(idxDokuTaktikVerhalten, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Verbindung"));
QModelIndex idxDokuTaktikVerbindung = m_pModel->insertElementData(idxDokuTaktik, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Verbindung halten"));
m_pModel->insertElementData(idxDokuTaktikVerbindung, e);
e.setText(QStringLiteral("Zeichendurchgabe"));
m_pModel->insertElementData(idxDokuTaktikVerbindung, e);
// 1.2 Befehle und Meldungen
e.markAsFolder(true);
e.setText(QStringLiteral("Befehle und Meldungen"));
QModelIndex idxBefMeld = m_pModel->insertElementData(idxDoku, e);
e.setText(QStringLiteral("Befehlsgebung"));
QModelIndex idxBefGeb = m_pModel->insertElementData(idxBefMeld, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Mündliche Befehlsausgaben"));
m_pModel->insertElementData(idxBefGeb, e);
e.setText(QStringLiteral("Absprachen"));
m_pModel->insertElementData(idxBefGeb, e);
e.setText(QStringLiteral("Ergebnisvortrag"));
m_pModel->insertElementData(idxBefGeb, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Verteilung und Zuführung"));
QModelIndex idxVerZuf = m_pModel->insertElementData(idxBefMeld, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Befehle"));
m_pModel->insertElementData(idxVerZuf, e);
e.setText(QStringLiteral("Pläne"));
m_pModel->insertElementData(idxVerZuf, e);
e.setText(QStringLiteral("Meldungen"));
m_pModel->insertElementData(idxVerZuf, e);
// 1.3 Logistische Versorgung
e.markAsFolder(true);
e.setText(QStringLiteral("Logistische Versorgung"));
QModelIndex idxLogVer = m_pModel->insertElementData(idxDoku, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Betriebsstoff"));
m_pModel->insertElementData(idxLogVer, e);
e.setText(QStringLiteral("Munition"));
m_pModel->insertElementData(idxLogVer, e);
e.setText(QStringLiteral("Verpflegung"));
m_pModel->insertElementData(idxLogVer, e);
e.setText(QStringLiteral("NVG"));
m_pModel->insertElementData(idxLogVer, e);
e.setText(QStringLiteral("EVG"));
m_pModel->insertElementData(idxLogVer, e);
// 1.4 Sanitätsdienst
e.markAsFolder(true);
e.setText(QStringLiteral("Sanitätsdienst"));
QModelIndex idxSani = m_pModel->insertElementData(idxDoku, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Versorgung"));
m_pModel->insertElementData(idxSani, e);
e.setText(QStringLiteral("Kameradenhilfe"));
m_pModel->insertElementData(idxSani, e);
// 1.5 Instandsetzung
e.markAsFolder(true);
e.setText(QStringLiteral("Instandsetzung"));
QModelIndex idxInstand = m_pModel->insertElementData(idxDoku, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Bergung"));
m_pModel->insertElementData(idxInstand, e);
e.setText(QStringLiteral("Instandsetzung"));
m_pModel->insertElementData(idxInstand, e);
// 2. Beurteilung
e.markAsFolder(true);
e.setText(QStringLiteral("Beurteilung"));
QModelIndex idxEval = m_pModel->insertElementData(root, e);
// 2.1 Taktik
e.setText(QStringLiteral("Taktik"));
QModelIndex idxEvlTakt = m_pModel->insertElementData(idxEval, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Führung"));
QModelIndex idxEvlTaktFuehr = m_pModel->insertElementData(idxEvlTakt, e);
e.markAsFolder(false);
e.setText(QStringLiteral("gut"));
m_pModel->insertElementData(idxEvlTaktFuehr, e);
e.setText(QStringLiteral("mittel"));
m_pModel->insertElementData(idxEvlTaktFuehr, e);
e.setText(QStringLiteral("schlecht"));
m_pModel->insertElementData(idxEvlTaktFuehr, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Planung"));
QModelIndex idxEvlTaktPlan = m_pModel->insertElementData(idxEvlTakt, e);
e.markAsFolder(false);
e.setText(QStringLiteral("gut"));
m_pModel->insertElementData(idxEvlTaktPlan, e);
e.setText(QStringLiteral("planlos"));
m_pModel->insertElementData(idxEvlTaktPlan, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Koordination"));
QModelIndex idxEvlTaktKoord = m_pModel->insertElementData(idxEvlTakt, e);
e.markAsFolder(false);
e.setText(QStringLiteral("vorhanden"));
m_pModel->insertElementData(idxEvlTaktKoord, e);
e.setText(QStringLiteral("nicht vorhanden"));
m_pModel->insertElementData(idxEvlTaktKoord, e);
e.markAsFolder(true);
e.setText(QStringLiteral("Feindlage"));
QModelIndex idxEvlTaktFeind = m_pModel->insertElementData(idxEvlTakt, e);
e.markAsFolder(false);
e.setText(QStringLiteral("berücksichtigt"));
m_pModel->insertElementData(idxEvlTaktFeind, e);
e.setText(QStringLiteral("falsch eingeschätzt"));
m_pModel->insertElementData(idxEvlTaktFeind, e);
e.setText(QStringLiteral("nicht erkannt"));
m_pModel->insertElementData(idxEvlTaktFeind, e);
// 2.2 Meldewesen
e.markAsFolder(true);
e.setText(QStringLiteral("Meldewesen"));
QModelIndex idxEvlMeld = m_pModel->insertElementData(idxEval, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Bataillon zu Brigade"));
m_pModel->insertElementData(idxEvlMeld, e);
e.setText(QStringLiteral("Ebene Teileinheit"));
m_pModel->insertElementData(idxEvlMeld, e);
e.setText(QStringLiteral("Effektivität"));
m_pModel->insertElementData(idxEvlMeld, e);
// 2.3 Sperren
e.markAsFolder(true);
e.setText(QStringLiteral("Sperren"));
QModelIndex idxEvlSperr = m_pModel->insertElementData(idxEval, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Verlegen"));
m_pModel->insertElementData(idxEvlSperr, e);
e.setText(QStringLiteral("Räumen"));
m_pModel->insertElementData(idxEvlSperr, e);
// 2.4 ABC-Abwehr
e.markAsFolder(true);
e.setText(QStringLiteral("ABC-Abwehr"));
QModelIndex idxEvlABC = m_pModel->insertElementData(idxEval, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Schutz"));
m_pModel->insertElementData(idxEvlABC, e);
e.setText(QStringLiteral("Aufklärung"));
m_pModel->insertElementData(idxEvlABC, e);
// 2.5 Hilfsmaßnahmen
e.markAsFolder(true);
e.setText(QStringLiteral("Hilfsmaßnahmen"));
QModelIndex idxEvlHilf = m_pModel->insertElementData(idxEval, e);
e.markAsFolder(false);
e.setText(QStringLiteral("Versorgungsabläufe"));
m_pModel->insertElementData(idxEvlHilf, e);
e.setText(QStringLiteral("Instandsetzung"));
m_pModel->insertElementData(idxEvlHilf, e);
e.setText(QStringLiteral("Sanitätsdienst"));
m_pModel->insertElementData(idxEvlHilf, e);
}
} // namespace Evaluations