mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	undo: add cylinder undo commands by copy & paste
Do a simple copy & paste followed by a simple search & replace to generate cylinder undo commands from weight undo commands. Obviously, this is still missing the necessary code to keep the dive-data consistent after cylinder editing. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
		
							parent
							
								
									36754d3399
								
							
						
					
					
						commit
						aa7b0cadb2
					
				
					 5 changed files with 240 additions and 1 deletions
				
			
		|  | @ -293,6 +293,21 @@ int editWeight(int index, weightsystem_t ws, bool currentDiveOnly) | |||
| 	return execute_edit(new EditWeight(index, ws, currentDiveOnly)); | ||||
| } | ||||
| 
 | ||||
| int addCylinder(bool currentDiveOnly) | ||||
| { | ||||
| 	return execute_edit(new AddCylinder(currentDiveOnly)); | ||||
| } | ||||
| 
 | ||||
| int removeCylinder(int index, bool currentDiveOnly) | ||||
| { | ||||
| 	return execute_edit(new RemoveCylinder(index, currentDiveOnly)); | ||||
| } | ||||
| 
 | ||||
| int editCylinder(int index, cylinder_t cyl, bool currentDiveOnly) | ||||
| { | ||||
| 	return execute_edit(new EditCylinder(index, cyl, currentDiveOnly)); | ||||
| } | ||||
| 
 | ||||
| // Trip editing related commands
 | ||||
| void editTripLocation(dive_trip *trip, const QString &s) | ||||
| { | ||||
|  |  | |||
|  | @ -90,6 +90,9 @@ void editProfile(dive *d); // dive computer(s) and cylinder(s) will be reset! | |||
| int addWeight(bool currentDiveOnly); | ||||
| int removeWeight(int index, bool currentDiveOnly); | ||||
| int editWeight(int index, weightsystem_t ws, bool currentDiveOnly); | ||||
| int addCylinder(bool currentDiveOnly); | ||||
| int removeCylinder(int index, bool currentDiveOnly); | ||||
| int editCylinder(int index, cylinder_t cyl, bool currentDiveOnly); | ||||
| #ifdef SUBSURFACE_MOBILE | ||||
| // Edits a dive and creates a divesite (if createDs != NULL) or edits a divesite (if changeDs != NULL).
 | ||||
| // Takes ownership of newDive and createDs!
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include "core/subsurface-string.h" | ||||
| #include "core/tag.h" | ||||
| #include "qt-models/weightsysteminfomodel.h" | ||||
| #include "qt-models/tankinfomodel.h" | ||||
| #ifdef SUBSURFACE_MOBILE | ||||
| #include "qt-models/divelocationmodel.h" | ||||
| #endif | ||||
|  | @ -917,6 +918,7 @@ bool EditWeightBase::workToBeDone() | |||
| 	return !dives.empty(); | ||||
| } | ||||
| 
 | ||||
| // ***** Remove Weight *****
 | ||||
| RemoveWeight::RemoveWeight(int index, bool currentDiveOnly) : | ||||
| 	EditWeightBase(index, currentDiveOnly) | ||||
| { | ||||
|  | @ -943,6 +945,7 @@ void RemoveWeight::redo() | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ***** Edit Weight *****
 | ||||
| EditWeight::EditWeight(int index, weightsystem_t wsIn, bool currentDiveOnly) : | ||||
| 	EditWeightBase(index, currentDiveOnly), | ||||
| 	new_ws(empty_weightsystem) | ||||
|  | @ -999,6 +1002,183 @@ void EditWeight::undo() | |||
| 	redo(); | ||||
| } | ||||
| 
 | ||||
| // ***** Add Cylinder *****
 | ||||
| AddCylinder::AddCylinder(bool currentDiveOnly) : | ||||
| 	EditDivesBase(currentDiveOnly), | ||||
| 	cyl(empty_cylinder) | ||||
| { | ||||
| 	if (dives.empty()) | ||||
| 		return; | ||||
| 	else if (dives.size() == 1) | ||||
| 		setText(tr("Add cylinder")); | ||||
| 	else | ||||
| 		setText(tr("Add cylinder (%n dive(s))", "", dives.size())); | ||||
| 	cyl = create_new_cylinder(dives[0]); | ||||
| } | ||||
| 
 | ||||
| AddCylinder::~AddCylinder() | ||||
| { | ||||
| 	free_cylinder(cyl); | ||||
| } | ||||
| 
 | ||||
| bool AddCylinder::workToBeDone() | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void AddCylinder::undo() | ||||
| { | ||||
| 	for (dive *d: dives) { | ||||
| 		if (d->cylinders.nr <= 0) | ||||
| 			continue; | ||||
| 		remove_cylinder(d, d->cylinders.nr - 1); | ||||
| 		emit diveListNotifier.cylinderRemoved(d, d->cylinders.nr); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void AddCylinder::redo() | ||||
| { | ||||
| 	for (dive *d: dives) { | ||||
| 		add_cloned_cylinder(&d->cylinders, cyl); | ||||
| 		emit diveListNotifier.cylinderAdded(d, d->cylinders.nr - 1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int find_cylinder_index(const struct dive *d, const cylinder_t &cyl) | ||||
| { | ||||
| 	for (int idx = 0; idx < d->cylinders.nr; ++idx) { | ||||
| 		if (same_cylinder(d->cylinders.cylinders[idx], cyl)) | ||||
| 			return idx; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly) : | ||||
| 	EditDivesBase(currentDiveOnly), | ||||
| 	cyl(empty_cylinder) | ||||
| { | ||||
| 	// Get the old cylinder, bail if index is invalid
 | ||||
| 	if (!current || index < 0 || index >= current->cylinders.nr) { | ||||
| 		dives.clear(); | ||||
| 		return; | ||||
| 	} | ||||
| 	cyl = clone_cylinder(current->cylinders.cylinders[index]); | ||||
| 
 | ||||
| 	std::vector<dive *> divesNew; | ||||
| 	divesNew.reserve(dives.size()); | ||||
| 	indexes.reserve(dives.size()); | ||||
| 
 | ||||
| 	for (dive *d: dives) { | ||||
| 		if (d == current) { | ||||
| 			divesNew.push_back(d); | ||||
| 			indexes.push_back(index); | ||||
| 			continue; | ||||
| 		} | ||||
| 		int idx = find_cylinder_index(d, cyl); | ||||
| 		if (idx >= 0) { | ||||
| 			divesNew.push_back(d); | ||||
| 			indexes.push_back(idx); | ||||
| 		} | ||||
| 	} | ||||
| 	dives = std::move(divesNew); | ||||
| } | ||||
| 
 | ||||
| EditCylinderBase::~EditCylinderBase() | ||||
| { | ||||
| 	free_cylinder(cyl); | ||||
| } | ||||
| 
 | ||||
| bool EditCylinderBase::workToBeDone() | ||||
| { | ||||
| 	return !dives.empty(); | ||||
| } | ||||
| 
 | ||||
| // ***** Remove Cylinder *****
 | ||||
| RemoveCylinder::RemoveCylinder(int index, bool currentDiveOnly) : | ||||
| 	EditCylinderBase(index, currentDiveOnly) | ||||
| { | ||||
| 	if (dives.size() == 1) | ||||
| 		setText(tr("Remove cylinder")); | ||||
| 	else | ||||
| 		setText(tr("Remove cylinder (%n dive(s))", "", dives.size())); | ||||
| } | ||||
| 
 | ||||
| void RemoveCylinder::undo() | ||||
| { | ||||
| 	for (size_t i = 0; i < dives.size(); ++i) { | ||||
| 		add_to_cylinder_table(&dives[i]->cylinders, indexes[i], clone_cylinder(cyl)); | ||||
| 		emit diveListNotifier.cylinderAdded(dives[i], indexes[i]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void RemoveCylinder::redo() | ||||
| { | ||||
| 	for (size_t i = 0; i < dives.size(); ++i) { | ||||
| 		remove_cylinder(dives[i], indexes[i]); | ||||
| 		emit diveListNotifier.cylinderRemoved(dives[i], indexes[i]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ***** Edit Cylinder *****
 | ||||
| EditCylinder::EditCylinder(int index, cylinder_t cylIn, bool currentDiveOnly) : | ||||
| 	EditCylinderBase(index, currentDiveOnly), | ||||
| 	new_cyl(empty_cylinder) | ||||
| { | ||||
| 	if (dives.empty()) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (dives.size() == 1) | ||||
| 		setText(tr("Edit cylinder")); | ||||
| 	else | ||||
| 		setText(tr("Edit cylinder (%n dive(s))", "", dives.size())); | ||||
| 
 | ||||
| 	// Try to untranslate the cylinder type
 | ||||
| 	new_cyl = clone_cylinder(cylIn); | ||||
| 	QString vString(new_cyl.type.description); | ||||
| 	for (int i = 0; i < MAX_TANK_INFO && tank_info[i].name; ++i) { | ||||
| 		if (gettextFromC::tr(tank_info[i].name) == vString) { | ||||
| 			free_cylinder(new_cyl); | ||||
| 			new_cyl.type.description = copy_string(tank_info[i].name); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If that doesn't change anything, do nothing
 | ||||
| 	if (same_cylinder(cyl, new_cyl)) { | ||||
| 		dives.clear(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	TankInfoModel *tim = TankInfoModel::instance(); | ||||
| 	QModelIndexList matches = tim->match(tim->index(0, 0), Qt::DisplayRole, gettextFromC::tr(new_cyl.type.description)); | ||||
| 	if (!matches.isEmpty()) { | ||||
| 		if (new_cyl.type.size.mliter != cyl.type.size.mliter) | ||||
| 			tim->setData(tim->index(matches.first().row(), TankInfoModel::ML), new_cyl.type.size.mliter); | ||||
| 		if (new_cyl.type.workingpressure.mbar != cyl.type.workingpressure.mbar) | ||||
| 			tim->setData(tim->index(matches.first().row(), TankInfoModel::BAR), new_cyl.type.workingpressure.mbar / 1000.0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| EditCylinder::~EditCylinder() | ||||
| { | ||||
| 	free_cylinder(new_cyl); | ||||
| } | ||||
| 
 | ||||
| void EditCylinder::redo() | ||||
| { | ||||
| 	for (size_t i = 0; i < dives.size(); ++i) { | ||||
| 		set_cylinder(dives[i], indexes[i], new_cyl); | ||||
| 		emit diveListNotifier.cylinderEdited(dives[i], indexes[i]); | ||||
| 	} | ||||
| 	std::swap(cyl, new_cyl); | ||||
| } | ||||
| 
 | ||||
| // Undo and redo do the same as just the stored value is exchanged
 | ||||
| void EditCylinder::undo() | ||||
| { | ||||
| 	redo(); | ||||
| } | ||||
| 
 | ||||
| #ifdef SUBSURFACE_MOBILE | ||||
| 
 | ||||
| EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_site *editDs, location_t dsLocationIn) | ||||
|  |  | |||
|  | @ -377,6 +377,45 @@ private: | |||
| 	void redo() override; | ||||
| }; | ||||
| 
 | ||||
| class AddCylinder : public EditDivesBase { | ||||
| public: | ||||
| 	AddCylinder(bool currentDiveOnly); | ||||
| 	~AddCylinder(); | ||||
| private: | ||||
| 	cylinder_t cyl; | ||||
| 	void undo() override; | ||||
| 	void redo() override; | ||||
| 	bool workToBeDone() override; | ||||
| }; | ||||
| 
 | ||||
| class EditCylinderBase : public EditDivesBase { | ||||
| protected: | ||||
| 	EditCylinderBase(int index, bool currentDiveOnly); | ||||
| 	~EditCylinderBase(); | ||||
| 
 | ||||
| 	cylinder_t cyl; | ||||
| 	std::vector<int> indexes; // An index for each dive in the dives vector.
 | ||||
| 	bool workToBeDone() override; | ||||
| }; | ||||
| 
 | ||||
| class RemoveCylinder : public EditCylinderBase { | ||||
| public: | ||||
| 	RemoveCylinder(int index, bool currentDiveOnly); | ||||
| private: | ||||
| 	void undo() override; | ||||
| 	void redo() override; | ||||
| }; | ||||
| 
 | ||||
| class EditCylinder : public EditCylinderBase { | ||||
| public: | ||||
| 	EditCylinder(int index, cylinder_t cyl, bool currentDiveOnly); // Clones cylinder
 | ||||
| 	~EditCylinder(); | ||||
| private: | ||||
| 	cylinder_t new_cyl; | ||||
| 	void undo() override; | ||||
| 	void redo() override; | ||||
| }; | ||||
| 
 | ||||
| #ifdef SUBSURFACE_MOBILE | ||||
| // Edit a full dive. This is used on mobile where we don't have per-field granularity.
 | ||||
| // It may add or edit a dive site.
 | ||||
|  | @ -406,5 +445,4 @@ private: | |||
| #endif // SUBSURFACE_MOBILE
 | ||||
| 
 | ||||
| } // namespace Command
 | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -87,6 +87,9 @@ signals: | |||
| 	void divesTimeChanged(timestamp_t delta, const QVector<dive *> &dives); | ||||
| 
 | ||||
| 	void cylindersReset(const QVector<dive *> &dives); | ||||
| 	void cylinderAdded(dive *d, int pos); | ||||
| 	void cylinderRemoved(dive *d, int pos); | ||||
| 	void cylinderEdited(dive *d, int pos); | ||||
| 	void weightsystemsReset(const QVector<dive *> &dives); | ||||
| 	void weightAdded(dive *d, int pos); | ||||
| 	void weightRemoved(dive *d, int pos); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue