mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
core: replace divesite_table_t by a vector of std::unique_ptr<>s
This is a long commit, because it introduces a new abstraction: a general std::vector<> of std::unique_ptrs<>. Moreover, it replaces a number of pointers by C++ references, when the callee does not suppoert null objects. This simplifies memory management and makes ownership more explicit. It is a proof-of-concept and a test-bed for the other core data structrures. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
411188728d
commit
e39dea3d68
41 changed files with 451 additions and 426 deletions
|
@ -37,7 +37,7 @@ int LocationInformationModel::columnCount(const QModelIndex &) const
|
|||
|
||||
int LocationInformationModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return divelog.sites->nr;
|
||||
return (int)divelog.sites->size();
|
||||
}
|
||||
|
||||
QVariant LocationInformationModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
|
@ -81,21 +81,18 @@ Qt::ItemFlags LocationInformationModel::flags(const QModelIndex &index) const
|
|||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
|
||||
QVariant LocationInformationModel::getDiveSiteData(const struct dive_site *ds, int column, int role)
|
||||
QVariant LocationInformationModel::getDiveSiteData(const struct dive_site &ds, int column, int role)
|
||||
{
|
||||
if (!ds)
|
||||
return QVariant();
|
||||
|
||||
switch(role) {
|
||||
case Qt::EditRole:
|
||||
case Qt::DisplayRole:
|
||||
switch(column) {
|
||||
case DIVESITE: return QVariant::fromValue<dive_site *>((dive_site *)ds); // Not nice: casting away const
|
||||
case NAME: return QString::fromStdString(ds->name);
|
||||
case NUM_DIVES: return static_cast<int>(ds->dives.size());
|
||||
case DIVESITE: return QVariant::fromValue<dive_site *>((dive_site *)&ds); // Not nice: casting away const
|
||||
case NAME: return QString::fromStdString(ds.name);
|
||||
case NUM_DIVES: return static_cast<int>(ds.dives.size());
|
||||
case LOCATION: return "TODO";
|
||||
case DESCRIPTION: return QString::fromStdString(ds->description);
|
||||
case NOTES: return QString::fromStdString(ds->notes);
|
||||
case DESCRIPTION: return QString::fromStdString(ds.description);
|
||||
case NOTES: return QString::fromStdString(ds.notes);
|
||||
case TAXONOMY: return "TODO";
|
||||
}
|
||||
break;
|
||||
|
@ -111,22 +108,22 @@ QVariant LocationInformationModel::getDiveSiteData(const struct dive_site *ds, i
|
|||
case EDIT: return editIcon();
|
||||
case REMOVE: return trashIcon();
|
||||
#endif
|
||||
case NAME: return dive_site_has_gps_location(ds) ? QIcon(":geotag-icon") : QVariant();
|
||||
case NAME: return dive_site_has_gps_location(&ds) ? QIcon(":geotag-icon") : QVariant();
|
||||
}
|
||||
break;
|
||||
case DIVESITE_ROLE:
|
||||
return QVariant::fromValue<dive_site *>((dive_site *)ds); // Not nice: casting away const
|
||||
return QVariant::fromValue<dive_site *>((dive_site *)&ds); // Not nice: casting away const
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant LocationInformationModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
if (!index.isValid() || index.row() >= (int)divelog.sites->size())
|
||||
return QVariant();
|
||||
|
||||
struct dive_site *ds = get_dive_site(index.row(), divelog.sites);
|
||||
return getDiveSiteData(ds, index.column(), role);
|
||||
const auto &ds = (*divelog.sites)[index.row()].get();
|
||||
return getDiveSiteData(*ds, index.column(), role);
|
||||
}
|
||||
|
||||
void LocationInformationModel::update()
|
||||
|
@ -137,7 +134,7 @@ void LocationInformationModel::update()
|
|||
|
||||
void LocationInformationModel::diveSiteDiveCountChanged(dive_site *ds)
|
||||
{
|
||||
int idx = get_divesite_idx(ds, divelog.sites);
|
||||
int idx = get_divesite_idx(ds, *divelog.sites);
|
||||
if (idx >= 0)
|
||||
dataChanged(createIndex(idx, NUM_DIVES), createIndex(idx, NUM_DIVES));
|
||||
}
|
||||
|
@ -162,7 +159,7 @@ void LocationInformationModel::diveSiteDeleted(struct dive_site *, int idx)
|
|||
|
||||
void LocationInformationModel::diveSiteChanged(struct dive_site *ds, int field)
|
||||
{
|
||||
int idx = get_divesite_idx(ds, divelog.sites);
|
||||
int idx = get_divesite_idx(ds, *divelog.sites);
|
||||
if (idx < 0)
|
||||
return;
|
||||
dataChanged(createIndex(idx, field), createIndex(idx, field));
|
||||
|
@ -170,7 +167,7 @@ void LocationInformationModel::diveSiteChanged(struct dive_site *ds, int field)
|
|||
|
||||
void LocationInformationModel::diveSiteDivesChanged(struct dive_site *ds)
|
||||
{
|
||||
int idx = get_divesite_idx(ds, divelog.sites);
|
||||
int idx = get_divesite_idx(ds, *divelog.sites);
|
||||
if (idx < 0)
|
||||
return;
|
||||
dataChanged(createIndex(idx, NUM_DIVES), createIndex(idx, NUM_DIVES));
|
||||
|
@ -181,9 +178,9 @@ bool DiveSiteSortedModel::filterAcceptsRow(int sourceRow, const QModelIndex &sou
|
|||
if (fullText.isEmpty())
|
||||
return true;
|
||||
|
||||
if (sourceRow < 0 || sourceRow > divelog.sites->nr)
|
||||
if (sourceRow < 0 || sourceRow > (int)divelog.sites->size())
|
||||
return false;
|
||||
struct dive_site *ds = divelog.sites->dive_sites[sourceRow];
|
||||
const auto &ds = (*divelog.sites)[sourceRow];
|
||||
QString text = QString::fromStdString(ds->name + ds->description + ds->notes);
|
||||
return text.contains(fullText, Qt::CaseInsensitive);
|
||||
}
|
||||
|
@ -193,10 +190,15 @@ bool DiveSiteSortedModel::lessThan(const QModelIndex &i1, const QModelIndex &i2)
|
|||
// The source indices correspond to indices in the global dive site table.
|
||||
// Let's access them directly without going via the source model.
|
||||
// Kind of dirty, but less effort.
|
||||
struct dive_site *ds1 = get_dive_site(i1.row(), divelog.sites);
|
||||
struct dive_site *ds2 = get_dive_site(i2.row(), divelog.sites);
|
||||
if (!ds1 || !ds2) // Invalid dive sites compare as different
|
||||
return false;
|
||||
|
||||
// Be careful to respect proper ordering when sites are invalid.
|
||||
bool valid1 = i1.row() >= 0 && i1.row() < (int)divelog.sites->size();
|
||||
bool valid2 = i2.row() >= 0 && i2.row() < (int)divelog.sites->size();
|
||||
if (!valid1 || !valid2)
|
||||
return valid1 < valid2;
|
||||
|
||||
const auto &ds1 = (*divelog.sites)[i1.row()];
|
||||
const auto &ds2 = (*divelog.sites)[i2.row()];
|
||||
switch (i1.column()) {
|
||||
case LocationInformationModel::NAME:
|
||||
default:
|
||||
|
@ -230,18 +232,19 @@ QStringList DiveSiteSortedModel::allSiteNames() const
|
|||
// This shouldn't happen, but if model and core get out of sync,
|
||||
// (more precisely: the core has more sites than the model is aware of),
|
||||
// we might get an invalid index.
|
||||
if (idx < 0 || idx > divelog.sites->nr) {
|
||||
if (idx < 0 || idx > (int)divelog.sites->size()) {
|
||||
report_info("DiveSiteSortedModel::allSiteNames(): invalid index");
|
||||
continue;
|
||||
}
|
||||
locationNames << QString::fromStdString(divelog.sites->dive_sites[idx]->name);
|
||||
locationNames << QString::fromStdString((*divelog.sites)[idx]->name);
|
||||
}
|
||||
return locationNames;
|
||||
}
|
||||
|
||||
struct dive_site *DiveSiteSortedModel::getDiveSite(const QModelIndex &idx)
|
||||
struct dive_site *DiveSiteSortedModel::getDiveSite(const QModelIndex &idx_source)
|
||||
{
|
||||
return get_dive_site(mapToSource(idx).row(), divelog.sites);
|
||||
auto idx = mapToSource(idx_source).row();
|
||||
return idx >= 0 && idx < (int)divelog.sites->size() ? (*divelog.sites)[idx].get() : NULL;
|
||||
}
|
||||
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
// Thus, different views can connect to different models.
|
||||
enum Columns { EDIT, REMOVE, NAME, DESCRIPTION, NUM_DIVES, LOCATION, NOTES, DIVESITE, TAXONOMY, COLUMNS };
|
||||
enum Roles { DIVESITE_ROLE = Qt::UserRole + 1 };
|
||||
static QVariant getDiveSiteData(const struct dive_site *ds, int column, int role);
|
||||
static QVariant getDiveSiteData(const struct dive_site &ds, int column, int role);
|
||||
|
||||
LocationInformationModel(QObject *obj = 0);
|
||||
static LocationInformationModel *instance();
|
||||
|
|
|
@ -50,9 +50,9 @@ QVariant DivesiteImportedModel::data(const QModelIndex &index, int role) const
|
|||
if (index.row() + firstIndex > lastIndex)
|
||||
return QVariant();
|
||||
|
||||
struct dive_site *ds = get_dive_site(index.row() + firstIndex, importedSitesTable);
|
||||
if (!ds)
|
||||
if (index.row() < 0 || index.row() >= (int)importedSitesTable->size())
|
||||
return QVariant();
|
||||
struct dive_site *ds = (*importedSitesTable)[index.row()].get();
|
||||
|
||||
// widgets access the model via index.column()
|
||||
// Not supporting QML access via roles
|
||||
|
@ -68,7 +68,7 @@ QVariant DivesiteImportedModel::data(const QModelIndex &index, int role) const
|
|||
// 40075000 is circumference of the earth in meters
|
||||
struct dive_site *nearest_ds =
|
||||
get_dive_site_by_gps_proximity(&ds->location,
|
||||
40075000, divelog.sites);
|
||||
40075000, *divelog.sites);
|
||||
if (nearest_ds)
|
||||
return QString::fromStdString(nearest_ds->name);
|
||||
else
|
||||
|
@ -78,7 +78,7 @@ QVariant DivesiteImportedModel::data(const QModelIndex &index, int role) const
|
|||
unsigned int distance = 0;
|
||||
struct dive_site *nearest_ds =
|
||||
get_dive_site_by_gps_proximity(&ds->location,
|
||||
40075000, divelog.sites);
|
||||
40075000, *divelog.sites);
|
||||
if (nearest_ds)
|
||||
distance = get_distance(&ds->location,
|
||||
&nearest_ds->location);
|
||||
|
@ -126,18 +126,15 @@ Qt::ItemFlags DivesiteImportedModel::flags(const QModelIndex &index) const
|
|||
return QAbstractTableModel::flags(index) | Qt::ItemIsUserCheckable;
|
||||
}
|
||||
|
||||
void DivesiteImportedModel::repopulate(struct dive_site_table *sites)
|
||||
void DivesiteImportedModel::repopulate(dive_site_table *sites)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
importedSitesTable = sites;
|
||||
firstIndex = 0;
|
||||
lastIndex = importedSitesTable->nr - 1;
|
||||
checkStates.resize(importedSitesTable->nr);
|
||||
for (int row = 0; row < importedSitesTable->nr; row++)
|
||||
if (get_dive_site_by_gps(&importedSitesTable->dive_sites[row]->location, divelog.sites))
|
||||
checkStates[row] = false;
|
||||
else
|
||||
checkStates[row] = true;
|
||||
lastIndex = (int)importedSitesTable->size() - 1; // Qt: the "last index" is negative for empty lists. Insane.
|
||||
checkStates.resize(importedSitesTable->size());
|
||||
for (size_t row = 0; row < importedSitesTable->size(); row++)
|
||||
checkStates[row] = !get_dive_site_by_gps(&(*importedSitesTable)[row]->location, *divelog.sites);
|
||||
endResetModel();
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
QVariant data(const QModelIndex& index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
void repopulate(dive_site_table_t *sites);
|
||||
void repopulate(dive_site_table *sites);
|
||||
public
|
||||
slots:
|
||||
void changeSelected(QModelIndex clickedIndex);
|
||||
|
@ -29,7 +29,7 @@ private:
|
|||
int firstIndex;
|
||||
int lastIndex;
|
||||
std::vector<char> checkStates; // char instead of bool to avoid silly pessimization of std::vector.
|
||||
struct dive_site_table *importedSitesTable;
|
||||
dive_site_table *importedSitesTable;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -118,15 +118,15 @@ const QVector<dive_site *> &MapLocationModel::selectedDs() const
|
|||
return m_selectedDs;
|
||||
}
|
||||
|
||||
static bool hasVisibleDive(const dive_site *ds)
|
||||
static bool hasVisibleDive(const dive_site &ds)
|
||||
{
|
||||
return std::any_of(ds->dives.begin(), ds->dives.end(),
|
||||
return std::any_of(ds.dives.begin(), ds.dives.end(),
|
||||
[] (const dive *d) { return !d->hidden_by_filter; });
|
||||
}
|
||||
|
||||
static bool hasSelectedDive(const dive_site *ds)
|
||||
static bool hasSelectedDive(const dive_site &ds)
|
||||
{
|
||||
return std::any_of(ds->dives.begin(), ds->dives.end(),
|
||||
return std::any_of(ds.dives.begin(), ds.dives.end(),
|
||||
[] (const dive *d) { return d->selected; });
|
||||
}
|
||||
|
||||
|
@ -160,18 +160,17 @@ void MapLocationModel::reload(QObject *map)
|
|||
if (diveSiteMode)
|
||||
m_selectedDs = DiveFilter::instance()->filteredDiveSites();
|
||||
#endif
|
||||
for (int i = 0; i < divelog.sites->nr; ++i) {
|
||||
struct dive_site *ds = divelog.sites->dive_sites[i];
|
||||
for (const auto &ds: *divelog.sites) {
|
||||
QGeoCoordinate dsCoord;
|
||||
|
||||
// Don't show dive sites of hidden dives, unless we're in dive site edit mode.
|
||||
if (!diveSiteMode && !hasVisibleDive(ds))
|
||||
if (!diveSiteMode && !hasVisibleDive(*ds))
|
||||
continue;
|
||||
if (!dive_site_has_gps_location(ds)) {
|
||||
if (!dive_site_has_gps_location(ds.get())) {
|
||||
// Dive sites that do not have a gps location are not shown in normal mode.
|
||||
// In dive-edit mode, selected sites are placed at the center of the map,
|
||||
// so that the user can drag them somewhere without having to enter coordinates.
|
||||
if (!diveSiteMode || !m_selectedDs.contains(ds) || !map)
|
||||
if (!diveSiteMode || !m_selectedDs.contains(ds.get()) || !map)
|
||||
continue;
|
||||
dsCoord = map->property("center").value<QGeoCoordinate>();
|
||||
} else {
|
||||
|
@ -179,8 +178,8 @@ void MapLocationModel::reload(QObject *map)
|
|||
qreal longitude = ds->location.lon.udeg * 0.000001;
|
||||
dsCoord = QGeoCoordinate(latitude, longitude);
|
||||
}
|
||||
if (!diveSiteMode && hasSelectedDive(ds) && !m_selectedDs.contains(ds))
|
||||
m_selectedDs.append(ds);
|
||||
if (!diveSiteMode && hasSelectedDive(*ds) && !m_selectedDs.contains(ds.get()))
|
||||
m_selectedDs.append(ds.get());
|
||||
QString name = siteMapDisplayName(ds->name);
|
||||
if (!diveSiteMode) {
|
||||
// don't add dive locations with the same name, unless they are
|
||||
|
@ -192,8 +191,8 @@ void MapLocationModel::reload(QObject *map)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
bool selected = m_selectedDs.contains(ds);
|
||||
MapLocation *location = new MapLocation(ds, dsCoord, name, selected);
|
||||
bool selected = m_selectedDs.contains(ds.get());
|
||||
MapLocation *location = new MapLocation(ds.get(), dsCoord, name, selected);
|
||||
m_mapLocations.append(location);
|
||||
if (!diveSiteMode)
|
||||
locationNameMap[name] = location;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue