Système d'annuler-refaire par arbre (turs)

Description

TURS (Tree Undo Redo System) permet de gérer les annuler-refaire (ou précédent-suivant) sans perte de données avec l'utilisation d'un arbre.

Imaginons un sysème classique de précédent-suivant dans un navigateur web. Nous avons visité les sites webs suivants et nous sommes sur le dernier :

Site 1
Site 2
Site 3
Site 4 <-

On revient en arrière deux fois :

Site 1
Site 2 <-
Site 3
Site 4

Si l'on va sur un nouveau site 5, on va perdre les sites 3 et 4 :

Site 1
Site 2
Site 5 <-

Cependant, avec TURS, on utilise un arbre pour créer des branches (symbolisées par des points).

Site 1
Site 2
.
Site 3
Site 4
.
Site 5 <-

Ainsi les sites 3 et 4 sont conservés et depuis le site 2, il est possible d'accéder soit au site 5, soit aux sites 3 et 4.

Cette source peut aussi permettre, dans une certaine mesure, de s'initier aux templates en C++ ainsi qu'aux arbres (j'ai appris à les utiliser en programmant cette source).

Les fonctionnalités sont assez limitées (voir l'exemple fourni), mais il est possible d'adapter le code en modifiant directement les sources ou en héritant de la classe TURS.

Le code est commenté et documenté (la documentation est déjà générée et le fichier Doxyfile est fourni).

Attention, le zip et le code fournis sur cette page ne sont pas forcément à jour ! Pour voir les dernières sources, rendez-vous ici : https://bitbucket.org/mcc/dev/src/tip/TURS/

Source / Exemple :


#include "../../src/TURS.hh"
#include <cstdlib>
#include <vector>
#include <fstream>

void error(unsigned int line, const std::string& message) {
	std::cerr << "Ligne " << line << " : " << message << std::endl;
}

//Dans cet exemple, on lit l'entrée standard ou un fichier passé en paramètre
//afin d'exécuter des commandes pour manipuler le TURS.
int main(int argc, char** argv) {
	typedef std::vector<std::string>::const_iterator iter;
	typedef TURS<std::string> TURS_str;
	
	//Création d'un TURS de string.
	TURS_str turs;

	std::string line;
	std::vector<std::string> args;
	unsigned int i = 1;

	//On sélectionne le fichier passé en paramètre ou l'entrée standard.
	std::ifstream file;
	if(argc > 1) {
		file.open(argv[1]);
		if(!file) {
			std::cerr << "Le fichier n'existe pas : " << argv[1] << std::endl;
			return 1;
		}
	}
	std::istream& in = (argc > 1) ? file : std::cin;

	while(std::getline(in, line)) {
		//On récupère la commande.
		std::istringstream iss(line);
		std::string cmd;
		iss >> cmd;

		//On récupère les arguments.
		while(iss) {
			std::string arg;
			iss >> arg;
			args.push_back(arg);
		}

		//On exécute la commande.
		if(cmd == "action")  {
			if(args.size() > 0) {
				turs.addAction(args[0]);
			} else {
				error(i, "Argument manquant pour la commande 'action'");
			}
		} else if(cmd == "undo") {
			turs.undo();
		} else if(cmd == "redo") {
			if(args.size() > 0) {
				turs.redo(atoi(args[0].c_str()));
			} else {
				turs.redo();
			}
		} else if(cmd == "print") {
			if(args.size() > 0)  {
				for(iter it = args.begin(); it != args.end(); ++it) {
					if(*it == "$tree") {
						std::cout << turs << " ";
					} else if(*it == "$currentVal") {
						std::cout << turs.currentVal() << " ";
					} else if(*it == "$nl") {
						std::cout << std::endl;
					} else {
						std::cout << *it << " ";
					}
				}
				std::cout << std::endl;
			}
		} else if(cmd == "clear") {
			turs.clear();
		} else if(cmd == "mode") {
			if(args.size() > 0) {
				if(args[0] == "tree") {
					turs.setMode(TURS_str::TREE_MODE);
				} else if(args[0] == "normal") {
					turs.setMode(TURS_str::NORMAL_MODE);
				} else {
					error(i, "Argument invalide pour la commande 'mode'");
				}
			} else {
				error(i, "Argument manquant pour la commande 'mode'");
			}
		} else if(cmd == "quit") {
			break;
		}
		
		args.clear();
		i++;
	}

	return 0;
}

Conclusion :


J'espère que cette source pourra être utile !

Il existe peut-être des bugs, si c'est le cas, merci de me les indiquer.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.