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) { | ||||
| 			current_dive = d; | ||||
| 			return; | ||||
| 		} | ||||
| 	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