/** * @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 #include #include #include #include #include #include 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 &ocFtc, const std::shared_ptr &evlFtc, const std::shared_ptr &evlDtc, const std::shared_ptr &opmDtc, const std::shared_ptr &flmFtc, const std::shared_ptr &flmDtc, const std::shared_ptr &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 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(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()) { ItemComment c = v.value(); 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(""), &inputNotCancelled); if (strFolderName.isEmpty()) strFolderName = tr(""); 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(); 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()) { ItemComment c = v.value(); 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 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()) { ItemComment c = v.value(); 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()) { ItemComment c = v.value(); 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()) m_ui->m_pushButton_NewComment->setEnabled(!v.value().isFolder()); else if (v.canConvert()) { if (!v.value().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(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() && !v.value().isFolder()) { QAction *pActionNewComment = new QAction(tr("New comment"), &menu); connect(pActionNewComment, &QAction::triggered, this, &EditSchemaDialog::onAddNewComment); menu.addAction(pActionNewComment); } else if (v.canConvert()) { ItemComment c = v.value(); 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