Shadoware.Org

mercredi, 19 mars 2014

Mon livret de messe - Site de génération de livrets au format PDF

Mon livret de messe - Générateur de PDF

Bonjour,

Ce petit billet pour vous parler d'un site que j'ai développé pour ma femme et dont l'adresse est http://monlivretdemesse.fr. Ce projet que je développe depuis plusieurs années, a été mis à jours récément. Je profite de cette mise à jours pour vous parler de ce projet fonctionnellement mais aussi techniquement.

Monlivretdemesse.FR est un site permettant aux utilisateurs allant se marier de générer leur livret de messe au format PDF afin de l'imprimer directement chez eux. Les pages du livret ainsi générées sont alors ordonnées de telle manière qu'il suffit de faire une impression recto/verso puis de plier les feuilles pour avoir son livret. Je me suis chargé du développement de ce site, pendant que ma femme se charge du contenu (donc le contenu des textes, des images, mais aussi et surtout le thème de chaque produit, leur format).

La nouvelle version sortie le 11 mars 2014 permet également la création d'autres types de produits afin de générer des

Le site a été écrit à l'aide du framework Symfony2 et utilise la bibliothèque TCPDF afin de générer les fichiers PDF. Les données sont stockées dans une base de données MongoDB. Parmi les données on peut compter les données produits, utilisateurs, mais aussi le cache des PDF générés enregistrés en tant que fichier dans GridFS (et ceci afin qu'un livret qui n'a pas été modifié ne soit pas re-généré).

Symfony2

Symfony 2 est un framework PHP permettant le développement de sites Internet. Il est livré par défaut avec un ORM: Doctrine qui permet de faire correspondre à une structure de base de données des classes PHP qui seront automatiquement hydratées.

Le développement PHP s'en retrouve presque agréable (je préfère les langages compilés en règle générale). Le framework est de la même trempe que le Framework Python Django.

Ce dernier m'a d'ailleurs tenté (bien qu'interpreté aussi), mais une lecture rapide de la documentation m'a donné l'impression d'être un peu moins pratique à utiliser que Symfony2. Peut-être car je ne fais pas de Python.

Pour mon prochain projet j'étudierai l'utilisation de symfony2 vs ruby on rails vs django vs node.js. Mais je ne suis pas sûr qu'au final l'utilisation d'une des technos précédentes m'apporte beaucoup plus par rapport à ce que sait déjà faire un framework comme symfony2. L'avantage d'un tel framework réside aussi dans le nombre de bundle et de librairie utilisables à l'extérieur.

Par rapport à la distribution de base de symfony2 j'ai remplacé la version Doctrine ORM par Doctrine ODM. Ce qui me permet de me connecter à une base de données MongoDB.

MongoDB

Mon projet d'abord basé sur une base MySQL a été basculé sur une base de données NoSQL nommée MongoDB.

La raison n'est pas technique (je n'ai pas besoin de replication, de sharding, ...., pas assez de visiteurs). J'avais juste envie de tester cette base de données sur mon projet. De plus l'aspect orienté document est agréable au développement.

En effet, au lieu de stocker les informations dans différentes tables et de tenter d'y accéder à l'aide de jointure ou de requête multiple, dans on MongoDB on stocke un document dans un format binaire du JSON (le BSON).

Un panier stocké en base pourra avoir la forme :

{
  "_id": ObjectId("......................"),
  "expiration_updated_at": ISODate("2014-03-17T21:00:34.0Z"),
  "lines": [
    {
      "product": {
        "product": "marque-place-baroque-dore",
        "product_name": "Marque-place baroque doré",
        "variant": "dore-gris",
        "variant_name": "Doré\/Gris",
        "amount": 7.9
      },
      "custom": ObjectId("....................")
    }
  ],
  "lines_count": NumberInt(1)
}

On retrouve dans un seul document les informations liées au panier et les informations concernant chaque ligne. La dénormalisation n'étant pas un problème, on rappelera alors ici le nom du produit, et le nombre de lignes que l'on pourrait retrouver autrement mais qui permettra un affichage plus rapide de cette manière.

Par exemple, sur la page d'acceuil où on affiche le nombre de produit dans le panier, il nous suffira de requêter lines_count sans toucher à l'attribute lines. Ensuite lors de l'affichage du panier, on récupérera les lignes et les informations du panier en une seule requête et sans jointure.

Ainsi pour des entités avec forte relation, qu'on ne récupère jamais les unes sans les autres, une seule requête permet de récupérer toutes les informations. Par exemple, dans une base relationnelle, on aura l'habitude de stocker l'entête du panier dans une table, et les lignes dans une autre table. Avec Mongo, si je veux récupérer le panier en une requête, je récupère aussi les lignes. Cela implique par contre de ne pouvoir requêter facilement sur les lignes du panier indépendamment de leur entête.

Le seul problème que j'ai actuellement avec l'ODM Doctrine est que la mise à jour du panier se fait en plusieurs requêtes alors qu'il serait préférable de le faire en une seule pour des questions d'atomicité. Ce point fait d'ailleurs l'objet du ticket 437 du Github du projet.

Les différents modules du site

Dans cette section je vais vous parler rapidement des différents bundle que j'ai créé pour le site.

Le CMS

Afin de faciliter l'édition des pages de contenu (Mention légales, Documentation, FAQ) sans toucher au code. J'ai écrit un mini CMS. Le but est de stocker dans la base de données les différentes pages du projet, ainsi que les images associées aux pages.

Pour cela j'ai un bundle nommé CMS qui utilise la notion d'édition inline de CKEditor. J'ai écris mon propre Explorer de media qui permet de récupérer et ajouter dans cette même base des fichiers à attacher aux différentes pages.

L'adresse de la page est alors décomposée pour récupérer la clé de la page. Une page dont l'adresse sera /page/prout aura comme clé en base /prout. Pour un utilisateur non administrateur (ou anonyme), si la page est trouvée, elle est affichée telle quelle et si elle n'est pas trouvée, une page 404 est affichée.

En mode administrateur si la page existe, elle est ouverte en mode édition inline pour CKEditor. Si la page n'existe pas, elle est ouverte en mode création et en mode inline avec CKEditor. Il est ainsi super facile pour un administrateur de créer de nouvelles pages.

La partie media permet d'ajouter dans un GridFS dedié les images, et fichiers attachés.

Le module est du coup assez simple, deux documents

  • Page
  • Media

Le document Page ressemble à ceci:

/**
 * Page
 *
 * @MongoDB\Document(collection="cms_page")
 */
class Page {
    /**
     * @var string
     *
     * @MongoDB\Id(strategy="CUSTOM", options={"class"="\Shadoware\CMSBundle\Generator\PageSlugGenerator"})
     */
    private $slug;

    /**
     * @var string
     *
     * @MongoDB\String
     */
    private $name;

    /**
     * @var string
     *
     * @MongoDB\String
     */
    private $title;

    /**
     * @var string
     *
     * @MongoDB\String
     */
    private $content;

    /**
     * @var string $lang
     *
     * @MongoDB\String
     */
    private $lang;
}

Le controlleur est assez simple :

/**
 * @Route("/page/{slug}", requirements={"slug" = ".+"})
 * @Template()
 */
public function indexAction($slug) {
    $dm = $this->get('doctrine_mongodb')->getManager();

    $page = $dm->getRepository("CMSBundle:Page")->find($slug);
    if ($page == null) {
        if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {
            $page = new Page();
            $page->setTitle("Titre de la page");
            $page->setSlug($slug);
            $page->setName("Nom");
            $page->setContent("Contenue de la page");
        } else {
            throw $this->createNotFoundException("Page not found");
        }
    }

    $request = $this->getRequest();
    if ($request->getMethod() == "POST" && $page != null) {
        $page->setName($request->get('name'));
        $page->setTitle($request->get('title'));
        $page->setContent($request->get('content'));

        $dm->persist($page);
        $dm->flush();
    }

    return array('page' => $page);
}

Et enfin la vue Twig contient les références à CKEditor et l'activation du contenu modifiable inliné pour les projets. Pour l'instant le module est fortement lié à l'application existante. J'ai dans l'espoir d'avoir assez de temps un jour pour externaliser ce module afin de pouvoir le partager à plus de monde.

Si vous avez envie d'avoir plus d'information sur ce bundle n'hesitez pas à me contacter et je vous réponderez avec joie.

Les produits

La partie produits et beaucoup plus liée à l'activité du site. Les produits contiennent pour chaque colori, un modèle dans lequel sont définis la position des différentes informations qui seront par la suite saisies par l'utilisateur. Ma femme peut ainsi, après avoir préparé son modèle le personnaliser sur le site.

Un document de type produit personnalisé permet ensuite de spécialiser le produit en y ajoutant les informations saisies par l'utilisateur. C'est ce produit final qui est ensuite acheté par l'utilisateur.

Les paiements

La partie paiement contient la gestion du panier, de la facturation et le lien avec le site Paypal. En effet on utilise l'API de paypal pour effectuer les paiements car nous n'avions pas l'envie de gérer pour ce site un système de paiement onéreux et complexe. Paypal prélève un pourcentage de la transaction, et permet le paiement par carte bancaire des utilisateurs anonymes, ce qui nous convient.

Au niveau du panier, certaines informations sont enregistrées, comme le nombre de lignes dans le panier, ainsi que le nom du produit et le nom du coloris choisis afin de faciliter le requêtage et l'affichage.

La gestion des utilisateurs

La gestion des utilisateurs passent par FOS/UserBundle. Quelques personnalisations ont été ajoutées à ce module afin de correspondre au thème du site et aussi pour ajouter quelques informations.

Le site

Ajoute les CSS et javascript personnalisés du site. Le theme a été acheté à une époque sur un site proposant des templates, mais à depuis été customizé et adapté pour notre utilisation.

L'admin

L'interface d'administration permet à femme et à moi d'accéder aux différents produit, d'en créer de nouveau, de les modifiers. L'interface se base sur un thème bootstrape et reste assez simple. Seul l'utilisateur avec le role d'administrateur peut accéder à cette page.

Dans l'avenir.

Le découpage actuel ne me plaît pas forcément. En effet, je charge des bundles propres à l'admin sur le site alors que ces derniers pourraient être chargés uniquement dans le cadre de l'admin et inversement. Je pense qu'appliquer une architecture comme celle décrite ici: http://jolicode.com/blog/multiple-applications-with-symfony2, pourrait être une bonne idée pour mieux découper l'application.

Dans le même style, la partie CMS actuelle est liée au site, et j'aimerais la découpler du site pour pouvoir l'utiliser assez facilement dans d'autres projets.

Mes contributions

Lors du développement de mon projet, j'ai eu besoin de certaines fonctionnalités que je n'ai pas trouvées dans les bundles existants ou qui ne me convenaient pas. Je vous présente ici différents projets que j'ai développé pour pallier à ces manques, sachant que pour l'instant ceux-ci ne sont pas parfaits et voir même, la documentation peut laisser à désirer (quand aux tests unitaires ils sont dans le néant).

Si vous souhaiter aider ou contribuer, n'hésitez pas.

CollectionBundle

Lien: CollectionBundle

Dans symfony, il est possible d'ajouter dans un formulaire un type collection pour permettre à un utilisateur de saisir une collection de sous-éléments (jointure de type OneToMany):

$builder->add('emails', 'collection', array(
    // chaque item du tableau sera un champ « email »
    'type'   => 'email',
    // ces options sont passées à chaque type « email »
    'options'  => array(
        'required'  => false,
        'attr'      => array('class' => 'email-box')
    ),
));

Le problème c'est que dans les formulaires symfony2 il n'est pas possible de gérer des formulaires différents suivant le sous-type de l'objet (gestion de l'héritage dans l'ORM).

CollectionBundle propose deux nouveaux types :

  • Un type permettant de gérer pour chaque classe fille, un formulaire différent.
  • Un type permettant de gérer des collections de taille fixe : Exemple toujours 5 éléments, quel que soit le nombre d'éléments rééls en base.

Ce bundle est actuellement utilisé uniquement dans la partie admin du site.

DoctrineMigrationODMBundle

Lien: DoctrineMigrationODMBundle

Pour l'ORM Doctrine, il existe DoctrineMigrationBundle qui permet de faire des migrations de schéma, mais il n'existait pas d'équivalent pour l'ODM gérant MongoDB.

Même si MongoDB est schemaless, et que les données peuvent être migrées à l'execution, je ressens le besoin d'avoir la possiblité d'exécuter des scripts lors des changements de version, pour :

  • ajouter de nouvelles données (nécessaires) dans des tables (car on requête sur ces données).
  • renommage de collection, suite à gros refactoring.
  • voir autre

FPDI et FPDF_TPL

Pour la génération des PDF, je génère une première version où chaque page est un élément différent, puis je me sers de FPDI pour associer les différentes pages sur une même page (avec la mention SPECIMEN ou pas).

Afin d'avoir accès à FPDI je me suis créé les dépôts suivants qui fonctionnent avec ceux de tecnick.com/tcpdf pour les utilisateurs de TCPDF.

Liens:

ImageResizerBundle

Lien : ImageResizerBundle

Dérivé de https://github.com/nresni/ImageResizerBundle, ce bundle ajoute

  • des caches supplémentaires
  • fournit une URL sur la valeur du cache directement (et de générer le cache lors de l'appel de la commande twig). Cette dernière permet de cacher un peu l'URL utilisée pour accéder à l'image d'origine. On ne peut accéder alors qu'à l'URL finale. Comme les ids des images sont des ObjectId, il n'est pas possible de retrouver par le nom l'URL de l'image d'origine.

Cette extension est utilisée par toute l'application pour l'affichage de toutes les miniatures.

PiwikBundle

Lien : PiwikBundle

Ce plugin a été créé afin de pouvoir ajouter la gestion de Piwik dans Symfony2. Les commandes PIWIK peuvent être passées au travers d'un service ou au travers de commandes TWIG. Ce plugin gère également la notion d'e-commerce de PIWIK.

Une fois le plugin installé (via composer), il faut l'activer à l'aide de la configuration suivante:

shadoware_piwik:
    base_url: http://monpiwik.monsite # URL de base du serveur PIWIK
    id_site: 1                        # N° du site dans PIWIK
    hidePiwik: false                  # Indique s'il faut cacher le tracker par un controlleur interne.
    tokenId: abcedfghijkmn123456789   # Le token id de l'utilisateur (pour le cas où on cache piwik)
    heartbeat: ~                      # Permet de définir quelques attributs activant la fonctionnalité de heatbeat de piwik.

Une fois la configuration faite, le plugin ajoutera juste avant chaque balise l'appel à piwik (en utilisant la méthode asynchrone). Si la page ne contient pas de balise ou si elle constitue une page de redirection, les informations seront déportées à l'affichage suivant.

Cette dernière fonctionnalité permet par exemple d'ajouter des éléménts au panier e-commerce piwik lors des pages de redirection, et de traiter son affichage dès que possible. Cela a par contre comme limitation de ne pas gérer les conflits.

L'utilisation depuis un controlleur se fait grâce à l'utilisation du service:

$this->container->get('shadoware_piwik.service')->addEcommerceItem($productId, $productName, $category, $amount);
$this->container->get('shadoware_piwik.service')->trackEcommerceCartUpdate($totalAmount);

L'utilisation depuis une page twig se fait à l'aide des commandes twig. Par exemple dans la page twig de base:

<title>{{ 'title' | trans }} - {% block title %}{{ 'menu.home' | trans }}{% endblock %}</title>
{{ setPiwikPageName(block('title')) }}

Conclusion

Bon voilà j'espère vous avoir fait découvrir le site ainsi que quelques nouveaux plugins intéressant.

A bientôt,

samedi, 12 janvier 2013

Passage du site sous Pelican

Bonjour à tous,

Cela fait bien longtemps que je n'ai rien écrit sur ce site. Et pour cause, je suis bien occupé :D.

J'ai quand même pris un peu de temps récemment pour passer entièrement mon site sous Pelican.

C'est mon cadeau de Noël de Geek ;).

Qu'est-ce que Pelican ?

Pelican est un gestionnaire de blog statique.

Qu'est-ce que ça veut dire ?

Cela signifie que je vais écrire mes billets avec mon éditeur de texte préféré (kwrite), au format Markdown (ou restructuredText), et que je génère mon blog au format HTML avant publication. (De la même manière que l'on compilerait un programme).

Le serveur n'a alors besoin de servir que des fichiers statiques, il n'y a donc pas de surplus de mémoire, ou de délai dû à la nécessité de générer les pages.

Les pages n'étant pas modifiées tous les jours, il n'y a de toute façon pas d'intérêt de générer les pages à chaque accès.

Les avantages indéniables sont les suivants :

  • Pas de base de données, pas de page générée à la volée : donc pas de temps de latence. La page est servie dés qu'elle est demandée. De ...

Lire la suite ...

dimanche, 01 juillet 2012

Cross-Compilation - Compiler un programme pour MS/Windows sous Gnu/Linux

Qu'est que la cross-compilation1 ?

La cross compilation est la possibilité sur une machine avec un matériel spécifique (architecture) et avec un système d'exploitation donné, de compiler des programmes pour une autre architecture, ou pour un autre système d'exploitation.

Cela peut être utilisé par exemple pour compiler un programme sur votre ordinateur de tous les jours (sous Gnu/Linux, avec une architecture i386) à destination de votre téléphone mobile, qui lui est sous Symbian avec un processeur ARM.

Les raisons de faire de la compilation croisée peuvent donc être multiples :

  • Éviter de redémarrer votre machine pour compiler vos binaires.
  • Disponibilité des outils sur votre machine / Indisponibilité des outils de compilation sur la machine de destination (on trouve rarement des outils de compilation sur des téléphones portables2).
  • Puissances des calculs (la compilation prendra moins de temps sur votre PC de bureau que sur votre appareil mobile3).
  • Licence : Vous voulez compiler à destination d'un système d'exploitation que vous ne possédez pas

Attention: La compilation croisée ne garantie pas que programme fonctionnera, vous devrez toujours faire quelques tests à partir d'un émulateur ou à partir du système d'exploitation final.

Bref, à partir du moment ...

Lire la suite ...

dimanche, 14 août 2011

KMDAlert - Logiciel de surveillance de périphérique RAID - Version pour KDE 4.0

Présentation

Possédant chez moi des disques durs en RAID logiciels sous Gnu/Linux, en 2007 (cela fait déjà 4 ans), j'avais écrit un petit logiciel dont le but était de faire du monitoring RAID.

En cas de reconstruction du RAID ou de disque défectueux, le logiciel affiche une notification à l'utilisateur, et change le statut affiché dans la barre de notification (systray). L'icône change bien sur en fonction de l'état du RAID :

  • dégradé (avec un point d'exclamation)
  • en cours de synchronisation (avec une barre de progression)
  • disque RAID dans un état normal

Ce logiciel ne tournait que sous KDE 3.X.

Voici donc une nouvelle version (qui a mis le temps de sortir) qui est un portage de l'application sous KDE 4.X. Elle utilise donc le nouveau système de notification de KDE (pour l'instant en passant uniquement par les notifications standard). Quelques améliorations y seront apportées plus tard.

Requis

Pour fonctionner KMDAlert nécessite que le dossier /sys soit monté et que /sys/block/ soit renseigné pour chaque volume RAID (exemple /sys/block/md0, /sys/block/md1, ...). KMDAlert observe ensuite les modifications faites sur les fichiers pour informer l'utilisateur des modifications faites ...

Lire la suite ...

samedi, 06 août 2011

qGenConfig - Générateur de classe

Présentation

Ce logiciel permet de générer des objets Qt héritant de QConfig à partir d'un fichier écrit au format XML.

Lors de la sauvegarde de paramètres avec Qt, il faut généralement écrire des choses ainsi :

QSettings settings("MaBoite", "MonLogiciel");

settings.beginGroup("Ma fenêtre");
settings.setValue("Taille", win->size());
settings.setValue("Pleine écran", win->isFullScreen());
settings.endGroup();

Puis pour récupérer les mêmes paramètres, il faut écrire :

QSettings settings("MaBoite", "MonLogiciel");

settings.beginGroup("Ma fenêtre");
QSize size = settings.value("Taille").toSize();
bool fullscreen = settings.value("Pleine écran").toBool();
settings.endGroup();

Si les valeurs doivent être récupérées dans toute l'application et qu'un jour l'un des paramètres change de nom, de type, ou de groupe, il ne sera pas possible d'être sûr que tous les endroits de l'application sont bien modifiés lors de la compilation.

C'est là qu'intervient qGenConfig.

Le but est d'écrire un fichier XML représentant la configuration du logiciel et possédant une certaine structure (des groupes, et des valeurs). Le programme parcourt ensuite ce fichier et génère une classe permettant de lire et d'enregistrer la configuration à l'aide de qGenConfig. Le contenu des données est alors stocké dans une structure C ...

Lire la suite ...

dimanche, 26 juin 2011

[C++/Qt] CMake et Qt

Suite à un billet datant de 2008, je reviens vers vous pour ajouter quelques précisions sur la compilation de programme Qt avec CMake. En effet, pour mon programme XINX, j'ai modifié la chaîne de compilation actuelle utilisant QMake par une chaîne de compilation CMake.

CMake est un puissant générateur de Makefile, il permet de remplacer les anciens (mais pas complètement révolus) autotools. CMake ne remplace donc pas le programme make mais vient se placer en amont.

CMake permet de compiler un programme à différents endroits du dossier des sources, ce qui permet de garder le répertoire des sources propre.

Nous allons considérer dans la suite le dossier projet suivant :

  • projet
    • source
    • build

Compilation

Nous passerons sous silence la compilation d'un programme non Qt qui peut être retrouvé dans la documentation et nous nous limiterons aux explications liées aux programmes écrits en ''Qt' (qui peuvent également être retrouvés dans d'autres tutoriels sur Internet).

Package à utiliser

Pour utiliser Qt4 avec CMake, il faut inclure le package Qt4 :

project(lenomdemonprojet) 
cmake_minimum_required(VERSION 2.8.0)
find_package(Qt4 REQUIRED)

Définir les modules Qt à utiliser :

Il est ensuite possible d'activer ou de désactiver les différents modules de Qt à ...

Lire la suite ...

mardi, 03 mai 2011

XINX v0.10.1

Bonjour à tous,

Je suis heureux de vous annoncer la nouvelle version de XINX. Cette version apporte, en plus de la ré-écriture complète de la gestion du contenu et de la complétion, son petit lot de nouveautés et de corrections.

La version 0.10.1 est beaucoup plus stable que sa grande soeur 0.9. Un soin particulier a été apporté à la recherche des sources d'anomalie possible, ainsi que des fuites mémoires. Ces opérations ont été faites grâce à des outils tels que valgrind, mais aussi grâce aux béta-testeurs (Merci à eux).

De plus l'utilisation des pointeurs intelligents de Qt ont permis de passer plus de temps, sur la gestion des structures et moins de temps sur la gestion de la mémoire, sur des parties du code assez critiques (comme ContentView et CodeCompletion). Ils ont également permis un partage plus facile des structures entre les différents threads avec moins de contrôle de synchronisation.

Liens

Gestion Projet et Gestion des sessions

Multi-projet

Project

XINX est maintenant capable d'ouvrir plusieurs projets en même temps. Cela permet donc plusieurs choses :

  • Rechercher un fichier pouvant ...

Lire la suite ...

mardi, 25 janvier 2011

[C++/Qt] Performance de l'utilisation de QSharedPointer

Présentation

Qt est un framework orienté objet écrit en C++ et permettant de faire des interfaces graphiques. Ce framework est utilisé par le projet KDE depuis ses débuts pour en faire un environnement de bureau très complet.

Qt fournit un ensemble de pointeur intelligent1 permettant de gérer plus facilement la mémoire. Le but est alors de ne plus avoir à supprimer des objets. La suppression se fera soit par un pointeur intelligent soit par le système de hiérarchie d'objet existant en Qt (l'objet père qui supprime l'ensemble des objets fils qui lui sont rattachés).

Qt propose l'ensemble des pointeurs intelligents suivants:

  • QSharedDataPointer / QSharedData : ces deux classes utilisées ensemble permettent d'écrire un objet avec partage implicite. Cela signifie que l'objet fonctionnera comme la classe QString. Tant que l'objet est copié, passé en paramètre, .... l'objet n'est pas dupliqué (tous les objets pointes vers le même espace mémoire). Au moment où l'objet est modifié, l'objet est dupliqué. C'est ce qu'on appelle le COW2.
  • QExplictlySharedDataPointer / QSharedData : QExplicitlySharedDataPointer est une variante de QSharedDataPointer. Ce pointeur intelligent, comme son nom l'indique, est détaché uniquement lorsque la méthode detach() est appelée ...

Lire la suite ...

mercredi, 22 décembre 2010

[C++/Qt] Concaténation de chaînes de caractères

Présentation

Qt est un framework orienté objet écrit en C++ et permettant de faire des interfaces graphiques à l’aide de ces widgets. Ce framework est utilisé par le projet KDE depuis ses débuts pour en faire un environnement très complet.

Qt permet donc de faire des interfaces graphiques mais aussi d’accéder à des bases de données SQL, de faire de la communication réseau, une gestion simplifiée des threads, la lecture de fichier XML. Qt intègre aussi le moteur HTML Webkit.

Qt ajoute une couche supplémentaire au C++ permettant de faire de l’introspection de classe un peu plus poussée (comme l’appel d’une méthode dont on ne connaît le nom qu’à l’exécution). Qt permet également la gestion d’évènement par l’intermédiaire d’un système puissant de SIGNALS et de SLOTS.

Dans la suite de cet article nous allons nous concentrer sur une très petite partie de Qt mais qui est utilisée dans beaucoup d’applications écrites en Qt : les chaînes de caractères, et plus précisément, la concaténation de chaînes de caractères.

Concaténation de chaînes de caractères.

Comme dans d’autres langages, la concaténation de chaînes de caractères se fait à l'aide de l ...

Lire la suite ...

dimanche, 06 juin 2010

Calcul de la distance entre deux fichiers

Présentation

Suite à un billet sur LinuxFR, où je demandais comment calculer la distance (ou le pourcentage de similitude entre deux logiciels), j'ai obtenu la formule suivante :

distance = 1 - ( C(A) + C(B) - C(AB) ) / Max(C(A), C(B))

où C(X) est la taille du fichier X compressé1.

Après avoir testé les formats gzip, bzip2 et lzma, j'ai conclu que le format de compression le plus performant pour le calcul, est le format lzma, car le dictionnaire avec la mise en commun était le plus gros, et donc le calcul de distance est plus efficace.

Le programme

J'ai donc décidé d'écrire un programme parcourant un dossier (avec plusieurs milliers de fichiers) et de calculer pour toutes les combinaisons des fichiers la distance entre chaque fichier. Ce programme consommant énormément de mémoire, il se peut que pour un grand nombre de fichier, le programme se plante avec une erreur d'allocation de mémoire.

Ce programme permet de pouvoir faire une cartographie de ces fichiers et ainsi de pouvoir les classer. Testé sur des fichiers textes (sources de logiciels), le programme est assez efficace.

Testé sur des images, ou des vidéos, les fichiers sont considérés ...

Lire la suite ...

Page 1 / 4 »