Bloquer en Cocoa pour lecteur mp3

Résolu/Fermé
Ninja_En_Short Messages postés 133 Date d'inscription mercredi 19 septembre 2007 Statut Membre Dernière intervention 27 juin 2014 - 21 janv. 2008 à 12:54
 ahahAHAHah - 12 févr. 2008 à 18:31
Bonjour,

J'écris car j'ai un tp à rendre cette semaine mais je suis une quiche en Cocoa (je commence à croire à l'incompatibilité génétique) et j'ai donc grand besoin d'aide.

Pour faire simple j'ai un interface (faite avec interface builder), quatres boutons (play, stop, + et -) et un tableau (qui stocke le nom des musiques dans un dossier). Le lecteur est mpg123 (libre). La prog se fait avec XCode

Je vous met ici mon .h et l'énoncé en espérant que quelqu'un puisse m'aider.

Enoncé (long il est vrai) :


1. Préambule

Ce cahier de TP est organisé en une progression tout au long du cursus Cocoa. Il est divisé en
plusieurs parties, ces dernières suivant le découpage du cours.

Toute cette progression est structurée autour d’un projet, allant de la prise en main des outils de
développement à la conception et au développement de l’application.

L’objectif de ce TP est la réalisation d’un lecteur mp3 :


2. Pré-requis
2.1 Installation d’Xcode

Une fois votre machine correctement installée et configurée il vous faudra installer les outils de
développement.
Vous pourrez trouver ces outils sur le cd 1 d’installation de Mac OS X ou sur le site Internet d’Apple à
l’adresse suivante : http://developer.apple.com/tools/
2.2 Compilation de mpg123

Pour notre projet nous allons utiliser un lecteur mp3 gratuit en ligne de commande qui vient du monde
UNIX.
Le projet est nommé mpg123 et il vous faudra télécharger les sources puis les compiler sur la machine.

Vous trouverez les sources à l’adresse suivante : https://sourceforge.net/projects/mpg123/

Configurez, compilez et installez le projet sur votre système.

Note : Vous pourrez dès maintenant écouter des musiques via le Terminal en lançant la
commande mpg123 maMusique.mp3.
Pour avoir plus de détails sur les options disponibles faites : mpg123 --help


2.3 Xcode : nouveau projet

Maintenant que nous avons correctement installé et configuré notre espace de travail nous allons créer
un nouveau projet Xcode.

Lancez Xcode qui se trouve dans le répertoire /Developer/Applications/

Créez ensuite un nouveau projet pour développer une application Cocoa.

2.4 Ajout de mpg123 à notre projet

Plus tard si vous êtes amené à partager votre application avec une autre personne, il faudra que celle-ci
installe le projet mpg123 comme vous l’avez fait précédemment. Vous l’aurez compris ce n’est pas du
tout pratique.

Pour pouvoir faire fonctionner notre logiciel sur n’importe quelle machine sans avoir besoin de faire
d’autres manipulations que celle de l’installer, il faut que le projet mpg123 fasse partie des ressources
du projet Xcode.

Ajoutez l’exécutable mpg123 aux ressources de votre projet.

Note : Vous pouvez choisir l’option qui vous permet de copier le fichier choisi dans le répertoire
de destination afin de l’avoir en permanence avec votre projet même si vous supprimez le fichier
de votre système.


3. Création de l’interface
graphique
3.1 Lancement d’ Interface Builder

Une fois notre projet Xcode correctement configuré nous allons commencer à travailler sur celui-ci.

Nous allons dans un premier temps nous consacrer à l’interface graphique avec Interface Builder, puis
nous reviendrons plus tard dans Xcode pour développer notre application.

Lancez Interface Builder depuis Xcode pour commencer à éditer l’interface graphique de votre
application.

3.2 Renommer le titre de la fenêtre

Nous allons commencer par renommer notre fenêtre.

La majeure partie des modifications que nous apporterons à notre interface se fera via l’Inspecteur qui
se trouve dans le menu Tools -> Show Inspector.

Une fois l’Inspecteur lancé, renommez votre fenêtre par « My Player ».

3.3 Ajout des contrôleurs

Nous allons maintenant agrémenter notre interface avec les différents contrôleurs dont on aura besoin
lors de l’utilisation de notre lecteur mp3.

Ajoutez une liste qui listera les musiques qui devront êtres lues par notre lecteur.
La liste devra avoir une seule colonne et les lignes devront être d’une couleur différente une ligne sur
deux.

Ajoutez ensuite les boutons « Play » et « Pause » pour jouer et mettre en pause la musique.

Un lecteur mp3 sans musique n’est pas un lecteur mp3. Nous allons donc rajouter un bouton « + »
pour ajouter une musique à notre liste et un bouton « – » pour en retirer.


4. Interface du contrôleur
4.1 Définition d’une classe contrôleur

Maintenant que nous avons disposé tous les contrôles qui seront nécessaires à une utilisation
simplifiée, nous allons créer une classe qui va contrôler nos boutons et notre liste.

Créez la classe contrôleur depuis Interface Builder en sous classant la classe NSObject et nommez là
« PlayController ».

4.2 Outlets / Actions

La classe contrôleur va nous permettre à la fois d’écouter les actions d’un utilisateur comme par
exemple le clic sur un bouton et d’effectuer des actions comme lancer la lecture d’une musique.

Pour chaque contrôleur rajoutez un Outlet à la classe PlayController. De la même façon rajoutez une
Action au contrôleur pour chaque action qu’il sera possible de faire avec le lecteur (lire, mettre en
pause...).
Vous donnerez aux Outlets les noms suivant : addButton, listTableView, playButton, pauseButton,
removeButton. Les noms associés aux Actions seront : addTrack, playPause et removeTrack.

Note : Vous pouvez spécifier le type de l’Outlet : NSButton, NSTableView etc. La lecture du
code n’en sera qu’améliorée par la suite.

4.3 Instanciation de la classe contrôleur

Maintenant que notre classe contrôleur est créée et que nos Outlets et Actions sont déclarées, il faut
instancier la classe.

Maintenant que la classe contrôleur PlayController est terminée nous allons créer un objet de type
PlayControlle. Cet objet possèdera comme n’importe quel autre objet (ex : NSObject, NSString etc.)
des méthodes qui seront déclanchées par l’envoie de messages. On dit qu’on instancie la classe
PlayController.

Instanciez la classe PlayController depuis Interface Builder. Une fois la classe instanciée vous devriez
voir apparaître un cube bleu dans l’onglet Instances de la fenêtre MainMenu.nib.


4.4 Connexion des Outlets / Actions

Nous remarquons un point d’exclamation en bas à gauche du cube qui nous alerte sur le fait qu’il
manque des relations entre les objets.



Il va falloir par exemple faire pointer la variable d’instance addButton (nommé aussi Outlet) de la
classe PlayController sur l’objet NSButton de la fenêtre (le bouton que vous aurez nommé Add dans
l’interface de votre player).

Pour relier les objets entre eux il faut utiliser la touche ctrl puis sélectionner un objet et faire glisser le
lien entre sur le contrôleur. Faites de même dans l’autre sens pour relier les Outlets aux objets de
l’interface.

Note : Faites bien attention du sens dans lequel vous reliez vos objets.

Reliez de cette façon tous les boutons aux Actions de notre contrôleur et les Outlets de notre
contrôleur à nos objets (NSButton, NSTextField etc.).

Note : Si tous vos objets sont correctement reliés aux différents Outlets et Actions vous devriez
avoir un cube bleu sans point d’exclamation dans l’onglet « Instances » de la fenêtre
« MainMenu.nib »


4.5 Définition du DataSource

Nous avons la NSTableView servant à lister nos musiques, il va falloir y définir une source de
données : un datasource.

Le datasource est une variable d’instance de l’objet graphique (aussi appelé Outlet). Cette variable
devra pointer vers un objet qui devra respecter un protocole informel. Nous reviendrons sur le
protocole dans le chapitre 6.
Si on revient à notre lecteur, nous avons un objet graphique : la NSTableview qui possède l’Outlet
datasource et notre contrôleur PlayController qui sera notre objet qui implémentera les méthodes
définis par le protocole.

Notre PlayController sera charger de "contrôler" les données qui seront affichées dans la
NSTableView. Il faudra pour cela relier l’Outlet dataSource de la NSTableView au PlayController.

Note : N’oubliez pas de sauvegarder de temps en temps !

4.6 Définition du Delegate

Comment faire pour gérer les évènements utilisateurs ? Par exemple si on double-clique sur une
musique, il serait intéressant de lancer cette dernière.

Le delegate est lui aussi un Outlet tout comme le dataSource qui va contrôler les objets et définir leurs
comportements. Tout comme le dataSource il faudra le relier à notre classe PlayController.
On pourra par la suite "réimplémenter" dans notre classe PlayController les méthodes dites déléguées
pour lesquelles on souhaite définir un comportement particulier.
Si on revient à la gestion du double-clique, il nous suffira de réécrire la méthode qui est appelée lors
d’un double-clique pour lui dire de lancer une musique au lieu de ne rien faire (l’action par défaut).

Étant donné que l’on souhaite que ce soit notre contrôleur qui gère lui-même les objets de notre
fenêtre (boutons, liste...), il faut que l’instance Window délègue ce travail au contrôleur.

Reliez l’Outlet delegate de l’instance Window à notre contrôleur PlayController afin que ce soit celui-
ci qui définisse le comportement de nos contrôles.

4.7 Génération du code source

Nous en avons bientôt terminé avec Interface Builder. Maintenant que tous nos objets sont placés et
les liaisons faites il ne nous reste plus qu’à générer le "code" de notre classe contrôleur pour pouvoir
ensuite implémenter celui-ci dans Xcode.

Une fois terminé vous pouvez enregistrer votre projet Interface Builder et quitter l’application.

Ensuite sous Xcode, placez les classes PlayController.h et PlayController.m dans le dossier Classes
pour avoir un projet ordonné.


5. Constructeur et destructeur
5.1 Rajout de certains objets

Pour avoir un meilleur contrôle des musiques qui seront listées nous allons rajouter un tableau à notre
contrôleur. Ce tableau contiendra les différentes musiques préalablement rajoutées à notre lecteur.

Nous nommerons ce tableau listArray et il sera de type NSMutableArray.

Le type NSMutableArray permettra la modification du tableau (ajout, suppression, édition d’une
musique) contrairement à un tableau de type NSArray qui est immuable.

Nous parlions dans la première partie du TP du projet mpg123. Nous avions rajouté ce projet à nos
ressources, mais nous ne l’avions pas encore utilisé.
Pour utiliser des commandes telles que mpg123 nous utilisons des variables de type NSTask.

Il vous faut donc définir une variable d’instance de ce type que l’on nommera arbitrairement
the123Task de type NSTask dans notre contrôleur.

5.2 La méthode init

La génération de code automatique d’Interface Builder ne nous permet pas de définir une méthode
init, qui nous le rappelons permet d’initialiser notre classe et plus particulièrement les instances de
cette classe.
Précédemment nous avons rajouté 2 variables (listArray et the123Task). Il peut être intéressant
d’initialiser ces variables à la création de l’objet. Par exemple nous pourrions commencer à remplir le
tableau avec les chemins menant aux musiques.

Déclarez la méthode init dans l’interface PlayController.

Implémentez là ensuite en initialisant la variable the123Task à nil et en remplissant le tableau avec
quelques chemins menant aux musiques.

5.3 La méthode dealloc

Comme la méthode init, une méthode dealloc doit être définie pour gérer nos variables à la
destruction de l’objet.

Déclarez la méthode dealloc et implémentez là en vaillant à ne pas avoir de problème mémoire à la
sortie, c’est-à-dire en libérant tous les objets dont vous êtes propriétaire.


6. Gestion du dataSource
6.1 Respect du protocole – Partie 1

Dans la partie 4.5 nous avions défini notre contrôleur PlayController comme dataSource de notre
NSTableView.
Cette définition nous impose le respect du protocole NSTableDataSource où sont déclarées les
méthodes qui permettent à une instance de NSTableView d’accéder au contenu de son dataSource.

La première méthode à déclarer puis implémenter sera numberOfRowsInTableView.
Cette méthode permettra à l’objet dataSource de renvoyer le nombre de lignes qui composent la table.
C’est à dire le nombre de musiques contenu dans notre tableau listArray.

La méthode numberOfRowsInTableView:
(int)numberOfRowsInTableView:(NSTableView *)aTableView;

Déclarez et implémentez cette dernière.

6.2 Respect du protocole – Partie 2

Comme pour la méthode précédente on va devoir déclarer et implémenter la méthode :
tableView :objectValueForTableColumn :row :.
Par cette méthode, notre dataSource (PlayController) renverra l’objet à afficher au niveau de la ligne
(rowIndex) et de la colonne (aTableColumn) spécifiées.
La source sera comme toujours notre tableau listArray.

La méthode tableView:objectValueForTableColumn:row:
-(id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;

Déclarez et implémentez cette dernière.


7. Gestion de la tâche mpg123
7.1 Lecture de la musique

Maintenant que nous pouvons récupérer les éléments de notre liste, à savoir les chemins vers les
musiques nous allons développer la méthode qui va lire notre musique.

Déclarez et implémentez la méthode start123With :(NSString *)track qui va lancer le processus
mpg123 et lire la musique passée en paramètre : track.

La méthode start123With:
(void)start123With:(NSString *)track;

7.2 Arrêt de la musique

Écouter de la musique est une bonne chose, mais il faut bien pouvoir l’arrêter à un moment donné.

Déclarez la méthode stop123: qui arrêtera le processus mpg123 et détruira l’objet the123Task.

La méthode stop123:
(void)stop123;

Implémentez ensuite la méthode stop123 qui devra arrêter le processus en cours puis détruire l’objet
the123Task.


7.3 Lecture ou suspension de la musique

Précédemment dans le chapitre 4 nous avons relié nos boutons à des Actions définies dans notre
contrôleur. L’action qui nous intéresse ici est l’action play à laquelle étaient reliés au bouton Play.

Pour commencer nous allons avoir besoin de 2 nouvelles variables pour contrôler notre lecture. La
première variable à déclarer est currentPath qui devra contenir le chemin vers la piste en cours de
lecture. L’autre variable sera isSuspended qui permettra de définir si la piste est en cours de lecture ou
en pause.

Les nouvelles variables
NSString *currentPath;
BOOL isSuspended;

Veillez ensuite à correctement initialiser ces variables dans la méthode init.

Voulez allez ensuite modifier la méthode start123With: afin d’enregistrer la piste en cours de lecture
dans la variable currentPath.

Afin d’avoir une interface claire d’utilisation et/ou éviter certains usages malintentionnés il vous
faudra désactiver le bouton pause au lancement de l’application après le chargement de l’interface.

La méthode awakeFromNib est une méthode qui est exécutée juste après le chargement complet de
l’interface graphique.

La méthode awakeFromNib
-(void)awakeFromNib
{
}

Elle permet donc d’initialiser les contrôleurs qui s’y trouvent comme les boutons par exemples.
Cette méthode n’a pas besoin d’être déclarée dans l’interface du contrôleur, vous avez juste à
l’implémenter dans le fichier .m si vous en avez besoin.

Note : Via Interface Builder vous avez peut-être déjà désactivé le bouton. Vous n’aurez donc rien
à écrire pour le moment dans la méthode awakeFromNib.

Déclarez ensuite la méthode play et pause dans l’interfae du contrôleur si elles n’y sont pas déjà.

Les méthodes play et pause
(IBAction)play:(id)sender;
(IBAction)pause:(id)sender;


Pour l’implémentation de la méthode, vous allez devoir suivre les règles ci-dessous :

- Vous devrez créer le processus et lancer la musique si le processus n’existe pas.
- Si la personne appuie sur le bouton pause la musique doit être suspendue.
- Si la personne relance une musique en pause la musique doit reprendre à l’endroit ou elle a été
suspendue.
- Si la personne choisie une autre musique après avoir mis en pause celle qu’il écoutait, cette
dernière devra être correctement arrêtée avant de lancer la nouvelle chanson.

8. Ajout et suppression de fichiers

Formidable nous avons enfin un lecteur fonctionnel. Seul défaut, on ne peut lire que les musiques qui
ont été codé avec notre lecteur.

Il va falloir maintenant développer nos 2 autres boutons : le bouton " + " et le bouton " – ".
8.1 Ajout d’une musique

Nous allons commencer avec le bouton " + ".
8.1.1 La méthode addTrack

Vous devriez retrouver dans le fichier de l’Interface de votre contrôleur la méthode addTrack déjà
déclarée. Si toute fois ce n’était pas le cas déclarez là.

La méthode addTrack
-(IBAction)addTrack:(id)sender;

À l’appel de cette méthode un NSOpenPanel devra apparaître vous permettant de naviguer à travers
votre arborescence en vous montrant uniquement les fichiers dont l’extension est .mp3. Vous pourrez
grâce à ce panel sélectionner une ou plusieurs musiques à ajouter à votre liste.
Vous utiliserez pour cela un objet de type NSOpenPanel et la méthode beginSheetForDirectory:
file: types: modalForWindowmodalDelegate: didEndSelector:: contextInfo:.

Exemple

// Tell a new object NSOpenPanel to present a sheet Open panel on
//the window

NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setAllowsMultipleSelection: NO];

// Define different options to configure them at this start

[openPanel beginSheetForDirectory: nil
file: nil
types:[NSArray arrayWithObject: @"txt"]
Cahier de Travaux Pratiques – Cursus Cocoa 16 / 19


modalForWindow:[NSApp mainWindow]
modalDelegate:self // To control objects selected in the open panel
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
contextInfo:nil];


Implémentez cette méthode en pensant à déléguer temporairement le panel à votre contrôleur pour
récupérer les chemins menant aux musiques dans votre tableau grâce au paramètre modalDelegate.

8.1.2 Implémentation des délégués

Comme nous l’expliquions juste avant nous devions déléguer temporairement notre panel à notre
contrôleur afin de récupérer les données sélectionnées.
Ceci se passait avec la méthode openPanelDidEnd: ReturnCode: contextInfo.

La méthode openPanelDidEnd:returnCode:contextInfo
-(void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode
contextInfo:(void *)contextInfo;

Commencez par déclarer cette méthode.

Passez ensuite à l’implémentation de la méthode openPanelDidEnd :returnCode :contextInfo qui
remplira la liste de lecture si la personne a appuyé sur le bouton OK avec la ou les musiques
préalablement sélectionnées.

8.2 Suppression d’une musique

Passons maintenant à notre bouton " – " qui s’il est appuyé provoque la suppression de la musique
sélectionnée de la liste de lecture.

Vous devrez déclarer comme pour la méthode addTrack la méthode removeTrack dans l’Interface
de votre contrôleur si elle ne l’ai pas déjà.

La méthode removeTrack:
-(IBAction)removeTrack:(id)sender;

Implémentez ensuite la méthode removeTrack qui devra retirer de la liste (notre tableau listArray) la
musique précédemment sélectionnée.


9. Gestion du problème de la
fermeture de la fenêtre
9.1 Fermeture de la fenêtre

Il nous reste encore un point à corriger : la gestion de la fermeture de la fenêtre. En effet vous aurez
peut-être pu constater que lorsque l’on fermait celle-ci, la musique continuait de jouer.
Ceci est dû au fait que la fermeture de la fenêtre n’arrête pas notre processus mpg123.

Vous aurez à déclarer la méthode windowWillClose qui sera appelée juste avant la fermeture de
l’objet NSWindow dans l’Interface de votre contrôleur.

La méthode windowWillClose
(void)windowWillClose:(NSNotification *)aNotification;

Implémentez ensuite cette dernière afin qu’elle arrête le processus mpg123 avant de terminer
l’application.


10. Bonus
10.1 Double-clique pour lancer une musique
Beaucoup de lecteur audio lance la lecture d’une musique lorsque l’on double-clique sur celle-ci.

À vous maintenant de rajouter cette option à votre lecteur.

10.2 Gestion du Drag & Drop

Une grande partie des applications Mac OS X comme le Finder, iTunes etc. utilisent le Drag & Drop.
Le Drag & Drop consiste à déplacer des éléments (musiques, fichiers, textes etc) entre les applications
à l’aide de la souris.

Vous allez devoir développer cette fonctionnalité dans votre lecteur afin de pouvoir changer l’ordre
des musiques dans la liste de lecture et ajouter des fichiers externes à votre application.

Afin de ne pas perturber le travail déjà fait, vous devrez utiliser les Catégories pour développer cette
nouvelle fonctionnalité.

10.2.1 Configuring your TableView

La première étape est la configuration de votre TableView. Il va falloir définir le type des données qui
seront reçues par notre tableView.

Vous utiliserez la méthode registerForDraggedTypes: pour enregistrer un nouveau type de données
supporté par votre tableView.

10.2.2 Beginning a drag operation

Lorsque vous prenez un objet (Drag) sur la tableView lors d’un Drag & Drop, la table envoie un
message tableView:writeRowsWithIndexes:toPasteboard: au data source.
L’implémentation de cette méthode consiste à placer les données sélectionnées dans le pastboard et de
retourner YES si tout c’est bien passé.

10.2.3 Validating a drag operation

Lorsque votre souris arrive avec le ou les éléments sélectionnés en cours de « Drag » la tableView
envoie un message
tableView:validateDrop:proposedRow:proposedDropOperation: à la data source.

Dans le cas de notre lecteur, cette méthode devra vérifier entre autres le fait que les fichiers sont de
types « mp3 ».
Cahier de Travaux Pratiques – Cursus Cocoa 19 / 19

10.2.4 Accepting a drop
Une fois la validation faite par la méthode précédente, les objets sont lâchés (Drop) dans la tableView.
Celle-ci envoie un message tableView:acceptDrop:row:dropOperation: au data source.
L’implémentation de cette méthode doit faire en sorte de gérer les objets qui se trouvent dans le
pastboard pour les ajouter à la tableView.

Il faudra aussi penser à mettre à jour la tableView ainsi que notre tableau récapitulant notre playlist.


le .h :

#import "PlayController.h"

@implementation PlayController

- (IBAction)addTrack:(id)sender
{

}

- (IBAction)playPause:(id)sender
{
[self start123With: currentPath];
}

- (IBAction)removeTrack:(id)sender
{

}


-(id)init
{
self=[super init];
if(self)
{
listArray = [[NSMutableArray alloc] initWithCapacity:5];
the123Task = nil;
currentPath = nil;
isSuspended = FALSE;
}
return self;
}

-(void)dealloc
{
[listArray dealloc];
[super dealloc];
}

-(int)numberOfRowsInTableView: (NSTableView *)aTableView2
{
return [listArray count];
}

-(id)tableview: (NSTableView *)aTableView objectValueForTableColumn: (NSTableColumn *)tableColumn row: (int)rowindex
{
return [listArray objectAtIndex: rowindex];
}


-(void)awakeFromNib
{

}

-(void)start123With: (NSString *)track
{
the123Task = [[NSTask alloc] init];
NSString *pathmpg = file://localhost/Users/admin/Desktop/TP%20MPG123/mpg123;
[the123Task setLaunchPath: pathmpg];
NSArray *taskArray = [NSArray arrayWithObject: track];
[the123Task setArguments: taskArray];
[start123With launch];
}

-(void)stop123
{
[start123With interrupt];
[the123Task release];
}

@end

Et le .m au cas où :

/* PlayController */

#import <Cocoa/Cocoa.h>

@interface PlayController : NSObject
{
IBOutlet NSButton *addButton;
IBOutlet NSTableView *listTableView;
IBOutlet NSButton *pauseButton;
IBOutlet NSButton *playButton;
IBOutlet NSButton *removeButton;
NSMutableArray *listArray;
NSTask *the123Task;
NSString *currentPath;
BOOL isSuspended;
}

- (IBAction)addTrack:(id)sender;
- (IBAction)playPause:(id)sender;
- (IBAction)removeTrack:(id)sender;
-(void)start123With: (NSString *)track;
-(void)stop123;

@end


Désolé pour l'abscence de commentaires,

Merci d'avance à ceux qui comprennent ce language tordu

6 réponses

Paye ton TP noter de P2 ...

Ya vraiment une difference entre bloquer a un endroit et demander de l'aide et balancer le tp complet.
3
ça va pas trop dur vos TP notés ?
Diplôme à vendre sur comment ça marche !!!
1
Ninja_En_Short Messages postés 133 Date d'inscription mercredi 19 septembre 2007 Statut Membre Dernière intervention 27 juin 2014 9
21 janv. 2008 à 14:19
Euh petite bourde j'ai inversé .h et .m '^^
0
DrDooM Messages postés 1 Date d'inscription mardi 22 janvier 2008 Statut Membre Dernière intervention 22 janvier 2008
22 janv. 2008 à 11:41
maile moi à drdoom[nospam]@live.com je devrais pouvoir t'aider
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Ninja_En_Short Messages postés 133 Date d'inscription mercredi 19 septembre 2007 Statut Membre Dernière intervention 27 juin 2014 9
23 janv. 2008 à 10:09
Non c'est bon j'ai trouvé un pote qui a put m'aider dessus.

Merci quand même ;)
0
Et tu peut faire en partager de ton aide, j'y suis ds le mm cas.!!!!!!!!!!!!!
0