begin process at 2012 05 27 19:30:49
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Divers

 > SYSTÈME D'ANNULER-REFAIRE PAR ARBRE (TURS)

SYSTÈME D'ANNULER-REFAIRE PAR ARBRE (TURS)


 Information sur la source

Note :
Aucune note
Catégorie :Divers Classé sous :Annuler, Refaire, Arbre, Tree, TURS Niveau :Initié Date de création :23/06/2011 Date de mise à jour :07/07/2011 14:55:53 Vu / téléchargé :1 761 / 73

Auteur : macsou01

Ecrire un message privé
Site perso
Commentaire sur cette source (7)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
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

  • #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;
  • }
#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.

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

23 juin 2011 20:08:52 :
Prise en considération de quelques recommandations faites dans les commentaires.
23 juin 2011 20:17:30 :
Modification du type pour TURSNode::childIndex (unsigned int en int car il renvoie parfois -1 si l'enfant cherché n'existe pas).
24 juin 2011 11:24:33 :
- Renommage des fichiers pour utiliser le modèle .hh/.hpp - Modification du Makefile - Modification de l'exemple - Modification de la documentation
24 juin 2011 11:42:52 :
Mise en place d'un dépôt Mercurial.
01 juillet 2011 23:03:14 :
Passage en version 0.2 : - Ajout d'un exemple GUI - Quelques modifs dans le code
02 juillet 2011 14:15:32 :
Amélioration de l'exemple GUI et quelques modifications dans le code du TURS. Modification du screenshot.
03 juillet 2011 13:33:07 :
Modif screenshot
07 juillet 2011 14:55:53 :
Ajout d'un zip, du code du main directement sur la page et mise à jour du lien vers le dépôt.

 Sources du même auteur

Source avec Zip Source avec une capture COURBE DE BÉZIER
Source avec Zip Source avec une capture ÉVALUATEUR D'EXPRESSIONS BOOLÉENNES (BEE)

 Sources de la même categorie

Source avec Zip KISIEL CD INFO DRIVE par kisiel0147852
Source avec une capture SUPPRESSION DES REDONDANCES DE FICHIERS par cyberntique
Source avec Zip ÉDITEUR DE RECTANGLES EN CONSOLE par seoseo
CONVERSION DE FICHIER EN FICHIER BMP par seoseo
Source avec Zip DETECTEUR EJP par idpro

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture ARBRE AABB par JeanMilost
Source avec Zip TREEREG (GESTION DU REGISTRE COMME UN ARBRE) par kts_system
ARBRE BINAIRE (NON-EQUILIBRE) par JCDjcd
Source avec Zip Source avec une capture ARBRE23 par Vyse
Source avec Zip Source avec une capture UN RAYTRACER EN C++ AVEC ARBRE CSG POUR LINUX (PORTABLE WIN... par gwoin

Commentaires et avis

Commentaire de CptPingu le 23/06/2011 18:30:43 administrateur CS

C'est un code très intéressant et propre. C'est assez rare !
(Pas de using namespace, pas de mélange C et C++, utilisation de la STL, des templates, documentation, etc... Ça fait plaisir !).
C'est sympa aussi d'avoir une documentation. C'est encore plus sympa de l'avoir fait en Doxygen !

Au sujet du comportement du programme, il n'y a rien à redire, c'est pratique et aisément utilisable en tant que bibliothèque.

Y a des petits trucs qui me gênent un peu, mais ce n'est pas très grave:
- Inclusion de .cpp dans un .hpp. Pour séparer un code de sa définition, je conseille généralement le couple: .cc/.hh/.hxx ou .cpp/.hh/.hpp
- std::string TURSNode<T>::toString => Plutôt qu'un "std::string ret;" j'utiliserais un std::ostringstream (concaténation plus rapide qu'avec un std::string) avec un "return ret.str()".
- Dans les constructeurs, j'utiliserais la liste d'initialisation plutôt que d'affecter les valeurs dans le corps du constructeurs. Ça te permettrait d'avoir des attributs constants.
- Au lieu de addAction(T val), je mettrais plutôt: addAction(const T& val), sinon bonjour les copies en cas de gros objet ! C'est valable pour les autres aussi.
- J'éviterais les NULL au profit de 0, voir: http://0217021.free.fr/portfolio/axel.berardino/articles/null-en-cpp

Au niveau du binaire de démonstration:
- Le makefile est un faux makefile :p. Il ne tient pas compte de ce qui est déjà compilé.
- Tu compiles les *.cpp alors qu'ils sont inclus par les .hpp. Donc théoriquement, ta ligne de compil devrait être: "g++ main.cpp -o CLI"
- Tu ne mets pas de flags de sécurité: "g++ -W -Wall -Wabi -g main.cpp", tu verrais pas mal de warnings ! (Tu compares souvent des entiers signés avec des entiers non signés).
- En release un -o3 serait pas mal non plus :)
- D'après valgrind, tu as des fuites mémoires dans TURS.cpp, ligne 20 et ligne 43. Je t'invite à repasser du valgrind sur ton code.
- Au lieu de faire "char line[]", tu peux mettre un "std::string line", et faire un "while (std::getline(std::cin, line)"
- Ton binaire devrait facultativement prendre en argument un fichier. Pratique pour débugger des fuites mémoires, par exemple :p

J'ai sûrement oublié des choses. Je les ajouterais peut être plus tard.

Commentaire de macsou01 le 23/06/2011 18:49:31

Merci pour toutes ces remarques intéressantes !

En effet par exemple pour la makefile j'avais bien remarqué que ça compilait même sans avoir modifié les fichiers, mais je ne savais pas d'où venait le problème.

Je vais essayer modifier ça rapidement.

Encore merci :)

Commentaire de CptPingu le 23/06/2011 19:00:15 administrateur CS

Pour le makefile, regarde dans mes sources. Tu trouveras un exemple de makefile + configure complet (avec gestion des dépendance via g++ -MM). C'est peut être un peu "overkill" pour ce que tu veux faire, mais ça peut toujours t'intéresser :p

Commentaire de macsou01 le 23/06/2011 20:12:37

J'ai modifié un peu mon code selon tes conseils. Cependant, il me reste les points suivants à effectuer :
- Gérer les sources suivant le modèle .cpp/.hh/.hpp (je n'ai pas bien compris comment faire et sur internet il n'y a pas beaucoup d'exemples clairs)
- Modifier le makefile de l'exemple pour qu'il ne compile pas à chaque fois (idem, j'ai regardé ton makefile (pour le compilateur Pascal) mais comme c'est pour un gros projet, il est un peu complexe, il faudra que j'y regarde de plus près)
- Vérifier les fuites mémoires (je verrai ça plus tard)

Commentaire de CptPingu le 23/06/2011 23:32:47 administrateur CS

> - Gérer les sources suivant le modèle .cpp/.hh/.hpp (je n'ai pas bien compris comment faire et sur internet il n'y a pas beaucoup d'exemples clairs)

C'est pas dur:
- Dans le .hh tu mets la définition de la classe.
- Dans le .cpp le code
- Dans le .hpp (qui est inclus à la fin du .hh) tu mets le code inliné ou templaté.
En fait, c'est juste un souci de nomination que tu as, pas de principe.

> Modifier le makefile de l'exemple pour qu'il ne compile pas à chaque fois (idem, j'ai regardé ton makefile (pour le compilateur Pascal) mais comme c'est pour un gros projet, il est un peu complexe, il faudra que j'y regarde de plus près)
Attention, par convention, "Makefile" prend une majuscule.
Soit tu mets -O3 (avec une majuscule à O) qui veut dire optim maximale, soit tu mets -g (qui veut dire, pas d'optim, ajouter des informations de debug). Les deux ne sont pas compatibles (et sont carrément à l'opposé).

Un Makefile tout mini, adapté à ton projet:

# Liste des fichier cpp, ne jamais mettre *.cpp
SRC=main.cpp
# Liste des headers, ils devraient être en .hpp et .hxx
HEADER= ../../../TURS/src/TURS.cpp \
../../../TURS/src/TURS.hpp \
../../../TURS/src/TURSNode.cpp \
../../../TURS/src/TURSNode.hpp
BINDIR=.
ifdef SystemRoot
BINNAME=CLI.exe
else
BINNAME=CLI
endif

TARGET=$(BINDIR)/$(BINNAME)
OBJ=$(SRC:.cpp=.o)
CPP=g++
CXXFLAGS=-W -Wall -Wabi -O3

all: $(TARGET)

$(TARGET): $(OBJ) $(HEADER)
$(CPP) $(CXXFLAGS) $(OBJ) -o $(TARGET)

%.o: %.cpp
$(CPP) -o $@ -c $< $(CFLAGS)
clean:
rm -rf *.o

distclean: clean
rm -rf $(TARGET)

Commentaire de CptPingu le 24/06/2011 00:00:18 administrateur CS

Je te propose aussi une version de ton application principale, qui prend l'entrée standard ou un fichier:

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

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

int main(int argc, char** argv)
{
  typedef std::vector<std::string>::const_iterator iter;
  typedef TURS<std::string> TURS_str;
  TURS_str turs;
  std::string line;
  std::vector<std::string> args;
  int i = 1;

  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))
  {
    std::istringstream iss(line);

    std::string cmd;
    iss >> cmd;

    while (iss)
    {
      std::string arg;
      iss >> arg;
      args.push_back(arg);
    }

    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;
}

Commentaire de macsou01 le 24/06/2011 10:32:01

Merci pour ces explications et ces bouts de codes ;).
Je vais mettre en place tout ça bientôt.

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Bouton Annuler ou refaire [ par gagah1 ] Salut à tous.J'ai vu dans tous les logiciels un bouton ANNULER et un bouton REFAIRE (càd annuler ou répéter la dernière action). Est-ce que dans API W r-tree(arbre region) [ par bouchra22 ] bonjour,svp aidez moi le plus tot possible;j'ai un exposé en c++ concernant R-tree,et j'ai besoin d'une implementation faite en c++;merci d'avance creation récursive de l'arbre de codage de la compression Huffman [ par kuja2053 ] Bonjour, Voila mon probleme : ayant un projet sur la compression de Huffman, j'ai décider de changer le format de l entete de mon fichier suite à un c Construction d'un arbre à partir d'un fichier [ par psgkiki ] Bonjour a tous, Ma question est comment construire un arbre contenant des données stockées dans un fichier. C'est pour un logiciel de devinette d'anim Théorie des graphes : algo de Kruskal [ par thespartan ] Bonjour j'ai implémenté l'agorithme de kruskal qui sert à la recherche d'arbre recouvrant de poids minimal (arpm) dans un graphe pondéré seulement voi Affichage d'un arbre dynamique(en C) [ par marocweb ] bonjour tout le monde,j'ai un arbre déja crée en mémoire en utilisant les listes chainées et cela comme suit :Chaque noeud point vers une liste chainé décrire XML sous forme de graphe [ par convexe ] Bonjour, Je suis débutant en base de données et j'aurais besoin d'une classe C++ qui permetrait de décrire les fichiers xml sous la forme de graphe , algorithme [ par itomie ] salut je voudrai savoir comment transformer un fichier texte a un arbre binaire , j'ai une idée c'est de mettre tout les valeur du fichier dans un tab abr [ par achrafkhalifa ] salut, quelqu'un me donne une fonction en language c de prototype void creer_arbre(struct **R , int x) qui permet de creer un arbre binaire de recherc


Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,889 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales