mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	filter: set dive selection at once
For each selected dive that is hidden by the filter, unselect_dive() was called, which led to a recalculation of the current dive and divecomputer. Instead, collect all deselected dives and deselect them at the end. Thus, these calculations are performed only once. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
		
							parent
							
								
									9f455b1457
								
							
						
					
					
						commit
						6df1c62dfc
					
				
					 4 changed files with 98 additions and 39 deletions
				
			
		| 
						 | 
				
			
			@ -15,7 +15,7 @@
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
// Set filter status of dive and return whether it has been changed
 | 
			
		||||
bool DiveFilter::setFilterStatus(struct dive *d, bool shown) const
 | 
			
		||||
bool DiveFilter::setFilterStatus(struct dive *d, bool shown, std::vector<dive *> &removeFromSelection) const
 | 
			
		||||
{
 | 
			
		||||
	bool old_shown, changed;
 | 
			
		||||
	if (!d)
 | 
			
		||||
| 
						 | 
				
			
			@ -23,16 +23,16 @@ bool DiveFilter::setFilterStatus(struct dive *d, bool shown) const
 | 
			
		|||
	old_shown = !d->hidden_by_filter;
 | 
			
		||||
	d->hidden_by_filter = !shown;
 | 
			
		||||
	if (!shown && d->selected)
 | 
			
		||||
		deselect_dive(d);
 | 
			
		||||
		removeFromSelection.push_back(d);
 | 
			
		||||
	changed = old_shown != shown;
 | 
			
		||||
	if (changed)
 | 
			
		||||
		shown_dives += shown - old_shown;
 | 
			
		||||
	return changed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DiveFilter::updateDiveStatus(dive *d, bool newStatus, ShownChange &change) const
 | 
			
		||||
void DiveFilter::updateDiveStatus(dive *d, bool newStatus, ShownChange &change, std::vector<dive *> &removeFromSelection) const
 | 
			
		||||
{
 | 
			
		||||
	if (setFilterStatus(d, newStatus)) {
 | 
			
		||||
	if (setFilterStatus(d, newStatus, removeFromSelection)) {
 | 
			
		||||
		if (newStatus)
 | 
			
		||||
			change.newShown.push_back(d);
 | 
			
		||||
		else
 | 
			
		||||
| 
						 | 
				
			
			@ -54,19 +54,20 @@ bool FilterData::validFilter() const
 | 
			
		|||
 | 
			
		||||
ShownChange DiveFilter::update(const QVector<dive *> &dives) const
 | 
			
		||||
{
 | 
			
		||||
	dive *old_current = current_dive;
 | 
			
		||||
 | 
			
		||||
	ShownChange res;
 | 
			
		||||
	bool doDS = diveSiteMode();
 | 
			
		||||
	bool doFullText = filterData.fullText.doit();
 | 
			
		||||
	std::vector<dive *> selection = getDiveSelection();
 | 
			
		||||
	std::vector<dive *> removeFromSelection;
 | 
			
		||||
	for (dive *d: dives) {
 | 
			
		||||
		// There are three modes: divesite, fulltext, normal
 | 
			
		||||
		bool newStatus = doDS        ? dive_sites.contains(d->dive_site) :
 | 
			
		||||
				 doFullText  ? fulltext_dive_matches(d, filterData.fullText, filterData.fulltextStringMode) && showDive(d) :
 | 
			
		||||
					       showDive(d);
 | 
			
		||||
		updateDiveStatus(d, newStatus, res);
 | 
			
		||||
		updateDiveStatus(d, newStatus, res, removeFromSelection);
 | 
			
		||||
	}
 | 
			
		||||
	res.currentChanged = old_current != current_dive;
 | 
			
		||||
	updateSelection(selection, std::vector<dive *>(), removeFromSelection);
 | 
			
		||||
	res.currentChanged = setSelection(selection);
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,30 +83,31 @@ void DiveFilter::reset()
 | 
			
		|||
 | 
			
		||||
ShownChange DiveFilter::updateAll() const
 | 
			
		||||
{
 | 
			
		||||
	dive *old_current = current_dive;
 | 
			
		||||
 | 
			
		||||
	ShownChange res;
 | 
			
		||||
	int i;
 | 
			
		||||
	dive *d;
 | 
			
		||||
	std::vector<dive *> selection = getDiveSelection();
 | 
			
		||||
	std::vector<dive *> removeFromSelection;
 | 
			
		||||
	// There are three modes: divesite, fulltext, normal
 | 
			
		||||
	if (diveSiteMode()) {
 | 
			
		||||
		for_each_dive(i, d) {
 | 
			
		||||
			bool newStatus = dive_sites.contains(d->dive_site);
 | 
			
		||||
			updateDiveStatus(d, newStatus, res);
 | 
			
		||||
			updateDiveStatus(d, newStatus, res, removeFromSelection);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (filterData.fullText.doit()) {
 | 
			
		||||
		FullTextResult ft = fulltext_find_dives(filterData.fullText, filterData.fulltextStringMode);
 | 
			
		||||
		for_each_dive(i, d) {
 | 
			
		||||
			bool newStatus = ft.dive_matches(d) && showDive(d);
 | 
			
		||||
			updateDiveStatus(d, newStatus, res);
 | 
			
		||||
			updateDiveStatus(d, newStatus, res, removeFromSelection);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for_each_dive(i, d) {
 | 
			
		||||
			bool newStatus = showDive(d);
 | 
			
		||||
			updateDiveStatus(d, newStatus, res);
 | 
			
		||||
			updateDiveStatus(d, newStatus, res, removeFromSelection);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	res.currentChanged = old_current != current_dive;
 | 
			
		||||
	updateSelection(selection, std::vector<dive *>(), removeFromSelection);
 | 
			
		||||
	res.currentChanged = setSelection(selection);
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,8 +57,10 @@ public:
 | 
			
		|||
private:
 | 
			
		||||
	DiveFilter();
 | 
			
		||||
	bool showDive(const struct dive *d) const; // Should that dive be shown?
 | 
			
		||||
	bool setFilterStatus(struct dive *d, bool shown) const;
 | 
			
		||||
	void updateDiveStatus(dive *d, bool newStatus, ShownChange &change) const;
 | 
			
		||||
	bool setFilterStatus(struct dive *d, bool shown,
 | 
			
		||||
			     std::vector<dive *> &removeFromSelection) const;
 | 
			
		||||
	void updateDiveStatus(dive *d, bool newStatus, ShownChange &change,
 | 
			
		||||
			      std::vector<dive *> &removeFromSelection) const;
 | 
			
		||||
 | 
			
		||||
	QVector<dive_site *> dive_sites;
 | 
			
		||||
	FilterData filterData;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -130,51 +130,63 @@ extern "C" void dump_selection(void)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Get closest dive in selection, if possible a newer dive.
 | 
			
		||||
// Supposes that selection is sorted
 | 
			
		||||
static dive *closestInSelection(timestamp_t when, const std::vector<dive *> &selection)
 | 
			
		||||
{
 | 
			
		||||
	// Start from back until we get the first dive that is before
 | 
			
		||||
	// the supposed-to-be selected dive. (Note: this mimics the
 | 
			
		||||
	// old behavior when the current dive changed).
 | 
			
		||||
	for (auto it = selection.rbegin(); it < selection.rend(); ++it) {
 | 
			
		||||
		if ((*it)->when > when && !(*it)->hidden_by_filter)
 | 
			
		||||
			return *it;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We didn't find a more recent selected dive -> try to
 | 
			
		||||
	// find *any* visible selected dive.
 | 
			
		||||
	for (dive *d: selection) {
 | 
			
		||||
		if (!d->hidden_by_filter)
 | 
			
		||||
			return d;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set the current dive either from a list of selected dives,
 | 
			
		||||
// or a newly selected dive. In both cases, try to select the
 | 
			
		||||
// dive that is newer that is newer than the given date.
 | 
			
		||||
// dive that is newer than the given date.
 | 
			
		||||
// This mimics the old behavior when the current dive changed.
 | 
			
		||||
// If a current dive outside of the selection was set, add
 | 
			
		||||
// it to the list of selected dives, so that we never end up
 | 
			
		||||
// in a situation where we display a non-selected dive.
 | 
			
		||||
static void setClosestCurrentDive(timestamp_t when, const std::vector<dive *> &selection, QVector<dive *> &divesToSelect)
 | 
			
		||||
{
 | 
			
		||||
	// Start from back until we get the first dive that is before
 | 
			
		||||
	// the supposed-to-be selected dive. (Note: this mimics the
 | 
			
		||||
	// old behavior when the current dive changed).
 | 
			
		||||
	for (auto it = selection.rbegin(); it < selection.rend(); ++it) {
 | 
			
		||||
		if ((*it)->when > when && !(*it)->hidden_by_filter) {
 | 
			
		||||
			current_dive = *it;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We didn't find a more recent selected dive -> try to
 | 
			
		||||
	// find *any* visible selected dive.
 | 
			
		||||
	for (dive *d: selection) {
 | 
			
		||||
		if (!d->hidden_by_filter) {
 | 
			
		||||
	if (dive *d = closestInSelection(when, selection)) {
 | 
			
		||||
		current_dive = d;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// No selected dive is visible! Take the closest dive. Note, this might
 | 
			
		||||
	// return null, but that just means unsetting the current dive (as no
 | 
			
		||||
	// dive is visible anyway).
 | 
			
		||||
	current_dive = find_next_visible_dive(when);
 | 
			
		||||
	if (current_dive)
 | 
			
		||||
	if (current_dive) {
 | 
			
		||||
		current_dive->selected = true;
 | 
			
		||||
		amount_selected++;
 | 
			
		||||
		divesToSelect.push_back(current_dive);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reset the selection to the dives of the "selection" vector and send the appropriate signals.
 | 
			
		||||
// Set the current dive to "currentDive". "currentDive" must be an element of "selection" (or
 | 
			
		||||
// null if "seletion" is empty). Return true if the selection or current dive changed.
 | 
			
		||||
void setSelection(const std::vector<dive *> &selection, dive *currentDive, int currentDc)
 | 
			
		||||
// null if "selection" is empty). Return true if the current dive changed.
 | 
			
		||||
bool setSelection(const std::vector<dive *> &selection, dive *currentDive, int currentDc)
 | 
			
		||||
{
 | 
			
		||||
	// To do so, generate vectors of dives to be selected and deselected.
 | 
			
		||||
	// We send signals batched by trip, so keep track of trip/dive pairs.
 | 
			
		||||
	QVector<dive *> divesToSelect;
 | 
			
		||||
	divesToSelect.reserve(selection.size());
 | 
			
		||||
	const dive *oldCurrent = current_dive;
 | 
			
		||||
 | 
			
		||||
	// Since we select only dives, there are no selected trips!
 | 
			
		||||
	amount_trips_selected = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -223,6 +235,15 @@ void setSelection(const std::vector<dive *> &selection, dive *currentDive, int c
 | 
			
		|||
 | 
			
		||||
	// Send the new selection
 | 
			
		||||
	emit diveListNotifier.divesSelected(divesToSelect);
 | 
			
		||||
	return current_dive != oldCurrent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool setSelection(const std::vector<dive *> &selection)
 | 
			
		||||
{
 | 
			
		||||
	dive *newCurrent = current_dive;
 | 
			
		||||
	if (current_dive && std::find(selection.begin(), selection.end(), current_dive) == selection.end())
 | 
			
		||||
		newCurrent = closestInSelection(current_dive->when, selection);
 | 
			
		||||
	return setSelection(selection, newCurrent, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" void select_single_dive(dive *d)
 | 
			
		||||
| 
						 | 
				
			
			@ -249,6 +270,32 @@ std::vector<dive *> getDiveSelection()
 | 
			
		|||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool diveInSelection(const std::vector<dive *> &selection, const dive *d)
 | 
			
		||||
{
 | 
			
		||||
	// Do a binary search using the ordering of the dive list.
 | 
			
		||||
	auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than);
 | 
			
		||||
	return it != selection.end() && *it == d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void updateSelection(std::vector<dive *> &selection, const std::vector<dive *> &add, const std::vector<dive *> &remove)
 | 
			
		||||
{
 | 
			
		||||
	// We could sort the array and merge the vectors as we do in the undo code. But is it necessary?
 | 
			
		||||
	for (dive *d: add) {
 | 
			
		||||
		auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than);
 | 
			
		||||
		if (it != selection.end() && *it == d)
 | 
			
		||||
			continue; // Ooops. Already there?
 | 
			
		||||
		selection.insert(it, d);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Likewise, we could sort the array and be smarter here. Again, is it necessary?
 | 
			
		||||
	for (dive *d: remove) {
 | 
			
		||||
		auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than);
 | 
			
		||||
		if (it == selection.end() || *it != d)
 | 
			
		||||
			continue; // Ooops. Not there?
 | 
			
		||||
		selection.erase(it);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Select the first dive that is visible
 | 
			
		||||
extern "C" void select_newest_visible_dive()
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,10 +45,18 @@ extern void dump_selection(void);
 | 
			
		|||
// Set the current dive to "currentDive" and the current dive computer to "currentDc".
 | 
			
		||||
// "currentDive" must be an element of "selection" (or null if "seletion" is empty).
 | 
			
		||||
// If "currentDc" is negative, an attempt will be made to keep the current computer number.
 | 
			
		||||
void setSelection(const std::vector<dive *> &selection, dive *currentDive, int currentDc);
 | 
			
		||||
// Returns true if the current dive changed.
 | 
			
		||||
bool setSelection(const std::vector<dive *> &selection, dive *currentDive, int currentDc);
 | 
			
		||||
 | 
			
		||||
// Get currently selectd dives
 | 
			
		||||
// Set selection, but try to keep the current dive. If current dive is not in selection,
 | 
			
		||||
// find the nearest current dive in the selection
 | 
			
		||||
// Returns true if the current dive changed.
 | 
			
		||||
bool setSelection(const std::vector<dive *> &selection);
 | 
			
		||||
 | 
			
		||||
// Get currently selected dives
 | 
			
		||||
std::vector<dive *> getDiveSelection();
 | 
			
		||||
bool diveInSelection(const std::vector<dive *> &selection, const dive *d);
 | 
			
		||||
void updateSelection(std::vector<dive *> &selection, const std::vector<dive *> &add, const std::vector<dive *> &remove);
 | 
			
		||||
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue