refs #568, improved validation and handling

* invalid models can be highlighted on stash
* selection mode can be toggled between single/multi selection (where applicable)
* color for highlighting can be set
* finetuning of menus
This commit is contained in:
Klaus Basan
2016-01-10 02:53:12 +01:00
parent 11ee49a382
commit b4dc21eeb4
15 changed files with 188 additions and 63 deletions

View File

@@ -363,18 +363,18 @@ namespace BlackGui
void CDbMappingComponent::ps_onStashedModelsChanged()
{
bool hlvp = this->ui->tvp_AircraftModelsForVPilot->derivedModel()->highlightGivenModelStrings();
bool hlom = this->ui->tvp_OwnAircraftModels->derivedModel()->highlightGivenModelStrings();
bool hlvp = this->ui->tvp_AircraftModelsForVPilot->derivedModel()->highlightModelStrings();
bool hlom = this->ui->tvp_OwnAircraftModels->derivedModel()->highlightModelStrings();
bool highlight = hlom || hlvp;
if (!highlight) { return; }
const QStringList stashedModels(this->ui->comp_StashAircraft->getStashedModelStrings());
if (hlvp)
{
this->ui->tvp_AircraftModelsForVPilot->derivedModel()->setHighlightModelsStrings(stashedModels);
this->ui->tvp_AircraftModelsForVPilot->derivedModel()->setHighlightModelStrings(stashedModels);
}
if (hlom)
{
this->ui->tvp_OwnAircraftModels->derivedModel()->setHighlightModelsStrings(stashedModels);
this->ui->tvp_OwnAircraftModels->derivedModel()->setHighlightModelStrings(stashedModels);
}
}
@@ -537,9 +537,10 @@ namespace BlackGui
void CDbMappingComponent::CMappingSimulatorModelMenu::customMenu(QMenu &menu) const
{
CSimulatorInfo sims = CSimulatorInfo::getLocallyInstalledSimulators();
bool empty = sims.isNoSimulator() || sims.isUnspecified();
if (!empty)
bool noSims = sims.isNoSimulator() || sims.isUnspecified();
if (!noSims)
{
if (!menu.isEmpty()) { menu.addSeparator(); }
QMenu *load = menu.addMenu(CIcons::appModels16(), "Load installed models");
QAction *a = nullptr;
CDbMappingComponent *mapComp = qobject_cast<CDbMappingComponent *>(this->parent());
@@ -565,7 +566,6 @@ namespace BlackGui
a = load->addAction(CIcons::appModels16(), "XPlane models", mapComp, SLOT(ps_requestSimulatorModels()));
a->setData(QVariant(static_cast<int>(CSimulatorInfo::XPLANE)));
}
menu.addSeparator();
}
this->nestedCustomMenu(menu);
}
@@ -578,8 +578,8 @@ namespace BlackGui
bool canUseVPilot = mappingComponent()->withVPilot();
if (canUseVPilot)
{
if (!menu.isEmpty()) { menu.addSeparator(); }
menu.addAction(CIcons::appMappings16(), "Load vPilot Rules", mapComp, SLOT(ps_loadVPilotData()));
menu.addSeparator();
}
this->nestedCustomMenu(menu);
}

View File

@@ -40,7 +40,7 @@ namespace BlackGui
// configure view
this->ui->tvp_AircraftModel->setFilterWidget(this->ui->filter_AircraftModelFilter);
this->ui->tvp_AircraftModel->allowDragDropValueObjects(true, false);
this->ui->tvp_AircraftModel->menuAddItems(CAircraftModelView::MenuStashModels);
this->ui->tvp_AircraftModel->menuAddItems(CAircraftModelView::MenuCanStashModels);
}
CDbModelComponent::~CDbModelComponent()

View File

@@ -47,7 +47,9 @@ namespace BlackGui
connect(this->ui->pb_Livery, &QPushButton::pressed, this, &CDbStashComponent::ps_copyOverPartsToSelected);
connect(this->ui->pb_Distributor, &QPushButton::pressed, this, &CDbStashComponent::ps_copyOverPartsToSelected);
ui->tvp_StashAircraftModels->menuAddItems(CAircraftModelView::MenuRemoveSelectedRows);
ui->tvp_StashAircraftModels->menuAddItems(CAircraftModelView::MenuRemoveSelectedRows | CAircraftModelView::MenuHighlightInvalid);
ui->tvp_StashAircraftModels->setHighlightModelStrings(true);
ui->tvp_StashAircraftModels->setHighlightModelStringsColor(Qt::red);
this->enableButtonRow();
}
@@ -241,30 +243,41 @@ namespace BlackGui
Q_UNUSED(skippedModels);
}
CStatusMessageList CDbStashComponent::validate() const
CStatusMessageList CDbStashComponent::validate(CAircraftModelList &invalidModels) const
{
if (this->ui->tvp_StashAircraftModels->isEmpty()) {return CStatusMessageList(); }
CAircraftModelList models(getSelectedOrAllModels());
if (models.isEmpty()) { return CStatusMessageList(); }
const CStatusMessageList msgs(models.validateForPublishing());
if (!msgs.isEmpty()) { return msgs; }
return CStatusMessageList(
const CStatusMessageList msgs(models.validateForPublishing(invalidModels));
// OK?
if (msgs.isEmpty())
{
CStatusMessage(validationCats(), CStatusMessage::SeverityInfo, QString("No errors in %1 model(s)").arg(models.size()))
});
return CStatusMessageList(
{
CStatusMessage(validationCats(), CStatusMessage::SeverityInfo, QString("No errors in %1 model(s)").arg(models.size()))
});
}
else
{
return msgs;
}
}
bool CDbStashComponent::validateAndDisplay(bool displayInfo)
{
const CStatusMessageList msgs(this->validate());
CAircraftModelList invalidModels;
const CStatusMessageList msgs(this->validate(invalidModels));
if (msgs.hasWarningOrErrorMessages())
{
this->showMessages(msgs);
this->ui->tvp_StashAircraftModels->setHighlightModelStrings(invalidModels.getModelStrings(false));
return false;
}
else
{
this->ui->tvp_StashAircraftModels->setHighlightModelStrings(QStringList());
if (displayInfo)
{
QString no = QString::number(this->getStashedModelsCount());

View File

@@ -139,7 +139,7 @@ namespace BlackGui
bool showMessage(const BlackMisc::CStatusMessage &msg, int timeoutMs = -1);
//! Validate
BlackMisc::CStatusMessageList validate() const;
BlackMisc::CStatusMessageList validate(BlackMisc::Simulation::CAircraftModelList &invalidModels) const;
//! Validate and display info messages
bool validateAndDisplay(bool displayInfo = false);

View File

@@ -45,14 +45,14 @@ namespace BlackGui
{
if (!m_nestedDelegate)
{
if (m_separatorAtEnd) { menu.addSeparator(); }
if (m_separatorAtEnd && !menu.isEmpty()) { menu.addSeparator(); }
return;
}
m_nestedDelegate->customMenu(menu);
}
IMenuDelegate *m_nestedDelegate = nullptr; //!< nested delegate if any
bool m_separatorAtEnd = false; //!< at end, terminate with seperator
bool m_separatorAtEnd = false; //!< at end, terminate with separator
};
} // ns

View File

@@ -125,6 +125,22 @@ namespace BlackGui
}
}
void CAircraftModelListModel::setHighlightModelStrings(const QStringList &modelStrings)
{
this->beginResetModel();
m_highlightStrings = modelStrings;
this->endResetModel();
}
void CAircraftModelListModel::setHighlightModelStrings(bool highlightModelStrings)
{
if (m_highlightModelStrings == highlightModelStrings) { return; }
this->beginResetModel();
m_highlightModelStrings = highlightModelStrings;
this->endResetModel();
}
QStringList CAircraftModelListModel::getModelStrings(bool sort) const
{
if (this->isEmpty()) { return QStringList(); }
@@ -143,15 +159,14 @@ namespace BlackGui
QVariant CAircraftModelListModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::BackgroundRole) { return CListModelDbObjects::data(index, role); }
bool ms = highlightGivenModelStrings() && !m_highlightStrings.isEmpty();
bool ms = highlightModelStrings() && !m_highlightStrings.isEmpty();
if (!ms) { return CListModelDbObjects::data(index, role); }
CAircraftModel model(this->at(index));
// highlight stashed first
if (m_highlightStrings.contains(model.getModelString(), Qt::CaseInsensitive))
{
static const QBrush b(Qt::yellow);
return b;
return this->m_highlightColor;
}
return QVariant();
}

View File

@@ -17,6 +17,7 @@
#include "blackmisc/simulation/aircraftmodellist.h"
#include <QStringList>
#include <QAbstractItemModel>
#include <QBrush>
namespace BlackGui
{
@@ -52,13 +53,16 @@ namespace BlackGui
AircraftModelMode getModelMode() const { return m_mode; }
//! Highlight models
bool highlightGivenModelStrings() const { return m_highlightModelStrings; }
void setHighlightModelStrings(const QStringList &modelStrings = QStringList());
//! Highlight models
void setHighlightModelsStrings(const QStringList &modelStrings = QStringList()) { m_highlightStrings = modelStrings; }
bool highlightModelStrings() const { return m_highlightModelStrings; }
//! Highlight models
void setHighlightModelsStrings(bool highlightModelStrings) { m_highlightModelStrings = highlightModelStrings; }
void setHighlightModelStrings(bool highlightModelStrings);
//! The highlight color
void setHighlightModelStringsColor(const QBrush &brush) { m_highlightColor = brush; }
//! Model strings
QStringList getModelStrings(bool sort) const;
@@ -70,9 +74,10 @@ namespace BlackGui
virtual QVariant data(const QModelIndex &index, int role) const override;
private:
AircraftModelMode m_mode = NotSet; //!< current mode
bool m_highlightModelStrings = false; //!< highlight in in model strings
QStringList m_highlightStrings; //!< model strings to highlight
AircraftModelMode m_mode = NotSet; //!< current mode
bool m_highlightModelStrings = false; //!< highlight in in model strings
QStringList m_highlightStrings; //!< model strings to highlight
QBrush m_highlightColor{Qt::yellow}; //!< how to highlight
};
} // ns
} // ns

View File

@@ -56,10 +56,10 @@ namespace BlackGui
this->m_menus = MenuBackend;
break;
case CAircraftModelListModel::VPilotRuleModel:
this->m_menus = MenuRefresh | MenuStashing | MenuHighlightDbData;
this->m_menus = MenuRefresh | MenuStashing | MenuToggleSelectionMode;
break;
case CAircraftModelListModel::OwnSimulatorModelMapping:
this->m_menus = MenuDisplayAutomatically | MenuStashing | MenuHighlightDbData;
this->m_menus = MenuDisplayAutomatically | MenuStashing | MenuHighlightDbData | MenuToggleSelectionMode;
break;
case CAircraftModelListModel::OwnSimulatorModel:
default:
@@ -91,7 +91,7 @@ namespace BlackGui
bool CAircraftModelView::hasSelectedModelsToStash() const
{
return m_menus.testFlag(MenuStashModels) && hasSelection();
return m_menus.testFlag(MenuCanStashModels) && hasSelection();
}
void CAircraftModelView::setImplementedMetaTypeIds()
@@ -123,6 +123,26 @@ namespace BlackGui
return delta;
}
void CAircraftModelView::setHighlightModelStrings(const QStringList &highlightModels)
{
this->derivedModel()->setHighlightModelStrings(highlightModels);
}
void CAircraftModelView::setHighlightModelStrings(bool highlight)
{
this->derivedModel()->setHighlightModelStrings(highlight);
}
void CAircraftModelView::setHighlightModelStringsColor(const QBrush &brush)
{
this->derivedModel()->setHighlightModelStringsColor(brush);
}
bool CAircraftModelView::highlightModelsStrings() const
{
return this->derivedModel()->highlightModelStrings();
}
void CAircraftModelView::dropEvent(QDropEvent *event)
{
if (!isDropAllowed()) { return; }
@@ -215,34 +235,43 @@ namespace BlackGui
void CAircraftModelView::customMenu(QMenu &menu) const
{
bool added = false;
if (this->m_menus.testFlag(MenuStashModels))
if (this->m_menus.testFlag(MenuCanStashModels))
{
menu.addAction(CIcons::appDbStash16(), "Stash", this, SLOT(ps_requestStash()));
QAction *a = menu.addAction(CIcons::appDbStash16(), "Stashing clears selection", this, SLOT(ps_stashingClearsSelection()));
a->setCheckable(true);
a->setChecked(m_stashingClearsSelection);
added = true;
}
if (this->m_menus.testFlag(MenuHighlightStashed))
{
// this function requires someone provides the model strings to be highlighted
// this function requires that someone provides the model strings to be highlighted
QAction *a = menu.addAction(CIcons::appDbStash16(), "Highlight stashed", this, SLOT(ps_toggleHighlightStashedModels()));
a->setCheckable(true);
a->setChecked(this->derivedModel()->highlightDbData());
added = true;
}
if (added) { menu.addSeparator(); }
if (this->m_menus.testFlag(MenuHighlightInvalid))
{
// this function requires that someone provides the model strings to be highlighted
QAction *a = menu.addAction(CIcons::appDbStash16(), "Highlight invalid models", this, SLOT(ps_to));
a->setCheckable(true);
a->setChecked(this->derivedModel()->highlightDbData());
}
CViewWithDbObjects::customMenu(menu);
}
void CAircraftModelView::ps_toggleHighlightStashedModels()
{
bool h = derivedModel()->highlightGivenModelStrings();
derivedModel()->setHighlightModelsStrings(!h);
bool h = derivedModel()->highlightModelStrings();
derivedModel()->setHighlightModelStrings(!h);
emit toggledHighlightStashedModels();
}
void CAircraftModelView::ps_toogleHighlightInvalidModels()
{
bool h = this->highlightModelsStrings();
this->setHighlightModelStrings(!h);
}
void CAircraftModelView::ps_stashingClearsSelection()
{
this->m_stashingClearsSelection = !this->m_stashingClearsSelection;
@@ -250,7 +279,7 @@ namespace BlackGui
void CAircraftModelView::ps_requestStash()
{
if (!m_menus.testFlag(MenuStashModels)) { return; }
if (!m_menus.testFlag(MenuCanStashModels)) { return; }
if (!this->hasSelection()) { return; }
emit requestStash(this->selectedObjects());
if (this->m_stashingClearsSelection)

View File

@@ -55,6 +55,18 @@ namespace BlackGui
//! Remove models with model strings
int removeModelsWithModelString(const QStringList &modelStrings, Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive);
//! \copydoc BlackGui::Models::CAircraftModelListModel::setHighlightModelStrings(const QStringList &)
void setHighlightModelStrings(const QStringList &highlightModels);
//! \copydoc BlackGui::Models::CAircraftModelListModel::setHighlightModelsStrings(bool)
void setHighlightModelStrings(bool highlight);
//! \copydoc BlackGui::Models::CAircraftModelListModel::setHighlightModelStringsColor
void setHighlightModelStringsColor(const QBrush &brush);
//! \copydoc BlackGui::Models::CAircraftModelListModel::highlightModelsStrings
bool highlightModelsStrings() const;
signals:
//! Request to stash if applicable
void requestStash(const BlackMisc::Simulation::CAircraftModelList &models);
@@ -76,6 +88,9 @@ namespace BlackGui
//! Highlight stashed models
void ps_toggleHighlightStashedModels();
//! Toggle highlight invalid models
void ps_toogleHighlightInvalidModels();
//! Toggle if stashing unselects
void ps_stashingClearsSelection();

View File

@@ -163,6 +163,9 @@ namespace BlackGui
// delegate?
if (this->m_menu) { this->m_menu->customMenu(menu); }
// separator
if (!menu.isEmpty() && ((this->m_menus & MenuStandard) > 0)) { menu.addSeparator(); }
// standard menus
int items = menu.actions().size();
if (this->m_menus.testFlag(MenuRefresh)) { menu.addAction(BlackMisc::CIcons::refresh16(), "Update", this, SIGNAL(requestUpdate())); }
@@ -192,13 +195,28 @@ namespace BlackGui
if (menu.actions().size() > items) { menu.addSeparator(); }
// selection menus
items = menu.actions().size();
SelectionMode sm = this->selectionMode();
if (sm == MultiSelection || sm == ExtendedSelection)
{
menu.addAction(BlackMisc::CIcons::empty16(), "Select all", this, SLOT(selectAll()), Qt::CTRL + Qt::Key_A);
menu.addAction(QIcon(), "Select all", this, SLOT(selectAll()), Qt::CTRL + Qt::Key_A);
}
menu.addAction(BlackMisc::CIcons::empty16(), "Clear selection", this, SLOT(clearSelection()), CShortcut::keyClearSelection());
menu.addSeparator();
if ((this->m_originalSelectionMode == MultiSelection || this->m_originalSelectionMode == ExtendedSelection) && this->m_menus.testFlag(MenuToggleSelectionMode))
{
if (sm == SingleSelection)
{
menu.addAction(QIcon(), "Switch to multi selection", this, SLOT(ps_toggleSelectionMode()));
}
else if (sm == MultiSelection || sm == ExtendedSelection)
{
menu.addAction(QIcon(), "Switch to single selection", this, SLOT(ps_toggleSelectionMode()));
}
}
if (sm != NoSelection)
{
menu.addAction(QIcon(), "Clear selection", this, SLOT(clearSelection()), CShortcut::keyClearSelection());
}
if (menu.actions().size() > items) { menu.addSeparator(); }
// load/save
items = menu.actions().size();
@@ -507,6 +525,21 @@ namespace BlackGui
this->m_displayAutomatically = a->isChecked();
}
void CViewBaseNonTemplate::ps_toggleSelectionMode()
{
if (this->m_originalSelectionMode == ExtendedSelection || this->m_originalSelectionMode == MultiSelection)
{
if (this->selectionMode() == SingleSelection)
{
this->setSelectionMode(this->m_originalSelectionMode);
}
else if (this->selectionMode() == MultiSelection)
{
this->setSelectionMode(SingleSelection);
}
}
}
void CViewBaseNonTemplate::ps_removeSelectedRows()
{
if (!m_enableDeleteSelectedRows) { return; }

View File

@@ -77,14 +77,18 @@ namespace BlackGui
MenuFilter = 1 << 5, ///< filter can be opened
MenuSave = 1 << 6, ///< save as JSON
MenuLoad = 1 << 7, ///< load from JSON
MenuToggleSelectionMode = 1 << 8, ///< allow to toggle selection mode
MenuStandard = MenuClear | MenuRemoveSelectedRows | MenuRefresh | MenuBackend |
MenuDisplayAutomatically | MenuFilter | MenuSave | MenuLoad | MenuToggleSelectionMode,
MenuLoadAndSave = MenuLoad | MenuSave,
MenuDefault = MenuClear | MenuDisplayAutomatically,
MenuDefault = MenuClear | MenuDisplayAutomatically | MenuToggleSelectionMode,
// special menus, should be in derived classes, but enums cannot be inherited
// maybe shifted in the future to elsewhere
MenuHighlightDbData = 1 << 8, ///< highlight DB data
MenuHighlightStashed = 1 << 9, ///< highlight stashed models
MenuStashModels = 1 << 10, ///< stash models
MenuStashing = MenuHighlightStashed | MenuStashModels,
MenuHighlightDbData = 1 << 9, ///< highlight DB data
MenuHighlightStashed = 1 << 10, ///< highlight stashed models
MenuCanStashModels = 1 << 11, ///< stash models
MenuStashing = MenuHighlightStashed | MenuCanStashModels,
MenuHighlightInvalid = 1 << 12 ///< highlight invalid models
};
Q_DECLARE_FLAGS(Menu, MenuFlag)
@@ -284,8 +288,9 @@ namespace BlackGui
//! Default file for load/save operations
QString getDefaultFilename() const;
ResizeMode m_resizeMode = ResizingOnceSubset; //!< mode
ResizeMode m_resizeMode = ResizingOnceSubset; //!< mode
RowsResizeMode m_rowResizeMode = Interactive; //!< row resize mode for row height
SelectionMode m_originalSelectionMode = this->selectionMode(); //!< Selection mode set
int m_resizeCount = 0; //!< flag / counter, how many resize activities
int m_skipResizeThreshold = 40; //!< when to skip resize (rows count)
int m_resizeAutoNthTime = 1; //!< with ResizeAuto, resize every n-th time
@@ -355,6 +360,9 @@ namespace BlackGui
//! Toggle auto display flag
void ps_toggleAutoDisplay();
//! Toogle between single and multi selection
void ps_toggleSelectionMode();
//! Clear the model
virtual void ps_clear() { this->clear(); }

View File

@@ -84,17 +84,13 @@ namespace BlackGui
template <class ModelClass, class ContainerType, class ObjectType, class KeyType>
void CViewWithDbObjects<ModelClass, ContainerType, ObjectType, KeyType>::customMenu(QMenu &menu) const
{
CViewBase<ModelClass, ContainerType, ObjectType>::customMenu(menu);
if (this->m_menus.testFlag(CViewBase<ModelClass, ContainerType, ObjectType>::MenuHighlightDbData))
{
if (!menu.isEmpty())
{
menu.addSeparator();
}
QAction *a = menu.addAction(CIcons::database16(), "Highlight DB data", this, SLOT(ps_toggleHighlightDbData()));
a->setCheckable(true);
a->setChecked(this->derivedModel()->highlightDbData());
}
CViewBase<ModelClass, ContainerType, ObjectType>::customMenu(menu);
}
template <class ModelClass, class ContainerType, class ObjectType, class KeyType>

View File

@@ -90,6 +90,14 @@ namespace BlackMisc
return QJsonDocument(toDatabaseJson()).toJson(format);
}
bool CAircraftModel::canInitializeFromFsd() const
{
bool nw = this->getModelType() == CAircraftModel::TypeQueriedFromNetwork ||
this->getModelType() == CAircraftModel::TypeFsdData ||
this->getModelType() == CAircraftModel::TypeUnknown;
return nw;
}
CVariant CAircraftModel::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
{
if (index.isMyself()) { return CVariant::from(*this); }
@@ -179,14 +187,6 @@ namespace BlackMisc
}
}
bool CAircraftModel::canInitializeFromFsd() const
{
bool nw = this->getModelType() == CAircraftModel::TypeQueriedFromNetwork ||
this->getModelType() == CAircraftModel::TypeFsdData ||
this->getModelType() == CAircraftModel::TypeUnknown;
return nw;
}
int CAircraftModel::comparePropertyByIndex(const CAircraftModel &compareValue, const CPropertyIndex &index) const
{
if (IDatastoreObjectWithIntegerKey::canHandleIndex(index)) { return IDatastoreObjectWithIntegerKey::comparePropertyByIndex(compareValue, index);}
@@ -204,6 +204,7 @@ namespace BlackMisc
return this->m_distributor.comparePropertyByIndex(compareValue.getDistributor(), index.copyFrontRemoved());
case IndexDescription:
return this->m_description.compare(compareValue.getDescription(), Qt::CaseInsensitive);
case IndexSimulatorInfoAsString:
case IndexSimulatorInfo:
return this->m_simulator.comparePropertyByIndex(compareValue.getSimulatorInfo(), index.copyFrontRemoved());
case IndexName:

View File

@@ -176,6 +176,12 @@ namespace BlackMisc
}
CStatusMessageList CAircraftModelList::validateForPublishing() const
{
CAircraftModelList invalidModels;
return validateForPublishing(invalidModels);
}
CStatusMessageList CAircraftModelList::validateForPublishing(CAircraftModelList &invalidModels) const
{
if (this->isEmpty()) { return CStatusMessageList(); }
CStatusMessageList msgs;
@@ -198,6 +204,7 @@ namespace BlackMisc
singleMsg.prependMessage(model.getModelString() + ": ");
}
msgs.push_back(singleMsg);
invalidModels.push_back(model);
}
return msgs;
}

View File

@@ -90,6 +90,9 @@ namespace BlackMisc
//! Validate for publishing
CStatusMessageList validateForPublishing() const;
//! Validate for publishing
CStatusMessageList validateForPublishing(CAircraftModelList &invalidModels) const;
//! To database JSON
QJsonArray toDatabaseJson() const;