Vue d’ensemble

Le tableau suivant liste les classes de modèle les plus importantes pour alimenter un diagramme de Gantt avec des données.

Classe Description
Activity Les activités représentent des objets qui seront affichés sous la timeline dans la vue graphique du contrôle de diagramme de Gantt. Les activités peuvent être ajoutées à une couche spécifique sur une ligne.
ActivityRef Une référence d’activité sert à identifier précisément l’emplacement d’une activité, cet emplacement étant la combinaison de la ligne, de la couche et de l’activité elle-même.
ActivityLink Un lien d’activité peut servir à exprimer une dépendance entre deux activités.
ActivityRepository Les référentiels d’activités sont utilisés par les lignes pour stocker et rechercher des activités.
Row Un objet ligne (modèle) sert à stocker les activités présentes sur une ligne (visuelle) du diagramme de Gantt.
Layer Les couches servent à créer des groupes d’activités.
LinesManager Un gestionnaire de lignes sert à contrôler la mise en page des lignes internes d’une ligne.
Layout Chaque ligne et chaque ligne interne d’une ligne sont associées à une mise en page. La mise en page influence plusieurs aspects lors du rendu et de la modification des activités. De plus, plusieurs couches système utilisées pour dessiner l’arrière-plan de la ligne utilisent également les informations de mise en page.
Calendar Un calendrier est une extension d’un référentiel d’activités avec en plus un nom et une propriété de visibilité.

Activité

Les activités représentent des objets qui seront affichés sous la timeline dans la vue graphique du contrôle de diagramme de Gantt. Elles peuvent être ajoutées à une couche spécifique sur une ligne en appelant Row.addActivity(Layer, Activity).

Types d’activité

Voici les différents types d’activités qui peuvent être ajoutés à une ligne.

  • Activity - implémentation de base : ActivityBaseBase - la forme la plus simple d’activité.

    • id (String)
    • name (String)
    • startTime (Instant)
    • endTime (Instant)
  • ChartActivity - implémentation de base : ChartActivityBaseBase - les activités de ce type peuvent être affichées dans une mise en page de graphique.

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)
  • chartValue (double)

  • CompletableActivity - implémentation de base : CompletableActivityBase - les activités de ce type portent une valeur de pourcentage (achèvement).

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)
  • percentageComplete (double)

  • HighLowChartActivity - implémentation de base : HighLowChartActivityBase - les activités de ce type peuvent être affichées dans une mise en page de graphique.

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)
  • high (double)
  • low (double)

  • MutableActivity - implémentation de base : MutableActivityBase - la forme la plus simple d’activité mutable. L’utilisateur peut modifier l’heure de début et de fin de ces activités.

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)

  • MutableChartActivity - implémentation de base : MutableChartActivityBase - ces activités peuvent être affichées dans une mise en page de graphique. L’utilisateur peut modifier l’heure de début, l’heure de fin et la valeur de graphique de ces activités.

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)
  • chartValue (double)

  • MutableCompletableActivity - implémentation de base : MutableCompletableActivityBase - ces activités portent une valeur de pourcentage (achèvement). L’utilisateur peut modifier leur heure de début, leur heure de fin et leur valeur de pourcentage d’achèvement.

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)
  • percentageComplete (double)

  • MutableHighLowChartActivity - implémentation de base : MutableHighLowChartActivityBase - ces activités peuvent être affichées dans une mise en page de graphique. L’utilisateur peut modifier leur heure de début, leur heure de fin ainsi que leurs valeurs high et low.

  • id (String)
  • name (String)
  • startTime (Instant)
  • endTime (Instant)
  • high (double)
  • low (double)

Activité de graphique

Une activité de graphique est une interface d’extension pour les activités. Elle doit être implémentée par les activités qui veulent participer à un ChartLayout. L’interface ajoute une valeur de graphique à l’activité. L’image ci-dessous montre un exemple de mise en page de graphique disposant une activité de graphique par jour.

Mise en page de capacité

Activité complétable

Une activité complétable est une activité qui porte une valeur « percentage complete » comprise entre 0 et 100 %. Les activités complétables sont dessinées avec un « moteur de rendu de barre d’activité complétable ». Ce moteur de rendu dessine l’arrière-plan de l’activité en fonction de la valeur de pourcentage d’achèvement. L’image ci-dessous montre un exemple.

Complétable

Activité de graphique high-low

Une activité de graphique high-low porte deux attributs supplémentaires : high et low. Ces valeurs sont utilisées par ChartLayout pour les positionner correctement. Un bon cas d’usage pour les activités high-low est celui des graphiques en chandeliers (par exemple prix d’ouverture / haut / bas / clôture d’actions).

Référence d’activité

Une référence d’activité sert à identifier précisément l’« emplacement » d’une activité. Un emplacement est la combinaison de la ligne, de la couche et de l’activité elle-même. Comme une même activité peut se trouver sur plusieurs lignes et/ou plusieurs couches en même temps, il est souvent nécessaire de travailler avec une référence d’activité plutôt qu’avec l’activité seule. Vous pouvez considérer une référence d’activité comme un « chemin » vers l’activité.

Un lien d’activité peut servir à modéliser n’importe quel type de dépendance entre deux activités. Dans les applications de planification de projet, un lien exprimerait une relation prédécesseur / successeur entre deux tâches. Par exemple, « la tâche A doit être terminée avant que la tâche B puisse commencer ». Dans d’autres domaines, un lien peut simplement exprimer que deux ou plusieurs activités doivent être planifiées ensemble et que déplacer l’une d’elles nécessite de déplacer toutes les autres également. L’image ci-dessous montre un exemple d’un tel lien.

Un lien peut être ajouté au diagramme de Gantt en appelant GanttChart.getLinks().add(myLink);

Lien

Référentiel d’activités

Les référentiels d’activités sont utilisés par les lignes pour stocker et rechercher des activités. Par défaut, chaque ligne possède un IntervalTreeActivityRepository. Ce référentiel par défaut peut être remplacé par un référentiel personnalisé, par exemple si votre application nécessite une stratégie de chargement paresseux.

Requêtes

La fonctionnalité la plus importante de tout référentiel est la possibilité de l’interroger pour obtenir les activités situées dans un intervalle de temps donné. À cette fin, l’interface ActivityRepository définit la méthode getActivities() avec les paramètres suivants :

Type Nom Description
Layer layer Lorsque l’utilisateur fait défiler vers la gauche ou vers la droite, la ligne interroge plusieurs fois le référentiel : une fois pour chaque couche.
Instant startTime L’heure de début de l’intervalle de temps pour lequel la ligne interroge les activités.
Instant endTime L’heure de fin de l’intervalle de temps pour lequel la ligne interroge les activités.
TemporalUnit unit La valeur actuelle de l’unité temporelle principale actuellement affichée par la ligne de dates. Il s’agit de l’unité affichée en bas de la ligne de dates, par exemple les jours. Ce paramètre peut être utilisé pour contrôler le niveau de détail du résultat. Si vous savez que l’utilisateur consulte actuellement des mois, il peut être pertinent d’agréger les activités quotidiennes.
ZomeId zoneId Le fuseau horaire affiché par la ligne.

Première / dernière heure utilisée

Chaque implémentation de référentiel doit pouvoir répondre à la question des premières et dernières heures utilisées (heure de début la plus ancienne / heure de fin la plus récente de toute activité stockée dans le référentiel). Cela permet à l’interface utilisateur de fournir des contrôles de navigation simples : « show earliest », « show latest ». Pour cela, les référentiels doivent implémenter les méthodes getEarliestTimeUsed() et getLatestTimeUsed().

Mise à jour des activités

Les activités doivent être retirées (ActivityRef.detachFromRow()) de leur référentiel avant d’être modifiées, puis rajoutées (ActivityRef.attachToRow()) après modification. C’est le seul moyen de garantir que la structure de données sous-jacente d’un référentiel reste toujours synchronisée avec les activités. Exemple : la structure d’arbre d’intervalles ne fonctionne correctement que si tous ses nœuds sont à leur emplacement correct. Cela ne peut être garanti que si les nœuds sont retirés de l’arbre avant d’être modifiés (sinon l’arbre ne les trouvera pas), puis réinsérés avec leur nouvelle valeur.

Gestion des événements

Les référentiels d’activités implémentent la prise en charge des listeners afin que l’interface utilisateur puisse se mettre à jour si le contenu du référentiel change. Les parties intéressées peuvent attacher des handlers en appelant addEventHandler() ou les supprimer en appelant removeEventHandler(). La classe d’événement s’appelle RepositoryEvent et possède trois types d’événement :

  • ACTIVITY_ADDED - une activité a été ajoutée au référentiel.
  • ACTIVITY_REMOVED - une activité a été retirée du référentiel.
  • REPOSITORY_CHANGED - quelque chose a changé l’état du référentiel.

Chacun de ces types d’événement déclenche normalement un redessin de la ligne à laquelle appartient le référentiel.

IntervalTreeActivityRepository

Le InteralTreeActivityRepository est un référentiel d’activités qui utilise une ou plusieurs structures de données d’arbre d’intervalles binaire pour stocker les activités.

Arbre d’intervalles binaire

ListActivityRepository

Le ListActivityRepository est un référentiel d’activités qui utilise une ou plusieurs structures de données de liste pour stocker les activités. Ce référentiel peut être configuré pour renvoyer différents types d’itérateurs de résultat depuis sa méthode de requête. Les valeurs possibles sont définies dans ListActivityRepository.IteratorType.

  • BINARY_ITERATOR - renvoie un itérateur qui effectue une recherche binaire pour trouver la première activité à dessiner pour un intervalle de temps donné. Il parcourt ensuite toutes les activités suivantes jusqu’à trouver une activité qui commence après l’intervalle donné.
  • LINEAR_ITERATOR - renvoie un itérateur qui effectue une recherche linéaire pour trouver la première activité à dessiner pour un intervalle de temps donné. Il parcourt ensuite toutes les activités suivantes jusqu’à trouver une activité qui commence après l’intervalle donné.
  • SIMPLE_ITERATOR - renvoie un itérateur qui n’effectue aucune recherche et commence immédiatement à renvoyer des activités, qu’elles se trouvent actuellement ou non dans l’intervalle de temps visible du diagramme de Gantt.

Le SIMPLE_ITERATOR est utilisé pour les lignes qui ne contiennent que quelques activités. Cet itérateur est précieux lorsque vous voulez vous assurer que le texte de fin d’une activité reste visible même si l’activité a déjà défilé hors de la zone visible.

Cas d’utilisation d’itérateur simple

Ligne

Un objet ligne sert à stocker les activités présentes sur une ligne du diagramme de Gantt. Ces activités ne sont pas stockées directement sur la ligne, mais dans un référentiel d’activités. Le référentiel par défaut est de type IntervalTreeActivityRepository. Les activités peuvent être placées sur des lignes internes au sein de la ligne. La ligne délègue ce travail à un LinesManager. Le gestionnaire par défaut est de type EqualLinesManager.

Arguments de type et hiérarchie

Trois arguments de type sont nécessaires pour définir une ligne. Le premier définit le type de la ligne parente, le deuxième le type des lignes enfants, et le troisième le type des activités affichées sur la ligne. Voici un exemple qui définit un « bâtiment ». Le bâtiment fait partie d’une usine. Le bâtiment contient des machines. Dans la ligne représentant le bâtiment, nous affichons des équipes.

public class Building extends Row<Factory, Machine, Shift> {
}

Un modèle de ce type nous permettrait d’afficher dans le diagramme de Gantt une hiérarchie ressemblant à ceci :

  • Usine
  • Bâtiment 1
  • Bâtiment 2
  • Bâtiment 3
    • Machine A
    • Machine B
    • Machine B
  • Bâtiment 4
    • Machine C
    • Machine D

Propriétés

Chaque ligne possède un ensemble de propriétés observables.

Propriété Type Description
expanded Boolean Contrôle si la ligne affiche ou non ses lignes enfants.
height double La hauteur actuelle de la ligne.
minHeight double La hauteur minimale de la ligne.
maxHeight double La hauteur maximale de la ligne.
layout Layout La mise en page utilisée par la ligne. La valeur par défaut est GanttLayout.
lineCount int Le nombre de lignes internes à afficher dans la ligne.
linesManager Lines Manager Le gestionnaire de lignes utilisé pour contrôler les lignes, leur position, leur hauteur et le placement des activités.
name String Le nom de la ligne, par exemple « Machine 1 », « Building 1 ».
parent Row La ligne parente. Il s’agit d’une propriété en lecture seule, gérée en interne et mise à jour lorsqu’une ligne est ajoutée à la liste des enfants d’une autre ligne.
référentiel Référentiel d’activités Le référentiel utilisé par la ligne pour stocker les activités.
showing boolean Un indicateur signalant que la ligne est actuellement affichée dans l’interface utilisateur. Cette information peut servir à optimiser les stratégies de chargement paresseux.
userObject Object Un objet utilisateur facultatif. Utilisé comme pont vers le modèle métier.
zoneId ZoneId Le fuseau horaire représenté par la ligne. Chaque ligne peut avoir son propre fuseau horaire.

Couche

Les couches servent à regrouper des activités. Les activités situées sur la même couche sont dessinées en même temps (ordre z). Une couche possède un nom, un ID, peut être activée / désactivée, et son opacité peut être modifiée. Ces changements ont un impact sur toutes les activités de cette couche. L’ID de la couche est utilisé pour les opérations de glisser-déposer d’activités entre différents diagrammes de Gantt. Les activités déposées sont ajoutées à la couche ayant le même ID. Le nom de la couche est utilisé comme ID par défaut pour les couches nouvellement créées. L’ID ne doit être modifié que si le même type de couche est utilisé avec des noms différents dans différents diagrammes de Gantt.

Gestionnaire de lignes

Ce gestionnaire sert à contrôler la mise en page des lignes internes d’une ligne. Les activités situées sur des lignes internes différentes ne se chevauchent pas, sauf si les lignes elles-mêmes se chevauchent. Chaque ligne interne peut avoir sa propre hauteur et sa propre position dans la ligne. Chaque ligne interne peut également avoir son propre mise en page. En utilisant des lignes internes et des mises en page, il est possible d’afficher de différentes manières des activités appartenant à la même ligne (voir ChartLayout, AgendaLayout, GanttLayout).

Nombre de lignes

Le nombre réel de lignes internes d’une ligne est stocké dans la propriété lineCount de la ligne. Appelez simplement Row.setLineCount(int) pour modifier sa valeur. Si le nombre de lignes est supérieur à zéro, la ligne rappelle son gestionnaire de lignes pour déterminer où se trouve chaque ligne interne, quelle est sa hauteur et quelle activité sera placée sur quelle ligne interne. Le type de mise en page à utiliser pour chaque ligne interne est également récupéré auprès du gestionnaire.

Interface

Le tableau suivant liste les méthodes de l’interface LineManager.

Method Description
double getLineHeight(int lineIndex, double rowHeight); Renvoie la hauteur de la ligne interne à l’index donné. La hauteur peut être calculée à la volée à partir de la hauteur de ligne disponible donnée.
int getLineIndex(A activity); Renvoie l’index de ligne interne pour l’activité donnée. Cette méthode place les activités sur différentes lignes internes.
Layout getLineLayout(int lineIndex); Renvoie la mise en page de la ligne interne ayant l’index donné. Chaque ligne interne peut avoir son propre mise en page.
double getLineLocation(int lineIndex, double rowHeight); Renvoie la position de la ligne interne ayant l’index donné. La position peut être calculée à la volée à partir de la hauteur de ligne disponible donnée.

Gestionnaire de lignes égales

Le EqualLinesManager peut être utilisé pour répartir uniformément les positions et les hauteurs des lignes internes sur une ligne. Chaque ligne interne aura la même hauteur et les lignes internes ne se chevaucheront pas. Bien que le gestionnaire fournisse ce comportement, il reste de la responsabilité de l’application de placer les activités sur différentes lignes internes et de spécifier la mise en page de chaque ligne interne. C’est aussi la raison pour laquelle les méthodes getLineHeight() et getLineLocation() sont finales, tandis que les méthodes getLineLayout() et getLineIndex() ne le sont pas et peuvent être surchargées.

Gestionnaire de lignes automatiques

Le AutoLinesManager peut être utilisé pour créer un nombre dynamique de lignes internes à partir de toutes les activités d’un référentiel. Ce gestionnaire de lignes détecte les groupes d’activités qui se chevauchent (intervalles heure de début / heure de fin) et garantit qu’un nombre suffisant de lignes internes est disponible pour placer les activités sans chevauchement. Vous trouverez ci-dessous le code source complet de cette classe de gestionnaire comme étude de cas. Notez que la méthode layout() du gestionnaire doit être invoquée de l’extérieur. Une bonne façon de le faire consiste à écouter les événements ACTIVITY_CHANGE_FINISHED, voire des événements plus fins comme START/END_TIME_CHANGE_FINISHED.

/**
 * Copyright (C) 2026 Dirk Lemmermann Software & Consulting (dlsc.com)
 *
 * This file is part of FlexGanttFX.
 */
package com.flexganttfx.view.util;
import static java.util.Objects.requireNonNull;
import impl.com.flexganttfx.skin.util.Placement;
import impl.com.flexganttfx.skin.util.Resolver;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.flexganttfx.model.Activity;
import com.flexganttfx.model.ActivityRepository;
import com.flexganttfx.model.Layer;
import com.flexganttfx.model.LinesManager;
import com.flexganttfx.model.Row;
import com.flexganttfx.model.layout.EqualLinesManager;
import com.flexganttfx.view.graphics.GraphicsBase;

/**
 * A specialized {@link LinesManager} used for ensuring that activities will not
 * overlap each other. This manager will create as many inner lines as needed
 * and will calculate the placement of all activities on these lines.
 *
 * @param <R>
 *            the type of the row that will be managed
 * @param <A>
 *            the type of the activities that will be managed
 *
 * @since 1.2
 */
public class AutoLinesManager<R extends Row<?, ?, A>, A extends Activity>
        extends EqualLinesManager<R, A> {

    private Map<A, Placement<A>> placements;
    private GraphicsBase<R> graphics;

    /**
     * Constructs a new automatic lines manager. The constructor requires a
     * reference to the graphics view to look up various parameters that are
     * needed when the manager queries the activity repository of the row (e.g.
     * the currently displayed temporal unit and the list of layers).
     *
     * @param row
     *            the managed row
     * @param graphics
     *            the graphics view where the manager will be used
     *
     * @since 1.2
     */
    public AutoLinesManager(R row, GraphicsBase<R> graphics) {
        super(row);
        this.graphics = requireNonNull(graphics);
        layout();
    }

    /**
     * Returns the graphics view where the manager will be used.
     *
     * @return the graphics view
     * @since 1.2
     */
    public final GraphicsBase<R> getGraphics() {
        return graphics;
    }

    public final void layout() {
        R row = getRow();
        ActivityRepository<A> repository = row.getRepository();
        Instant st = repository.getEarliestTimeUsed();
        Instant et = repository.getLatestTimeUsed();
        if (st == null || et == null) {
            return;
        }
        List<A> allActivities = new ArrayList<>();
        for (Layer layer : graphics.getLayers()) {
            Iterator<A> activities = repository.getActivities(layer, st, et,
                    graphics.getTimeline().getDateline()
                            .getPrimaryTemporalUnit(), row.getZoneId());
            if (activities != null) {
                activities.forEachRemaining(activity -> allActivities
                        .add(activity));
            }
        }
        placements = Resolver.resolve(allActivities);
        if (placements != null && !placements.isEmpty()) {
            Placement<A> p = placements.values().iterator().next();
            row.setLineCount(p.getColumnCount());
        } else {
            row.setLineCount(0);
        }
    }

    @Override
    public int getLineIndex(A activity) {
        if (placements != null) {
            Placement<A> placement = placements.get(activity);
            if (placement != null) {
                return placement.getColumnIndex();
            }
        }
        return -1;
    }
}

Types de mise en page

Chaque ligne et chaque ligne interne d’une ligne sont associées à une mise en page. La mise en page influence plusieurs aspects lors du rendu et de la modification des activités. De plus, plusieurs couches système utilisées pour dessiner l’arrière-plan de la ligne utilisent également les informations de mise en page. La mise en page peut être définie en appelant Row.setLayout(Layout) ou, lors de l’utilisation de lignes internes, en les renvoyant via le gestionnaire de lignes de la ligne.

FlexGanttFX inclut trois types de mise en page.

Mise en page Description
GanttLayout Dispose les activités horizontalement le long de la timeline. Les positions sont basées sur les heures de début et de fin des activités.
AgendaLayout Dispose les activités verticalement le long d’une échelle « heure locale » (0 - 24 heures). Les activités ressemblent ainsi à des entrées de calendrier.
ChartLayout Dispose les activités sous forme de valeurs de graphique. Les activités peuvent implémenter l’interface ChartActivity ou HighLowChartActivity.

Padding

Tous les types de mise en page possèdent une propriété de padding. Elle sert à créer un espace visuel en haut et en bas de chaque ligne / ligne interne.

Padding

Mise en page Gantt

Mise en page Gantt

Mise en page Agenda

La classe de mise en page d’agenda sert à disposer les activités dans un style similaire à un calendrier classique, où une échelle verticale affiche les heures. Les activités représentent des rendez-vous pour une journée donnée. Les activités affichées dans une mise en page d’agenda peuvent être rendues plusieurs fois, par exemple lorsqu’une activité s’étend sur plusieurs jours.

Mise en page Agenda

La classe de mise en page d’agenda vous permet de spécifier une heure de début et une heure de fin. Cela sert à restreindre l’intervalle de temps affiché et dans lequel les activités d’agenda sont disposées. Dans la plupart des cas, il n’est pas pertinent d’afficher les 24 heures complètes, mais seulement les heures de travail, par exemple de 8 h à 18 h. Appelez simplement AgendaLayout.setStartTime() ou setEndTime() pour modifier la plage horaire.

Stratégie de conflit

Les activités d’une mise en page d’agenda peuvent se chevaucher. La propriété conflictStrategy vous permet de gérer ces situations. La liste suivante présente les valeurs possibles.

Stratégie Description
OVERLAPPING Les entrées d’agenda en conflit sont dessinées les unes au-dessus des autres, mais l’une d’elles est décalée de quelques pixels. L’amplitude du décalage peut être contrôlée via la propriété overlapOffset sur AgendaLayout.
PARALLEL Les entrées d’agenda en conflit sont affichées dans différentes colonnes au sein de la même journée.

Mise en page de graphique

L’utilisation de la classe ChartLayout dispose les activités sous forme de barres de graphique. Une série de telles barres peut, par exemple, servir à former un profil de capacité. Les activités de type ChartActivity sont placées sur une ligne zéro entre la valeur minimale et la valeur maximale de la mise en page. La hauteur de l’activité de graphique est basée sur la valeur renvoyée par ChartActivity.getChartValue(). Les activités de type HighLowChartActivity apparaissent sous forme de barres flottantes. La mise en page prend également en charge la définition de lignes de graphique mineures et majeures dessinées dans l’arrière-plan de la ligne.

Mise en page de graphique

Valeurs min. et max. – la mise en page de graphique fournit deux propriétés qui contrôlent la disposition réelle des activités de graphique : minValue et maxValue. Ces valeurs doivent être gérées par l’application, et non par le framework. Elles peuvent être définies en appelant ChartLayout.setMinValue() ou ChartLayout.setMaxValue().

Graduations majeures et mineures – une liste de graduations majeures et mineures est disponible sur chaque instance de mise en page de graphique. Des valeurs peuvent être ajoutées à ces listes pour dessiner des lignes de valeur dans l’arrière-plan de la ligne. Exemple : la valeur min est égale à 0 et la valeur max à 100. Il serait alors logique de définir des graduations majeures pour les valeurs 50 et 100. Les graduations mineures pourraient être 10, 20, 30, 40, 60, 70, 80 et 90.

Calendrier

Un calendrier est une extension d’un référentiel d’activités avec en plus un nom et une propriété de visibilité. Les calendriers peuvent être ajoutés à tout le diagramme de Gantt ou à des lignes individuelles du diagramme. De plus, Dateline les utilise.

Dateline.getCalendars();
GraphicsBase.getCalendars();
Row.getCalendars();

Les calendriers sont utilisés pour l’arrière-plan des lignes. Ils peuvent marquer des éléments comme les week-ends ou les jours fériés. Les informations de calendrier sont toujours affichées en lecture seule. Les activités renvoyées par les calendriers doivent être de type CalendarActivity. Elles ne peuvent pas être modifiées interactivement par l’utilisateur.

Calendrier des week-ends

Il existe déjà un type de calendrier prédéfini inclus dans FlexGanttFX. Il s’appelle WeekendCalendar et sert à marquer les jours de week-end (par exemple samedi, dimanche).

Week-end

Le listing suivant montre le code complet de cette classe de calendrier. Il peut servir de base à vos propres calendriers.

/**
 * Copyright (C) 2014 Dirk Lemmermann Software & Consulting (dlsc.com)
 * This file is part of FlexGanttFX.
 */
package com.flexganttfx.model.calendar;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.util.Objects.requireNonNull;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;

import javafx.event.Event;

import com.flexganttfx.model.Layer;
import com.flexganttfx.model.repository.RepositoryEvent;
/**
 * A calendar specialized on returning activities that represent weekend days
 * (default: Saturday, Sunday). The days that are considered weekend days can be
 * configured by calling {@link #setWeekendDays(DayOfWeek...)}.
 *
 * @since 1.0
 */
public class WeekendCalendar extends CalendarBase<WeekendCalendarActivity> {

    private Instant lastStartTime = Instant.MIN;
    private Instant lastEndTime = Instant.MAX;
    private ZoneId lastZoneId;
    private List<WeekendCalendarActivity> entries;
    private EnumSet<DayOfWeek> weekendDays = EnumSet.of(DayOfWeek.SATURDAY,
            DayOfWeek.SUNDAY);
    /**
     * Constructs a new weekend calendar.
     *
     * @since 1.0
     */
    public WeekendCalendar() {
        super("Weekends");
    }

    /**
     * Sets the days of the week that are considered to be a weekend day. By
     * default {@link DayOfWeek#SATURDAY} and {@link DayOfWeek#SUNDAY} are
     * considered weekend days.
     *
     * @param days
     *            the days of the week that are to be considered weekend days
     * @since 1.0
     */
    public void setWeekendDays(DayOfWeek... days) {
        requireNonNull(days);
        weekendDays.clear();
        weekendDays.addAll(Arrays.asList(days));
        Event.fireEvent(this, new RepositoryEvent(this));
    }

    /**
     * Returns the days of the week that are to be considered weekend days. By
     * default {@link DayOfWeek#SATURDAY} and {@link DayOfWeek#SUNDAY} are
     * considered weekend days.
     *
     * @return the days of the week used as weekend days
     * @since 1.0
     */
    public DayOfWeek[] getWeekendDays() {
        return weekendDays.toArray(new DayOfWeek[weekendDays.size()]);
    }

    @Override
    public Iterator<WeekendCalendarActivity> getActivities(Layer layer,
            Instant startTime, Instant endTime, TemporalUnit temporalUnit,
            ZoneId zoneId) {

        if (!(temporalUnit instanceof ChronoUnit)) {
            /*
             * We only work for ChronoUnit.
             */
            return Collections.emptyListIterator();
        }
        if (startTime.equals(lastStartTime) && endTime.equals(lastEndTime)
                && zoneId.equals(lastZoneId)) {
            /*
             * We already answered this query for the given time interval. Let's
             * return the result from last time.
             */
            if (entries != null) {
                return entries.iterator();
            }
        } else {
            ChronoUnit unit = (ChronoUnit) temporalUnit;
            /*
             * The time interval has changed. Find the weekends within the new
             * interval, but only if the user is currently looking at days or
             * weeks.
             */
            if (isSupportedUnit(unit)) {
                /* Lazily create list structure. */
                if (entries == null) {
                    entries = new ArrayList<WeekendCalendarActivity>();
                } else {
                    entries.clear();
                }
                ZonedDateTime st = ZonedDateTime.ofInstant(startTime, zoneId);
                ZonedDateTime et = ZonedDateTime.ofInstant(endTime, zoneId);
                findWeekends(st, et);
                lastStartTime = startTime;
                lastEndTime = endTime;
                lastZoneId = zoneId;
                return entries.iterator();
            }
        }

        return Collections.emptyListIterator();
    }

    /**
     * Determines if weekends will be shown for the given temporal unit.
     * By default, we only show weekends for {@link ChronoUnit#DAYS} and
     * {@link ChronoUnit#WEEKS}. To support more units, override
     * this method in a subclass.
     *
     * @param unit
     *            the unit to check
     * @return true if weekend information will be shown in the Gantt chart
     * @since 1.0
     */
    protected boolean isSupportedUnit(TemporalUnit unit) {
        if (unit instanceof ChronoUnit) {
            ChronoUnit chronoUnit = (ChronoUnit) unit;
            switch (chronoUnit) {
            case DAYS:
            case WEEKS:
                return true;
            default:
                return false;
            }
        }
        return false;
    }

    private void findWeekends(ZonedDateTime st, ZonedDateTime et) {
        while (st.isBefore(et) || st.equals(et)) {
            if (weekendDays.contains(st.getDayOfWeek())) {
                st = st.truncatedTo(DAYS);
                entries.add(new WeekendCalendarActivity(st.getDayOfWeek()
                        .toString(), Instant.from(st), Instant.from(st
                        .plusDays(1)), st.getDayOfWeek()));
            }
            st = st.plusDays(1);
        }
    }
}