Skip to content

Commit

Permalink
feat(cpn): Add radio sort order edit and sorting models list by any c…
Browse files Browse the repository at this point in the history
…olumn (#3659)

* feat(cpn): Add radio sort order edit (color) and sorting models list by any column (all)

* Add column double click to enable/disable model sorting (disabled by default)
  • Loading branch information
Neil Horne authored and pfeerick committed Jun 23, 2023
1 parent 470db43 commit cee7393
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 55 deletions.
35 changes: 35 additions & 0 deletions companion/src/firmwares/radiodata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "radiodata.h"
#include "radiodataconversionstate.h"
#include "eeprominterface.h"
#include "compounditemmodels.h"

RadioData::RadioData() :
sortOrder(0)
Expand Down Expand Up @@ -308,3 +309,37 @@ QString RadioData::unEscapeCSV(QString str)
str.replace("//","/");
return str;
}

// static
QString RadioData::modelSortOrderToString(int value)
{
switch(value) {
case MSO_NO_SORT:
return tr("None");
case MSO_NAME_ASC:
return tr("Name %1").arg(CPN_STR_SW_INDICATOR_UP);
case MSO_NAME_DES:
return tr("Name %1").arg(CPN_STR_SW_INDICATOR_DN);
case MSO_DATE_ASC:
return tr("Last Opened %1").arg(CPN_STR_SW_INDICATOR_UP);
case MSO_DATE_DES:
return tr("Last Opened %1").arg(CPN_STR_SW_INDICATOR_DN);
default:
return CPN_STR_UNKNOWN_ITEM;
}
}

// static
AbstractStaticItemModel * RadioData::modelSortOrderItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName("radio.modelsortorder");

for (int i = 0; i < MSO_SORT_COUNT; i++) {
mdl->appendToItemList(modelSortOrderToString(i), i);
}

mdl->loadItemList();
return mdl;
}

16 changes: 16 additions & 0 deletions companion/src/firmwares/radiodata.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,20 @@

#include <QtCore>

// identiying names of static abstract item models
constexpr char AIM_RADIO_MODEL_SORT_ORDER[] {"radio.modelsortorder"};

class RadioDataConversionState;
class AbstractStaticItemModel;

enum MODEL_SORT_ORDER{
MSO_NO_SORT,
MSO_NAME_ASC,
MSO_NAME_DES,
MSO_DATE_ASC,
MSO_DATE_DES,
MSO_SORT_COUNT
};

class RadioData {
Q_DECLARE_TR_FUNCTIONS(RadioData)
Expand Down Expand Up @@ -52,6 +65,9 @@ class RadioData {
void fixModelFilenames();
QString getNextModelFilename();

static QString modelSortOrderToString(int value);
static AbstractStaticItemModel * modelSortOrderItemModel();

// leave here until all calls repointed
static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false)
{ return DataHelpers::getElementName(prefix, index, name, padding); }
Expand Down
124 changes: 93 additions & 31 deletions companion/src/mdichild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@
MdiChild::MdiChild(QWidget * parent, QWidget * parentWin, Qt::WindowFlags f):
QWidget(parent, f),
ui(new Ui::MdiChild),
modelsListModel(NULL),
labelsListModel(NULL),
modelsListModel(nullptr),
labelsListModel(nullptr),
modelsListProxyModel(nullptr),
parentWindow(parentWin),
radioToolbar(NULL),
modelsToolbar(NULL),
labelsToolbar(NULL),
lblLabels(NULL),

radioToolbar(nullptr),
modelsToolbar(nullptr),
labelsToolbar(nullptr),
lblLabels(nullptr),
firmware(getCurrentFirmware()),
lastSelectedModel(-1),
isUntitled(true),
forceCloseFlag(false),
stateDataVersion(1)
stateDataVersion(1),
cboModelSortOrder(nullptr)
{
ui->setupUi(this);
setWindowIcon(CompanionIcon("open.png"));
Expand All @@ -76,6 +77,7 @@ MdiChild::MdiChild(QWidget * parent, QWidget * parentWin, Qt::WindowFlags f):
ui->modelsList->setDragDropMode(QAbstractItemView::DragDrop);
ui->modelsList->setStyle(new ItemViewProxyStyle(ui->modelsList->style()));
ui->modelsList->setStyleSheet("QTreeView::item {margin: 2px 0;}"); // a little more space for our drop indicators

ui->lstLabels->setContextMenuPolicy(Qt::CustomContextMenu);

retranslateUi();
Expand Down Expand Up @@ -117,6 +119,7 @@ MdiChild::MdiChild(QWidget * parent, QWidget * parentWin, Qt::WindowFlags f):

MdiChild::~MdiChild()
{
delete modelSortOrderItemModel;
delete ui;
}

Expand Down Expand Up @@ -191,7 +194,7 @@ QAction * MdiChild::addAct(Actions actId, const QString & icon, const char * slo
newAction->setIcon(CompanionIcon(icon));
if (!shortcut.isEmpty())
newAction->setShortcut(shortcut);
if (slotObj == NULL)
if (slotObj == nullptr)
slotObj = this;
if (slot)
connect(newAction, SIGNAL(triggered()), slotObj, slot);
Expand All @@ -206,7 +209,7 @@ void MdiChild::setupNavigation()
act->deleteLater();
}
action.clear();
action.fill(NULL, ACT_ENUM_END);
action.fill(nullptr, ACT_ENUM_END);

addAct(ACT_GEN_EDT, "edit.png", SLOT(generalEdit()), tr("Alt+Shift+E"));
addAct(ACT_GEN_CPY, "copy.png", SLOT(copyGeneralSettings()), tr("Ctrl+Alt+C"));
Expand Down Expand Up @@ -284,6 +287,18 @@ void MdiChild::setupNavigation()
if ((btn = qobject_cast<QToolButton *>(radioToolbar->widgetForAction(action[ACT_GEN_SIM])))) {
btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
}

if (cboModelSortOrder)
cboModelSortOrder->deleteLater();
cboModelSortOrder = new QComboBox(this);
modelSortOrderItemModel = RadioData::modelSortOrderItemModel();
cboModelSortOrder->setModel(modelSortOrderItemModel);
connect(cboModelSortOrder, QOverload<int>::of(&QComboBox::currentIndexChanged), [=] (int index) {
radioData.sortOrder = index;
setModified();
});
action.replace(ACT_GEN_SRT, radioToolbar->addWidget(cboModelSortOrder));

// add spacer to right-align the buttons
QWidget * sp = new QWidget(this);
sp->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
Expand Down Expand Up @@ -328,7 +343,14 @@ void MdiChild::updateNavigation()
labelsToolbar->setVisible(hasLabels);
ui->lstLabels->setVisible(hasLabels);
lblLabels->setVisible(hasLabels);

action[ACT_GEN_PST]->setEnabled(hasClipboardData(1));
if (hasLabels) {
cboModelSortOrder->blockSignals(true);
cboModelSortOrder->setCurrentIndex(radioData.sortOrder);
cboModelSortOrder->blockSignals(false);
}
action[ACT_GEN_SRT]->setVisible(hasLabels);

action[ACT_MDL_CUT]->setEnabled(modelsSelected);
action[ACT_MDL_CUT]->setText(tr("Cut") % (modelsSelected ? sp % modelsRemvTxt : ns));
Expand All @@ -355,6 +377,7 @@ void MdiChild::retranslateUi()
action[ACT_GEN_CPY]->setText(tr("Copy Radio Settings"));
action[ACT_GEN_PST]->setText(tr("Paste Radio Settings"));
action[ACT_GEN_SIM]->setText(tr("Simulate Radio"));
cboModelSortOrder->setToolTip(tr("Radio Models Order"));

action[ACT_ITM_EDT]->setText(tr("Edit Model"));
action[ACT_ITM_DEL]->setText(tr("Delete"));
Expand Down Expand Up @@ -437,17 +460,17 @@ QAction * MdiChild::getAction(const MdiChild::Actions type)
if (type < ACT_ENUM_END)
return action[type];
else
return NULL;
return nullptr;
}

void MdiChild::showModelsListContextMenu(const QPoint & pos)
{
QModelIndex modelIndex = ui->modelsList->indexAt(pos);
QModelIndex viewIndex = ui->modelsList->indexAt(pos);
QMenu contextMenu;

updateNavigation();

if (modelsListModel->isModelType(modelIndex)) {
if (modelsListModel->isModelType(getDataIndex(viewIndex))) {
contextMenu.addActions(getEditActions());
if (countSelectedModels() == 1) {
contextMenu.addSeparator();
Expand Down Expand Up @@ -507,6 +530,11 @@ void MdiChild::adjustToolbarLayout()

void MdiChild::initModelsList()
{
if (modelsListProxyModel)
delete modelsListProxyModel;

modelsListProxyModel = new ModelsListProxyModel();

if (modelsListModel)
delete modelsListModel;

Expand All @@ -516,12 +544,15 @@ void MdiChild::initModelsList()
connect(modelsListModel, &ModelsListModel::refreshRequested, this, &MdiChild::refresh);
connect(modelsListModel, &QAbstractItemModel::dataChanged, this, &MdiChild::onDataChanged);

ui->modelsList->setModel(modelsListModel);
modelsListProxyModel->setSourceModel(modelsListModel);

ui->modelsList->setModel(modelsListProxyModel);
ui->modelsList->selectionModel()->currentIndex().row();

// Labels Editor + Model
if(labelsListModel)
if (labelsListModel)
delete labelsListModel;

labelsListModel = new LabelsModel(ui->modelsList->selectionModel(),
&radioData, this);
connect(labelsListModel, &LabelsModel::modelChanged, this, &MdiChild::modelLabelsChanged);
Expand All @@ -531,9 +562,23 @@ void MdiChild::initModelsList()
ui->lstLabels->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
ui->lstLabels->setItemDelegate(new LabelEditTextDelegate);

modelsListProxyModel->setFilter(labelsListModel); // TODO Used for filters when developed

ui->modelsList->setIndentation(0);

refresh();
modelsListProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);

connect(ui->modelsList->header(), &QHeaderView::sectionDoubleClicked, [=] (int logicalIndex) {
if (ui->modelsList->header()->isSortIndicatorShown()) {
ui->modelsList->sortByColumn(-1, Qt::AscendingOrder); // turn off sort indicator shown and return proxy model to its unsorted order
ui->modelsList->setSortingEnabled(false); // disable clicking a column to sort
}
else {
ui->modelsList->setSortingEnabled(true); // enable sorting by clicking a column
ui->modelsList->sortByColumn(logicalIndex, Qt::AscendingOrder);
}
});

if (firmware->getCapability(Capability::HasModelLabels)) {
ui->modelsList->header()->resizeSection(0, ui->modelsList->header()->sectionSize(0) * 1.5); // pad out model names
Expand All @@ -546,11 +591,10 @@ void MdiChild::initModelsList()

void MdiChild::refresh()
{
bool expand = true; // TODO: restore user-preferred state
clearCutList();
modelsListModel->refresh();
if (expand)
ui->modelsList->expandAll();
modelsListProxyModel->invalidate(); // force view refresh
ui->modelsList->expandAll();
if (lastSelectedModel > -1) {
setSelectedModel(lastSelectedModel);
lastSelectedModel = -1;
Expand All @@ -561,8 +605,9 @@ void MdiChild::refresh()

void MdiChild::onItemActivated(const QModelIndex index)
{
if (modelsListModel->isModelType(index)) {
int mIdx = modelsListModel->getModelIndex(index);
QModelIndex srcIdx = getDataIndex(index);
if (modelsListModel->isModelType(srcIdx)) {
int mIdx = modelsListModel->getModelIndex(srcIdx);
if (mIdx < 0 || mIdx >= (int)radioData.models.size())
return;
if (radioData.models[mIdx].isEmpty())
Expand Down Expand Up @@ -593,20 +638,32 @@ void MdiChild::onDataChanged(const QModelIndex & index)

QModelIndex MdiChild::getCurrentIndex() const
{
return ui->modelsList->selectionModel()->currentIndex();
return getDataIndex(ui->modelsList->selectionModel()->currentIndex());
}

int MdiChild::getCurrentModel() const
{
return modelsListModel->getModelIndex(getCurrentIndex());
}

QModelIndex MdiChild::getDataIndex(QModelIndex viewIndex) const
{
return modelsListProxyModel->mapToSource(viewIndex);
}

int MdiChild::getDataModel(QModelIndex viewIndex) const
{
return modelsListModel->getModelIndex(getDataIndex(viewIndex));
}

int MdiChild::countSelectedModels() const
{
int ret = 0;

foreach (QModelIndex index, ui->modelsList->selectionModel()->selectedRows()) {
if (index.isValid() && modelsListModel->isModelType(index) && !radioData.models.at(modelsListModel->getModelIndex(index)).isEmpty())
foreach (QModelIndex viewIndex, ui->modelsList->selectionModel()->selectedRows()) {
QModelIndex index = getDataIndex(viewIndex);
if (index.isValid() && modelsListModel->isModelType(index) &&
!radioData.models.at(modelsListModel->getModelIndex(index)).isEmpty())
++ret;
}
return ret;
Expand All @@ -621,8 +678,9 @@ bool MdiChild::setSelectedModel(const int modelIndex)
{
QModelIndex idx = modelsListModel->getIndexForModel(modelIndex);
if (idx.isValid()) {
ui->modelsList->scrollTo(idx);
ui->modelsList->setCurrentIndex(idx);
QModelIndex viewIdx = modelsListProxyModel->mapFromSource(idx);
ui->modelsList->scrollTo(viewIdx);
ui->modelsList->setCurrentIndex(viewIdx);
return true;
}
return false;
Expand All @@ -631,7 +689,8 @@ bool MdiChild::setSelectedModel(const int modelIndex)
QVector<int> MdiChild::getSelectedModels() const
{
QVector<int> models;
foreach (QModelIndex index, ui->modelsList->selectionModel()->selectedRows()) {
foreach (QModelIndex viewIndex, ui->modelsList->selectionModel()->selectedRows()) {
QModelIndex index = getDataIndex(viewIndex);
if (index.isValid() && modelsListModel->isModelType(index))
models.append(modelsListModel->getModelIndex(index));
}
Expand Down Expand Up @@ -957,7 +1016,7 @@ void MdiChild::pasteGeneralData(const QMimeData * mimeData)
GeneralSettings gs;
bool hasGenSettings = false;

if (!ModelsListModel::decodeMimeData(mimeData, NULL, &gs, &hasGenSettings))
if (!ModelsListModel::decodeMimeData(mimeData, nullptr, &gs, &hasGenSettings))
return;

if (hasGenSettings && askQuestion(tr("Do you want to overwrite radio general settings?")) == QMessageBox::Yes) {
Expand Down Expand Up @@ -999,7 +1058,8 @@ void MdiChild::pasteGeneralSettings()

void MdiChild::copy()
{
QMimeData * mimeData = modelsListModel->getModelsMimeData(ui->modelsList->selectionModel()->selectedRows());
QModelIndexList indexes = modelsListProxyModel->mapSelectionToSource(ui->modelsList->selectionModel()->selection()).indexes();
QMimeData * mimeData = modelsListModel->getModelsMimeData(indexes);
modelsListModel->getHeaderMimeData(mimeData);
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
clearCutList(); // clear the list by default, populate afterwards, eg. in cut().
Expand All @@ -1009,7 +1069,8 @@ void MdiChild::cut()
{
copy();
cutModels = getSelectedModels();
modelsListModel->markItemsForCut(ui->modelsList->selectionModel()->selectedIndexes());
QModelIndexList indexes = modelsListProxyModel->mapSelectionToSource(ui->modelsList->selectionModel()->selection()).indexes();
modelsListModel->markItemsForCut(indexes);
}

void MdiChild::removeModelFromCutList(const int modelIndex)
Expand Down Expand Up @@ -1151,7 +1212,7 @@ void MdiChild::openModelEditWindow(int row)
void MdiChild::print(int model, const QString & filename)
{
// TODO
PrintDialog * pd = NULL;
PrintDialog * pd = nullptr;

if (model>=0 && !filename.isEmpty()) {
pd = new PrintDialog(this, firmware, radioData.generalSettings, radioData.models[model], filename);
Expand All @@ -1171,6 +1232,7 @@ void MdiChild::setDefault()
int row = getCurrentModel();
if (!radioData.models[row].isEmpty() && radioData.generalSettings.currModelIndex != (unsigned)row) {
radioData.setCurrentModel(row);
refresh();
}
}

Expand Down Expand Up @@ -1370,7 +1432,7 @@ bool MdiChild::convertStorage(Board::Type from, Board::Type to, bool newFile)
isUntitled = true;

if (cstate.hasLogEntries(RadioDataConversionState::EVT_INF)) {
auto * msgBox = new QDialog(Q_NULLPTR, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
auto * msgBox = new QDialog(nullptr, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);

auto * tv = new ExportableTableView(msgBox);
tv->setSortingEnabled(true);
Expand Down
Loading

0 comments on commit cee7393

Please sign in to comment.