diff --git a/README.md b/README.md
index aef75e0..653686b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,45 @@
# miscJar
-Ensemble de fonctions pratiques pour programme java
\ No newline at end of file
+Misc est un atelier pour le développement d'application Java pouvant servir à l'illustration pédagogique.
+
+
+
+Objets de pratiques
+
+ * Log : fonction de trace
+ * Config : gestion de valeurs initiales
+ * Bundle : internationalisation
+ * UpdateSender : alerte sur modification de valeur
+ * ColorCheckedLine : gestion des couleurs d'un terminal pour testes unitaires en mode texte
+
+Fonctions récurrentes
+
+ * Util : ensemble de fonction (souvent graphique) pour factoriser du code
+
+Éléments graphiques
+
+ * SpinnerSlider : couplage d'un curseur (slider) et d'un champ numérique (spinner)
+ * DatePanel : saisie de date
+ * HourPanel : saisie d'heure
+ * ImagePreview : accessoire de visualisation d'image pour dialogue de choix de fichier.
+ * TitledDialog : fenêtre avec gestion d'icône de l'application
+ * HtmlDialog : affichage d'une page HTML dans une application
+ * Guide : outil d’auto-documentation pour surlignant l'action à réaliser dans un scénario d'utilisation
+
+Modèle MVC
+
+ * ApplicationManager : associe la gestion de bouton dans des menus déroulant ou des boîte d'icône
+ * HelpManager : menu d'aide standard avec gestion de langue
+ * ToolBarManager : boîte d'icône détachable
+ * Controler : contrôleur du modèle MVC
+ * ProgressState : gestion de modification du modèle pour connexion d'une barre de progression
+
+Contournement
+
+ * XML : contournement d'un bug d'une version de Java
+
+Réseau
+
+ * CommandLineServer : fonctions générique d'un serveur socket en mode texte
+ * CommandLineWaiter : classe générique à spécialiser en fonction du serveur souhaité
+
diff --git a/ant/build.xml b/ant/build.xml
new file mode 100644
index 0000000..5006243
--- /dev/null
+++ b/ant/build.xml
@@ -0,0 +1,579 @@
+
+
+
+
+
+
+
+
+
+ Java Practice : the chess game, by Dr. F. Merciol (c) 2008
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Chess Game source files]]>
+ Copyright © 2008 Dr. F. Merciol. Tous droits réservés.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/config/BundleManager.xml b/data/config/BundleManager.xml
new file mode 100644
index 0000000..c223597
--- /dev/null
+++ b/data/config/BundleManager.xml
@@ -0,0 +1,38 @@
+
+
+
+This file is automaticaly generated by BundleManager application at 6:58 PM on Aug 17, 2018.
+0
+2
+North
+/mnt/f/home/felix/Travail/IUT/M3101/data/config
+false
+false
+
+[x=50,y=50]
+data/images/bundle/bundle.png
+false
+false
+1
+true
+[x=50,y=50]
+false
+/mnt/sata/stock/nomade/IRISA-UBS/ImageByTrees/src/java/imageByTrees/app
+true
+[x=50,y=50]
+North
+[x=50,y=50]
+North
+
+[x=50,y=50]
+data/log
+true
+[x=50,y=50]
+[x=50,y=50]
+
+false
+South
+true
+true
+false
+
diff --git a/data/config/BundleManager_en_US.properties b/data/config/BundleManager_en_US.properties
new file mode 100644
index 0000000..6425997
--- /dev/null
+++ b/data/config/BundleManager_en_US.properties
@@ -0,0 +1,44 @@
+#Produit automatiquement par BundleManager
+#Thu Jun 30 17:35:12 CEST 2011
+ActionAddKey=add Key
+ActionAddLocale=add Locale
+ActionChangeLocale=Change Locale
+ActionEmpty=New
+ActionFile=File
+ActionInit=Select sources \u2026
+ActionMerge=Merge
+ActionNext=Next String
+ActionOpen=Open \u2026
+ActionQuit=Quit
+ActionRemoveKey=remove Key
+ActionRemoveLocale=remove Locale
+ActionRenameLocale=rename Locale
+ActionSave=Save
+ActionSaveAs=Save As \u2026
+AddKeyTitle=Add new key
+AddLocaleTitle=New locale name\:
+BundleEditorTitle=\ Bundle Editor ({0})
+BundleNotSavedTitle=Bundle not saved
+BundleTitle=\ Bundle Editor
+ExceptionCantLoad=Bundle {0} can''t be loaded\!
+ExceptionCantSave=Bundle {0} can''t be saved\!
+ExceptionDuplicatedKey=Duplicated key {0}\!
+ExceptionDuplicatedLocale=Duplicated locale {0}\!
+HeaderBundleFile=This file is generated automatically by BundleManager
+LabelBundelPropertieFile=bundle properties file
+LabelFileName=File name
+LabelKeys=keys
+LabelLine=Line
+LabelLineNumber=Line Number
+LabelNewKey=New key name\:
+LabelRealyDiscardBundle=Do you want to discard current bundle ?
+LabelSaveBundle=Do you want to save bundle ?
+MessageAddLocale=\ Add Locale
+MessageNoKey=You must have to select one key line\!
+MessageNoLocale=You must have to select one locale column\!
+MessageNoSourceDir=You must choose a directory source before (use Select Sources ...)\!
+MessageRenameLocale=\ Rename Locale
+NoKeyTitle=Can''t determine key
+NoLocaleTitle=Can''t determine locale
+NoSourceTitle=No source
+RenameLocaleTitle=Rename locale
diff --git a/data/config/BundleManager_fr_FR.properties b/data/config/BundleManager_fr_FR.properties
new file mode 100644
index 0000000..1f55e26
--- /dev/null
+++ b/data/config/BundleManager_fr_FR.properties
@@ -0,0 +1,44 @@
+#Produit automatiquement par BundleManager
+#Thu Jun 30 17:35:12 CEST 2011
+ActionAddKey=Ajouter R\u00E9f\u00E9rence
+ActionAddLocale=Ajouter Langue
+ActionChangeLocale=Changer de Langue
+ActionEmpty=Nouveau
+ActionFile=Fichiers
+ActionInit=Choisir Sources \u2026
+ActionMerge=Fusione
+ActionNext=Cha\u00EEne Suivante
+ActionOpen=Ouvrir \u2026
+ActionQuit=Quitter
+ActionRemoveKey=Supprimer R\u00E9f\u00E9rence
+ActionRemoveLocale=Supprimer Langue
+ActionRenameLocale=Renomer Langue
+ActionSave=Sauver
+ActionSaveAs=Sauver sous \u2026
+AddKeyTitle=AJouter une nouvelle r\u00E9f\u00E9rence
+AddLocaleTitle=Nouvelle langue \:
+BundleEditorTitle=\ Editeur de Baluchon (\= propri\u00E9t\u00E9s du programme) ({0})
+BundleNotSavedTitle=Baluchon non sauv\u00E9
+BundleTitle=\ Editeur de baluchon
+ExceptionCantLoad=Impossible de charger {0} \!
+ExceptionCantSave=Impossible de sauver {0} \!
+ExceptionDuplicatedKey=R\u00E9f\u00E9rence {0} en double \!
+ExceptionDuplicatedLocale=Localisation {0} en double \!
+HeaderBundleFile=Produit automatiquement par BundleManager
+LabelBundelPropertieFile=Baluchon de propri\u00E9t\u00E9s (Langue)
+LabelFileName=Nom du fichier
+LabelKeys=R\u00E9f\u00E9rences
+LabelLine=Ligne
+LabelLineNumber=Num\u00E9ro de Ligne
+LabelNewKey=Nouvelle r\u00E9f\u00E9rences \:
+LabelRealyDiscardBundle=Voulez-vous vraiment abandonner les modifications ?
+LabelSaveBundle=Vouslez-vous sauver le baluchon ?
+MessageAddLocale=\ Ajout d''une langue
+MessageNoKey=Vous devez selectionner une ligne de key \!
+MessageNoLocale=Vous devez selectionner une colonne de langue \!
+MessageNoSourceDir=Vous devez d''abord choisir un r\u00E9pertoire de source en utilisant "Choisir Sources ..." \!
+MessageRenameLocale=\ Changement de langue
+NoKeyTitle=Impossible de trouver la r\u00E9f\u00E9rence
+NoLocaleTitle=Impossible de trouver la langue
+NoSourceTitle=Pas de source
+RenameLocaleTitle=Renommer une langue
diff --git a/data/config/Chat.xml b/data/config/Chat.xml
new file mode 100644
index 0000000..095ad39
--- /dev/null
+++ b/data/config/Chat.xml
@@ -0,0 +1,60 @@
+
+
+
+This file is automaticaly generated by Chat application at 8:59 AM on Aug 17, 2018.
+1
+projets.iut-info-vannes.net
+127.0.0.10
+3
+10
+data/images/chat/chat.png
+false
+/
+squidva.univ-ubs.fr
+true
+felix
+10
+[x=50,y=50]
+80
+false
+[x=50,y=50]
+1
+
+
+data/log
+/home/felix
+[x=50,y=50]
+2
+10
+
+10
+1
+64
+false
+8080
+8080
+2
+localhost
+2
+10
+
+
+data/log
+
+10
+127.0.0.1
+3
+false
+false
+[x=50,y=50]
+isa
+2
+inconnu_2212
+SetDodwan
+18
+9090
+10
+10
+3128
+10
+
diff --git a/data/config/Chat_en_AU.properties b/data/config/Chat_en_AU.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_AU.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_CA.properties b/data/config/Chat_en_CA.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_CA.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_GB.properties b/data/config/Chat_en_GB.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_GB.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_IE.properties b/data/config/Chat_en_IE.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_IE.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_IN.properties b/data/config/Chat_en_IN.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_IN.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_MT.properties b/data/config/Chat_en_MT.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_MT.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_NZ.properties b/data/config/Chat_en_NZ.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_NZ.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_PH.properties b/data/config/Chat_en_PH.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_PH.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_SG.properties b/data/config/Chat_en_SG.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_SG.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_en_US.properties b/data/config/Chat_en_US.properties
new file mode 100755
index 0000000..baa6df9
--- /dev/null
+++ b/data/config/Chat_en_US.properties
@@ -0,0 +1,12 @@
+#Produit automatiquement par BundleManager
+#Thu Jun 30 17:41:47 CEST 2011
+ActionClear=Clear
+ActionManageExtention=Managed extention file
+ActionPseudo=Pseudonyme
+ChangePseudoTitle=\ Change login
+ChatNotSavedTitle=\ Chat not saved
+ChatTitle=\ Chat ({0})
+LabelChatFilter=Chat text (.chat)
+LabelNewPseudo=New login
+MessageRealyClearChat=Do you realy want to clear Chat?
+MessageSaveChat=Do you want to save chat?
diff --git a/data/config/Chat_en_ZA.properties b/data/config/Chat_en_ZA.properties
new file mode 120000
index 0000000..bd679fa
--- /dev/null
+++ b/data/config/Chat_en_ZA.properties
@@ -0,0 +1 @@
+Chat_en_US.properties
\ No newline at end of file
diff --git a/data/config/Chat_fr_BE.properties b/data/config/Chat_fr_BE.properties
new file mode 120000
index 0000000..f2d6181
--- /dev/null
+++ b/data/config/Chat_fr_BE.properties
@@ -0,0 +1 @@
+Chat_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Chat_fr_CA.properties b/data/config/Chat_fr_CA.properties
new file mode 120000
index 0000000..f2d6181
--- /dev/null
+++ b/data/config/Chat_fr_CA.properties
@@ -0,0 +1 @@
+Chat_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Chat_fr_CH.properties b/data/config/Chat_fr_CH.properties
new file mode 120000
index 0000000..f2d6181
--- /dev/null
+++ b/data/config/Chat_fr_CH.properties
@@ -0,0 +1 @@
+Chat_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Chat_fr_FR.properties b/data/config/Chat_fr_FR.properties
new file mode 100755
index 0000000..8a1c5c6
--- /dev/null
+++ b/data/config/Chat_fr_FR.properties
@@ -0,0 +1,12 @@
+#Produit automatiquement par BundleManager
+#Thu Jun 30 17:41:47 CEST 2011
+ActionClear=Effacer
+ActionManageExtention=G\u00E9rer l''extension de fichier
+ActionPseudo=Pseudonyme
+ChangePseudoTitle=\ Changer de pseudo
+ChatNotSavedTitle=\ Clavardage non sauv\u00E9
+ChatTitle=\ Clavardage ({0})
+LabelChatFilter=Clavardage (.chat)
+LabelNewPseudo=Nouveau pseudo
+MessageRealyClearChat=Voulez-vous vraiment oublier ce clavardage ?
+MessageSaveChat=Vouvez-vous sauvegarder ce clavardage ?
diff --git a/data/config/Chat_fr_LU.properties b/data/config/Chat_fr_LU.properties
new file mode 120000
index 0000000..f2d6181
--- /dev/null
+++ b/data/config/Chat_fr_LU.properties
@@ -0,0 +1 @@
+Chat_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Controller_br_FR_breton.properties b/data/config/Controller_br_FR_breton.properties
new file mode 100644
index 0000000..961e5c9
--- /dev/null
+++ b/data/config/Controller_br_FR_breton.properties
@@ -0,0 +1,10 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:34:22 CEST 2015
+ActionSave=Enrolla\u00F1\u2026
+ActionEmpty=Nevez
+FileTitle=\ Fichenn
+ActionLoadMessage=Karga\u00F1 ar gemenn\u2026
+ActionSaveAll=Enrolla\u00F1 holl\u2026
+ActionQuit=Kuitaat
+ActionSaveAs=Enrolla\u00F1 dindan\u2026
+ActionOpen=Digeri\u00F1\u2026
diff --git a/data/config/Controller_br_FR_gallo.properties b/data/config/Controller_br_FR_gallo.properties
new file mode 100644
index 0000000..085333e
--- /dev/null
+++ b/data/config/Controller_br_FR_gallo.properties
@@ -0,0 +1,10 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:34:22 CEST 2015
+ActionSave=Garder\u2026
+ActionEmpty=Nouviao
+FileTitle=\ Fichier
+ActionLoadMessage=Charjer le messaije\u2026
+ActionQuit=Qhiter
+ActionSaveAll=Garder tout
+ActionSaveAs=Garder sou\u2026
+ActionOpen=Ouvri\u2026
diff --git a/data/config/Controller_en_US.properties b/data/config/Controller_en_US.properties
new file mode 100644
index 0000000..2153a07
--- /dev/null
+++ b/data/config/Controller_en_US.properties
@@ -0,0 +1,10 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:34:22 CEST 2015
+ActionSave=Save\u2026
+ActionEmpty=Empty
+ActionLoadMessage=Load message\u2026
+FileTitle=\ File
+ActionQuit=Exit
+ActionSaveAll=Save all
+ActionSaveAs=Save as\u2026
+ActionOpen=Open\u2026
diff --git a/data/config/Controller_es_ES.properties b/data/config/Controller_es_ES.properties
new file mode 100644
index 0000000..8ad5ac2
--- /dev/null
+++ b/data/config/Controller_es_ES.properties
@@ -0,0 +1,10 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:34:22 CEST 2015
+ActionEmpty=Nuevo
+ActionLoadMessage=Carga el mensaje\u2026
+ActionOpen=Abrir\u2026
+ActionQuit=Dejar
+ActionSave=Salveguardar\u2026
+ActionSaveAll=Salveguardar todo
+ActionSaveAs=Salveguardar como\u2026
+FileTitle=\ Archivo
diff --git a/data/config/Controller_fr_FR.properties b/data/config/Controller_fr_FR.properties
new file mode 100644
index 0000000..6868a6e
--- /dev/null
+++ b/data/config/Controller_fr_FR.properties
@@ -0,0 +1,10 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:34:22 CEST 2015
+ActionSave=Sauver\u2026
+ActionEmpty=Nouveau
+ActionLoadMessage=Charge le message\u2026
+FileTitle=\ Fichier
+ActionQuit=Quitter
+ActionSaveAll=Sauver tout
+ActionSaveAs=Sauver sous\u2026
+ActionOpen=Ouvrir\u2026
diff --git a/data/config/Help_br_FR_breton.properties b/data/config/Help_br_FR_breton.properties
new file mode 100644
index 0000000..e9571d3
--- /dev/null
+++ b/data/config/Help_br_FR_breton.properties
@@ -0,0 +1,18 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:40:37 CEST 2015
+AboutTitle=\ Diwar-benn
+ActionAbout=Diwar-benn\u2026
+ActionBugReport=Digontammadur\u2026
+ActionClear=FR Effacer
+ActionForcePack=FR Ajuste la fen\u00EAtre
+ActionJConsole=FR Console
+ActionLicence=Aotre
+ActionLocale=Yezh
+ChangeLocaleTitle=\ Che\u00F1chamant yezh
+DumpTitle=\ Choaz ur fichenn roudo\u00F9
+HelpTitle=\ Sikour
+JConsoleTitle=FR Console Java
+LabelDumpFilter=Fichenn roud (.log)
+LicenceTitle=\ Aotre
+LocalizedTitle=\ Etrebroadel
+MessageChooseLocale=Choaz ur yezh
diff --git a/data/config/Help_br_FR_gallo.properties b/data/config/Help_br_FR_gallo.properties
new file mode 100644
index 0000000..65bcae2
--- /dev/null
+++ b/data/config/Help_br_FR_gallo.properties
@@ -0,0 +1,18 @@
+#Produit automatiquement par BundleManager
+#Tue Oct 13 20:07:38 CEST 2015
+AboutTitle=\ Entour du lojici\u00EB ; raport ao...
+ActionAbout=Entour\u2026
+ActionBugReport=D\u00E9pou\u00E9zoner\u2026
+ActionClear=FR Effacer
+ActionForcePack=FR Ajuste la fen\u00EAtre
+ActionJConsole=FR Console
+ActionLicence=Licence
+ActionLocale=Langaije
+ChangeLocaleTitle=\ Chanjer de langue
+DumpTitle=\ chou\u00E9zi un fichier de routes
+HelpTitle=\ A\u00EFde
+JConsoleTitle=FR Console Java
+LabelDumpFilter=Fichier de route (.log)
+LicenceTitle=\ Licence
+LocalizedTitle=\ Empllat
+MessageChooseLocale=Chou\u00E9zi une langue
diff --git a/data/config/Help_en_AU.properties b/data/config/Help_en_AU.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_AU.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_BG.properties b/data/config/Help_en_BG.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_BG.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_CA.properties b/data/config/Help_en_CA.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_CA.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_GB.properties b/data/config/Help_en_GB.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_GB.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_IE.properties b/data/config/Help_en_IE.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_IE.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_IN.properties b/data/config/Help_en_IN.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_IN.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_MT.properties b/data/config/Help_en_MT.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_MT.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_NZ.properties b/data/config/Help_en_NZ.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_NZ.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_PH.properties b/data/config/Help_en_PH.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_PH.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_SG.properties b/data/config/Help_en_SG.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_SG.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_en_US.properties b/data/config/Help_en_US.properties
new file mode 100755
index 0000000..96cb7ae
--- /dev/null
+++ b/data/config/Help_en_US.properties
@@ -0,0 +1,19 @@
+#Produit automatiquement par BundleManager
+#Sat Jun 25 19:24:13 CEST 2011
+#ActionPackBug=Bug: Window.pack
+AboutTitle=\ About
+ActionAbout=About\u2026
+ActionBugReport=Bug repport\u2026
+ActionClear=Clear
+ActionForcePack=Adjust window
+ActionJConsole=Console
+ActionLicence=Licence
+ActionLocale=Locale
+ChangeLocaleTitle=\ Change local
+DumpTitle=\ Dump file chossen
+HelpTitle=\ Help
+JConsoleTitle=Java Console
+LabelDumpFilter=Log file (.log)
+LicenceTitle=\ Licence
+LocalizedTitle= Localized label
+MessageChooseLocale=Choose new locale
diff --git a/data/config/Help_en_ZA.properties b/data/config/Help_en_ZA.properties
new file mode 120000
index 0000000..d0fdcbd
--- /dev/null
+++ b/data/config/Help_en_ZA.properties
@@ -0,0 +1 @@
+Help_en_US.properties
\ No newline at end of file
diff --git a/data/config/Help_es_ES.properties b/data/config/Help_es_ES.properties
new file mode 100644
index 0000000..c5041b8
--- /dev/null
+++ b/data/config/Help_es_ES.properties
@@ -0,0 +1,18 @@
+#Produit automatiquement par BundleManager
+#Sun Feb 04 15:57:59 CET 2018
+LocalizedTitle=\ Internacionalizaci\u00F3n
+ActionAbout=A prop\u00F3sito de\u2026
+ActionLicence=Licencia
+JConsoleTitle=Consola Java
+ActionClear=Borrar
+MessageChooseLocale=Selecciona unidioma
+ActionLocale=Idioma
+ChangeLocaleTitle=\ Cambio de idioma
+LabelDumpFilter=Archivo Log (.log)
+HelpTitle=\ Ayuda
+DumpTitle=\ Elecci\u00F3n de un archivo dump
+LicenceTitle=\ Licencia
+ActionJConsole=Consola
+AboutTitle=\ A prop\u00F3sito de
+ActionBugReport=Depuraci\u00F3n\u2026
+ActionForcePack=Ajusta la ventana
diff --git a/data/config/Help_fr_BE.properties b/data/config/Help_fr_BE.properties
new file mode 120000
index 0000000..40b2de9
--- /dev/null
+++ b/data/config/Help_fr_BE.properties
@@ -0,0 +1 @@
+Help_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Help_fr_CA.properties b/data/config/Help_fr_CA.properties
new file mode 120000
index 0000000..40b2de9
--- /dev/null
+++ b/data/config/Help_fr_CA.properties
@@ -0,0 +1 @@
+Help_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Help_fr_CH.properties b/data/config/Help_fr_CH.properties
new file mode 120000
index 0000000..40b2de9
--- /dev/null
+++ b/data/config/Help_fr_CH.properties
@@ -0,0 +1 @@
+Help_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Help_fr_FR.properties b/data/config/Help_fr_FR.properties
new file mode 100755
index 0000000..1c30112
--- /dev/null
+++ b/data/config/Help_fr_FR.properties
@@ -0,0 +1,19 @@
+#Produit automatiquement par BundleManager
+#Sat Jun 25 19:24:13 CEST 2011
+#ActionPackBug=Anomalie : Window.pack
+AboutTitle=\ A propos
+ActionAbout=A propos\u2026
+ActionBugReport=D\u00E9verminage\u2026
+ActionClear=Effacer
+ActionForcePack=Ajuste la fen\u00EAtre
+ActionJConsole=Console
+ActionLicence=Licence
+ActionLocale=Langage
+ChangeLocaleTitle=\ Changement de langue
+DumpTitle=\ Choix d''un fichier de traces
+HelpTitle=\ Aide
+JConsoleTitle=Console Java
+LabelDumpFilter=Fichier de trace (.log)
+LicenceTitle=\ Licence
+LocalizedTitle=\ Internationalisation
+MessageChooseLocale=Choisissez une langue
diff --git a/data/config/Help_fr_LU.properties b/data/config/Help_fr_LU.properties
new file mode 120000
index 0000000..40b2de9
--- /dev/null
+++ b/data/config/Help_fr_LU.properties
@@ -0,0 +1 @@
+Help_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Login.xml b/data/config/Login.xml
new file mode 100644
index 0000000..72cc4df
--- /dev/null
+++ b/data/config/Login.xml
@@ -0,0 +1,69 @@
+
+
+
+This file is automaticaly generated by Login application at 8:54 AM on Aug 17, 2018.
+1
+0
+3
+127.0.0.10
+data/images/login/login.png
+2
+[x=50,y=50]
+10
+false
+true
+felix
+10
+true
+[x=50,y=50]
+false
+[x=50,y=50]
+false
+1
+
+
+data/log
+[x=50,y=50]
+1
+10
+
+10
+1
+true
+false
+1
+true
+80
+8080
+1
+North
+/
+localhost
+1
+10
+false
+North
+
+
+data/log
+
+10
+projets.iut-info-vannes.net
+false
+1
+2
+false
+false
+North
+[x=50,y=50]
+2
+[x=50,y=50]
+North
+SetClient
+[x=50,y=50]
+10
+10
+10
+[x=50,y=50]
+false
+
diff --git a/data/config/Login_en_US.properties b/data/config/Login_en_US.properties
new file mode 100644
index 0000000..3b48ee1
--- /dev/null
+++ b/data/config/Login_en_US.properties
@@ -0,0 +1,38 @@
+#Produit automatiquement par BundleManager
+#Thu Jun 30 17:50:09 CEST 2011
+ActionAddAdmin=Add administrator
+ActionAddMember=Add member
+#ActionConnect=Connect
+ActionCreateGroup=Create group
+#ActionDisconnect=Disconnect
+ActionEditGroup=Edit group
+ActionEditLogin=Edit profile
+ActionJoinGroup=Join group
+ActionLeftGroup=Left group
+ActionLog=Log
+ActionRemoveAdmin=Remove administrator
+ActionRemoveGroup=Remove group
+ActionRemoveMember=Remove member
+ActionUnlog=Unlog
+GroupTitle=\ Group
+LabelConfirmPasswd=Confirm password\:
+LabelCreatedAt=Created at\:
+LabelEmail=Email\:
+LabelGroup=Group\:
+LabelGroupName=Group name\:
+LabelJoinGroup=Choose a group to join\:
+LabelLogged=Logged\:
+LabelLogin=Login\:
+LabelNewPasswd=New password\:
+LabelOldPasswd=Old password\:
+LabelPassword=Password\:
+LabelState=State\:
+LabelTry=Try n\u00B0\:
+LabelUpdatedAt=Updated at\:
+LabelUpdatedBy=By\:
+LabelUpdatedByIP=Created by (IP@)\:
+LoginTitle=\ Login ({0})
+ConnectionTitle=\ Connection
+ManageGroupTitle=\ Manage Group
+ManageLoginTitle=Manage profile
+anonymous=anonymous
diff --git a/data/config/Login_fr_FR.properties b/data/config/Login_fr_FR.properties
new file mode 100644
index 0000000..cc64cab
--- /dev/null
+++ b/data/config/Login_fr_FR.properties
@@ -0,0 +1,38 @@
+#Produit automatiquement par BundleManager
+#Thu Jun 30 17:50:09 CEST 2011
+#ActionConnect=Connecter
+#ActionDisconnect=D\u00E9connecter
+ActionAddAdmin=Ajoute un administrateur
+ActionAddMember=Ajoute un membre
+ActionCreateGroup=Cr\u00E9er un nouveau groupe
+ActionEditGroup=Modifie un group
+ActionEditLogin=Modifie le profil
+ActionJoinGroup=Rejoindre un groupe
+ActionLeftGroup=Quitter un groupe
+ActionLog=Indetification
+ActionRemoveAdmin=Retire un administrateur
+ActionRemoveGroup=supprime un groupe
+ActionRemoveMember=Retire un membre
+ActionUnlog=Retrai d''identit\u00E9
+ConnectionTitle=\ Connexion
+GroupTitle=\ Groupe
+LabelConfirmPasswd=V\u00E9rification du mot de passe \:
+LabelCreatedAt=Cr\u00E9\u00E9 le \:
+LabelEmail=Mel \:
+LabelGroup=Groupe \:
+LabelGroupName=Nom du groupe \:
+LabelJoinGroup=Choisissez un groupe \u00E0 rejoindre \:
+LabelLogged=Connect\u00E9 \:
+LabelLogin=Pseudonyme \:
+LabelNewPasswd=Nouveau mot de passe \:
+LabelOldPasswd=Ancien mot de passe \:
+LabelPassword=Mot de passe \:
+LabelState=Etat \:
+LabelTry=Essai n\u00B0 \:
+LabelUpdatedAt=Mise \u00E0 jour le \:
+LabelUpdatedBy=Par \:
+LabelUpdatedByIP=Cr\u00E9\u00E9 par (@ IP) \:
+LoginTitle=\ Connexion ({0})
+ManageGroupTitle=\ Gestion des groupes
+ManageLoginTitle=Gestion du profil
+anonymous=inconnu
diff --git a/data/config/Misc.xml b/data/config/Misc.xml
new file mode 100644
index 0000000..e0657a8
--- /dev/null
+++ b/data/config/Misc.xml
@@ -0,0 +1,17 @@
+
+
+
+This file is automaticaly generated by Misc application at 10:48 AM on Jan 28, 2021.
+
+[x=50,y=50]
+[x=50,y=50]
+[x=50,y=50]
+false
+false
+false
+[x=50,y=50]
+
+
+data/images/misc.png
+false
+
diff --git a/data/config/Protocol_en_US.properties b/data/config/Protocol_en_US.properties
new file mode 100644
index 0000000..89f0268
--- /dev/null
+++ b/data/config/Protocol_en_US.properties
@@ -0,0 +1,11 @@
+ActionLinkType=Link network
+ActionPublishDodwan=Publish
+ActionSetClient=Client
+ActionSetDodwan=Dodwan
+ActionSetProxy=Proxy
+ActionSetServer=Server
+ActionUnsetProtocol=None
+LabelAvailableNetworkCard=Your network cards\:
+LabelConnectionType=What kind of connexion do you want?
+LinkTypeTitle=\ Connection type manager
+NetworkTitle=\ Network
diff --git a/data/config/Protocol_fr_FR.properties b/data/config/Protocol_fr_FR.properties
new file mode 100644
index 0000000..544ee8c
--- /dev/null
+++ b/data/config/Protocol_fr_FR.properties
@@ -0,0 +1,11 @@
+ActionLinkType=Relier le r\u00E9seau
+ActionPublishDodwan=Publier
+ActionSetClient=Client
+ActionSetDodwan=Dodwan
+ActionSetProxy=Mandataire
+ActionSetServer=Serveur
+ActionUnsetProtocol=Aucun
+LabelAvailableNetworkCard=Vos cartes r\u00E9seau \:
+LabelConnectionType=Quel type de connexion souhaitez-vous ?
+LinkTypeTitle=\ Gestionnaire du type de connexion
+NetworkTitle=\ R\u00E9seau
diff --git a/data/config/Proxy_br_FR_breton.properties b/data/config/Proxy_br_FR_breton.properties
new file mode 100644
index 0000000..3169988
--- /dev/null
+++ b/data/config/Proxy_br_FR_breton.properties
@@ -0,0 +1,7 @@
+ActionSetProxy=FR Configuration r\u00E9seau\u2026
+ProxyTitle=FR Configuration R\u00e9seau (Proxy)
+LabelHost=FR Serveur du mandataire \:
+LabelPort=FR Port du mandataire \:
+ActionNoProxy=FR Ne pas utiliser de Mandataire
+ActionSystemConfigProxy=FR Utiliser la configuration Java du mandataire
+ActionManualConfigProxy=FR D\u00E9finir manuellement la configuration du mandataire
diff --git a/data/config/Proxy_br_FR_gallo.properties b/data/config/Proxy_br_FR_gallo.properties
new file mode 100644
index 0000000..3169988
--- /dev/null
+++ b/data/config/Proxy_br_FR_gallo.properties
@@ -0,0 +1,7 @@
+ActionSetProxy=FR Configuration r\u00E9seau\u2026
+ProxyTitle=FR Configuration R\u00e9seau (Proxy)
+LabelHost=FR Serveur du mandataire \:
+LabelPort=FR Port du mandataire \:
+ActionNoProxy=FR Ne pas utiliser de Mandataire
+ActionSystemConfigProxy=FR Utiliser la configuration Java du mandataire
+ActionManualConfigProxy=FR D\u00E9finir manuellement la configuration du mandataire
diff --git a/data/config/Proxy_en_AU.properties b/data/config/Proxy_en_AU.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_AU.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_BG.properties b/data/config/Proxy_en_BG.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_BG.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_CA.properties b/data/config/Proxy_en_CA.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_CA.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_GB.properties b/data/config/Proxy_en_GB.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_GB.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_IE.properties b/data/config/Proxy_en_IE.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_IE.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_IN.properties b/data/config/Proxy_en_IN.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_IN.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_MT.properties b/data/config/Proxy_en_MT.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_MT.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_NZ.properties b/data/config/Proxy_en_NZ.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_NZ.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_PH.properties b/data/config/Proxy_en_PH.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_PH.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_SG.properties b/data/config/Proxy_en_SG.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_SG.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_en_US.properties b/data/config/Proxy_en_US.properties
new file mode 100755
index 0000000..2b166ed
--- /dev/null
+++ b/data/config/Proxy_en_US.properties
@@ -0,0 +1,7 @@
+ActionSetProxy=Network configuration
+ProxyTitle=Network configuration
+LabelHost=Host\:
+LabelPort=Port\:
+ActionNoProxy=Use no proxy
+ActionSystemConfigProxy=Use Java VM proxy configuration
+ActionManualConfigProxy=Manual proxy definition
diff --git a/data/config/Proxy_en_ZA.properties b/data/config/Proxy_en_ZA.properties
new file mode 120000
index 0000000..5050b62
--- /dev/null
+++ b/data/config/Proxy_en_ZA.properties
@@ -0,0 +1 @@
+Proxy_en_US.properties
\ No newline at end of file
diff --git a/data/config/Proxy_es_ES.properties b/data/config/Proxy_es_ES.properties
new file mode 100644
index 0000000..741a2d8
--- /dev/null
+++ b/data/config/Proxy_es_ES.properties
@@ -0,0 +1,9 @@
+#Produit automatiquement par BundleManager
+#Sun Feb 04 16:05:53 CET 2018
+ActionNoProxy=No utilizar proxy
+ActionSetProxy=Configuraci\u00F3n de red
+LabelHost=Servidor proxy \:
+ProxyTitle=CConfiguraci\u00F3n de red (Proxy)
+ActionSystemConfigProxy=Utilizar la configuraci\u00F3n Java VM del proxy
+ActionManualConfigProxy=Especificar manualmente las opciones del proxy
+LabelPort=Puerto de proxy \:
diff --git a/data/config/Proxy_fr_BE.properties b/data/config/Proxy_fr_BE.properties
new file mode 120000
index 0000000..e261976
--- /dev/null
+++ b/data/config/Proxy_fr_BE.properties
@@ -0,0 +1 @@
+Proxy_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Proxy_fr_CA.properties b/data/config/Proxy_fr_CA.properties
new file mode 120000
index 0000000..e261976
--- /dev/null
+++ b/data/config/Proxy_fr_CA.properties
@@ -0,0 +1 @@
+Proxy_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Proxy_fr_CH.properties b/data/config/Proxy_fr_CH.properties
new file mode 120000
index 0000000..e261976
--- /dev/null
+++ b/data/config/Proxy_fr_CH.properties
@@ -0,0 +1 @@
+Proxy_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Proxy_fr_FR.properties b/data/config/Proxy_fr_FR.properties
new file mode 100755
index 0000000..3e6341a
--- /dev/null
+++ b/data/config/Proxy_fr_FR.properties
@@ -0,0 +1,7 @@
+ActionSetProxy=Configuration r\u00E9seau\u2026
+ProxyTitle=Configuration R\u00e9seau (Proxy)
+LabelHost=Serveur du mandataire \:
+LabelPort=Port du mandataire \:
+ActionNoProxy=Ne pas utiliser de Mandataire
+ActionSystemConfigProxy=Utiliser la configuration Java du mandataire
+ActionManualConfigProxy=D\u00E9finir manuellement la configuration du mandataire
diff --git a/data/config/Proxy_fr_LU.properties b/data/config/Proxy_fr_LU.properties
new file mode 120000
index 0000000..e261976
--- /dev/null
+++ b/data/config/Proxy_fr_LU.properties
@@ -0,0 +1 @@
+Proxy_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_br_FR_breton.properties b/data/config/RemoteUpdate_br_FR_breton.properties
new file mode 100644
index 0000000..638269a
--- /dev/null
+++ b/data/config/RemoteUpdate_br_FR_breton.properties
@@ -0,0 +1,36 @@
+#Produit automatiquement par BundleManager
+#Sat Feb 03 16:17:07 CET 2018
+ActionUpload=FR T\u00E9l\u00E9versement
+LabelLocalDate=FR Date local
+EnumCheckPeriodMonth=Miz
+EnumCheckPeriodYear=Bloavezh
+LabelRemove=FR Supprim\u00E9
+ActionOnline=FR Mise en ligne\u2026
+ActionLocalRemove=FR Nettoyer fichiers locaux
+MessageUploadCompleted=FR {0,choice,0\# Aucun t\u00E9l\u00E9verssement|0< {0} fichiers t\u00E9l\u00E9vers\u00E9s.}
+LabelLocal=FR Local
+EnumCheckPeriodWeek=Sizhun
+LabelFileName=FR Fichier
+EnumCheckPeriodDay=Deiz
+UpdateSoftTitle=FR Mise \u00E0 jour
+LabelRemoteSize=FR Taille distante
+MessageDownloadInfo={0} \: {1,choice,0\# (FR pas de serveur)|0< '{2,choice,0\# 0 fichenn|1\# 1 fichenn|1< {2,number,integer} fichenno\u00F9}' ({3}o)}
+LabelRemote=FR Distant
+ActionDetails=FR D\u00E9tails\u2026
+DownloadTitle=\ Pellgarga\u00F1 bremanaduro\u00F9
+MessageUpload=FR T\u00E9l\u00E9versement
+LabelDownload=FR T\u00E9l\u00E9charg\u00E9
+ActionUpdate=Bremanadur\u2026
+MessageDownloadCompleted={0,choice,0\# ebet pellgarga\u00F1|0< {0} fichenno\u00F9 pellgarget. Kuitaat hag adla\u00F1sa\u00F1 ar poellad.}
+MessageLocalRemove=FR Nettoyage local
+LabelRemoteDate=FR Date distante
+ActionDownload=FR T\u00E9l\u00E9chargement
+MessageUpdateSoft=FR Relancer la nouvelle version
+EnumCheckPeriodNoCheck=Gwech ebet
+LabelLocalSize=FR Taille local
+DetailsTitle=FR D\u00E9tails
+ActionRemoteRemove=FR Nettoyer fichiers distants
+LabelCheckingPeriod=Gwiria\u00F1 bremanadurio\u00F9 \:
+MessageDownload=Pellgarga\u00F1
+UploadTitle=FR T\u00E9l\u00E9versement
+LabelUpload=FR T\u00E9l\u00E9vers\u00E9
diff --git a/data/config/RemoteUpdate_br_FR_gallo.properties b/data/config/RemoteUpdate_br_FR_gallo.properties
new file mode 100644
index 0000000..0528aa6
--- /dev/null
+++ b/data/config/RemoteUpdate_br_FR_gallo.properties
@@ -0,0 +1,35 @@
+#Produit automatiquement par BundleManager
+#Sat Feb 03 16:17:07 CET 2018
+ActionUpload=FR T\u00E9l\u00E9versement
+LabelLocalDate=FR Date local
+EnumCheckPeriodMonth=Mou\u00E9z
+EnumCheckPeriodYear=An\u00E9e
+LabelRemove=FR Supprim\u00E9
+ActionOnline=FR Mise en ligne\u2026
+ActionLocalRemove=FR Nettoyer fichiers locaux
+MessageUploadCompleted=FR {0,choice,0\# Aucun t\u00E9l\u00E9verssement|0< {0} fichiers t\u00E9l\u00E9vers\u00E9s.}
+LabelLocal=FR Local
+EnumCheckPeriodWeek=Smaine
+LabelFileName=FR Fichier
+EnumCheckPeriodDay=Jou
+UpdateSoftTitle=FR Mise \u00E0 jour
+LabelRemoteSize=FR Taille distante
+MessageDownloadInfo=FR {0} \: {1,choice,0\# pas de serveur|0< '{2,choice,0\# pas de fichier|1\# 1 fichier|1< {2,number,integer} fichiers}' ({3}o)
+LabelRemote=FR Distant
+DownloadTitle=\ Telecharjer les abuteries
+MessageUpload=FR T\u00E9l\u00E9versement
+MessageDownloadCompleted=FR {0,choice,0\# Aucun t\u00E9l\u00E9chargement|0< {0} fichiers t\u00E9l\u00E9charg\u00E9s.\n Vous devez quitter et relancer le logiciel.}
+LabelDownload=FR T\u00E9l\u00E9charg\u00E9
+ActionUpdate=Abuter\u2026
+MessageLocalRemove=FR Nettoyage local
+LabelRemoteDate=FR Date distante
+ActionDownload=FR T\u00E9l\u00E9chargement
+MessageUpdateSoft=FR Relancer la nouvelle version
+EnumCheckPeriodNoCheck=Pas jam\u00E9s
+LabelLocalSize=FR Taille local
+DetailsTitle=FR D\u00E9tails
+ActionRemoteRemove=FR Nettoyer fichiers distants
+LabelCheckingPeriod=Ergarder \u00E9s abuteries \:
+UploadTitle=FR T\u00E9l\u00E9versement
+MessageDownload=T\u00E9l\u00E9charjer
+LabelUpload=FR T\u00E9l\u00E9vers\u00E9
diff --git a/data/config/RemoteUpdate_en_AU.properties b/data/config/RemoteUpdate_en_AU.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_AU.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_BG.properties b/data/config/RemoteUpdate_en_BG.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_BG.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_CA.properties b/data/config/RemoteUpdate_en_CA.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_CA.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_GB.properties b/data/config/RemoteUpdate_en_GB.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_GB.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_IE.properties b/data/config/RemoteUpdate_en_IE.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_IE.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_IN.properties b/data/config/RemoteUpdate_en_IN.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_IN.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_MT.properties b/data/config/RemoteUpdate_en_MT.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_MT.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_NZ.properties b/data/config/RemoteUpdate_en_NZ.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_NZ.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_PH.properties b/data/config/RemoteUpdate_en_PH.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_PH.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_SG.properties b/data/config/RemoteUpdate_en_SG.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_SG.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_en_US.properties b/data/config/RemoteUpdate_en_US.properties
new file mode 100755
index 0000000..86739ec
--- /dev/null
+++ b/data/config/RemoteUpdate_en_US.properties
@@ -0,0 +1,35 @@
+#Produit automatiquement par BundleManager
+#Sat Feb 03 16:17:07 CET 2018
+ActionUpload=Upload
+LabelLocalDate=Local date
+LabelRemove=Removed
+EnumCheckPeriodMonth=Month
+EnumCheckPeriodYear=Year
+ActionOnline=Online\u2026
+ActionLocalRemove=Clean local files
+MessageUploadCompleted={0,choice,0\# No upload|0< {0} files to upload}.
+LabelLocal=Local
+EnumCheckPeriodWeek=Week
+LabelFileName=File
+EnumCheckPeriodDay=Day
+UpdateSoftTitle=Update soft needed
+LabelRemoteSize=Remote size
+MessageDownloadInfo={0}\: {1,choice,0\#Server not responding|0< '{2,choice,0\# no file|1\# 1 file|1< {2,number,integer} files}' ({3}B)}
+LabelRemote=Remote
+ActionDetails=Details\u2026
+DownloadTitle=Download update
+MessageUpload=Upload
+MessageDownloadCompleted={0,choice,0\# No upload|0< {0} files uploaded.}
+ActionUpdate=Update\u2026
+LabelDownload=Downloaded
+LabelRemoteDate=Remote date
+ActionDownload=Download
+MessageUpdateSoft=Restart now
+LabelLocalSize=Local size
+DetailsTitle=Details
+EnumCheckPeriodNoCheck=Never
+ActionRemoteRemove=Clean remote files
+LabelCheckingPeriod=Cheking update\:
+UploadTitle=\ Upload
+MessageDownload=Download
+LabelUpload=Uploaded
diff --git a/data/config/RemoteUpdate_en_ZA.properties b/data/config/RemoteUpdate_en_ZA.properties
new file mode 120000
index 0000000..057d0a9
--- /dev/null
+++ b/data/config/RemoteUpdate_en_ZA.properties
@@ -0,0 +1 @@
+RemoteUpdate_en_US.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_es_ES.properties b/data/config/RemoteUpdate_es_ES.properties
new file mode 100644
index 0000000..1697afa
--- /dev/null
+++ b/data/config/RemoteUpdate_es_ES.properties
@@ -0,0 +1,36 @@
+!#Produit automatiquement par BundleManager
+#Sun Feb 04 16:11:51 CET 2018
+ActionUpload=Cargar
+LabelLocalDate=Data local
+LabelRemove=Borrado
+EnumCheckPeriodMonth=Mes
+EnumCheckPeriodYear=A\u00F1o
+ActionOnline=Puesta en l\u00EDnea\u2026
+ActionLocalRemove=Limpiar los archives locales
+MessageUploadCompleted={0,choice,0\# Ningunacarga|0< {0} archivos cargados}
+LabelLocal=Local
+EnumCheckPeriodWeek=Semana
+LabelFileName=Archivo
+EnumCheckPeriodDay=D\u00EDa
+UpdateSoftTitle=UpdateSoftTitle
+LabelRemoteSize=Tama\u00F1o Remoto
+MessageDownloadInfo={0}\: {1,choice,0\#Server not responding|0< '{2,choice,0\# no file|1\# 1 file|1< {2,number,integer} files}' ({3}B)}
+LabelRemote=Remoto
+ActionDetails=Detalles\u2026
+DownloadTitle=Descarga de las actualizaciones
+MessageUpload=Carga
+MessageDownloadCompleted={0,choice,0\# No upload|0< {0} files uploaded.}
+ActionUpdate=Actualizaci\u00F3n\u2026
+LabelDownload=Descargado
+MessageLocalRemove=MessageLocalRemove
+LabelRemoteDate=Data Remoto
+ActionDownload=Descarga
+MessageUpdateSoft=MessageUpdateSoft
+LabelLocalSize=Tama\u00F1o local
+DetailsTitle=Detalles
+EnumCheckPeriodNoCheck=Nunca
+ActionRemoteRemove=Limpiar los archivos remotos
+LabelCheckingPeriod=Verificaci\u00F3n de las actualizaciones \:
+UploadTitle=Carga
+MessageDownload=Descarga
+LabelUpload=Cargado
diff --git a/data/config/RemoteUpdate_fr_BE.properties b/data/config/RemoteUpdate_fr_BE.properties
new file mode 120000
index 0000000..c0a598c
--- /dev/null
+++ b/data/config/RemoteUpdate_fr_BE.properties
@@ -0,0 +1 @@
+RemoteUpdate_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_fr_CA.properties b/data/config/RemoteUpdate_fr_CA.properties
new file mode 120000
index 0000000..c0a598c
--- /dev/null
+++ b/data/config/RemoteUpdate_fr_CA.properties
@@ -0,0 +1 @@
+RemoteUpdate_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_fr_CH.properties b/data/config/RemoteUpdate_fr_CH.properties
new file mode 120000
index 0000000..c0a598c
--- /dev/null
+++ b/data/config/RemoteUpdate_fr_CH.properties
@@ -0,0 +1 @@
+RemoteUpdate_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/RemoteUpdate_fr_FR.properties b/data/config/RemoteUpdate_fr_FR.properties
new file mode 100755
index 0000000..d0b4aca
--- /dev/null
+++ b/data/config/RemoteUpdate_fr_FR.properties
@@ -0,0 +1,36 @@
+#Produit automatiquement par BundleManager
+#Sat Feb 03 16:17:07 CET 2018
+ActionUpload=T\u00E9l\u00E9versement
+LabelLocalDate=Date local
+LabelRemove=Supprim\u00E9
+EnumCheckPeriodMonth=Mois
+EnumCheckPeriodYear=Ann\u00E9e
+ActionOnline=Mise en ligne\u2026
+ActionLocalRemove=Nettoyer fichiers locaux
+MessageUploadCompleted={0,choice,0\# Aucun t\u00E9l\u00E9verssement|0< {0} fichiers t\u00E9l\u00E9vers\u00E9s}.
+LabelLocal=Local
+EnumCheckPeriodWeek=Semaine
+LabelFileName=Fichier
+EnumCheckPeriodDay=Jour
+UpdateSoftTitle=Mise \u00E0 jour
+LabelRemoteSize=Taille distante
+MessageDownloadInfo={0} \: {1,choice,0\# Le serveur ne r\u00E9pond pas|0< '{2,choice,0\# pas de fichier|1\# 1 fichier|1< {2,number,integer} fichiers}' ({3}o)}
+LabelRemote=Distant
+ActionDetails=D\u00E9tails\u2026
+DownloadTitle=T\u00E9l\u00E9chargement des mises \u00E0 jour
+MessageUpload=T\u00E9l\u00E9versement
+MessageDownloadCompleted={0,choice,0\# Aucun t\u00E9l\u00E9chargement|0< {0} fichiers t\u00E9l\u00E9charg\u00E9s.\n Vous devez quitter et relancer le logiciel.}
+ActionUpdate=Mise \u00E0 jour\u2026
+LabelDownload=T\u00E9l\u00E9charg\u00E9
+MessageLocalRemove=Nettoyage local
+LabelRemoteDate=Date distante
+ActionDownload=T\u00E9l\u00E9chargement
+MessageUpdateSoft=Relancer la nouvelle version ? \n (si ce message revient lancez UpdatedAdecWatt.jar)
+LabelLocalSize=Taille local
+DetailsTitle=D\u00E9tails
+EnumCheckPeriodNoCheck=Jamais
+ActionRemoteRemove=Nettoyer fichiers distants
+LabelCheckingPeriod=V\u00E9rification des mises \u00E0 jour \:
+UploadTitle=\ T\u00E9l\u00E9versement
+MessageDownload=T\u00E9l\u00E9chargement
+LabelUpload=T\u00E9l\u00E9vers\u00E9
diff --git a/data/config/RemoteUpdate_fr_LU.properties b/data/config/RemoteUpdate_fr_LU.properties
new file mode 120000
index 0000000..c0a598c
--- /dev/null
+++ b/data/config/RemoteUpdate_fr_LU.properties
@@ -0,0 +1 @@
+RemoteUpdate_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Story_br_FR_breton.properties b/data/config/Story_br_FR_breton.properties
new file mode 100644
index 0000000..8bae49f
--- /dev/null
+++ b/data/config/Story_br_FR_breton.properties
@@ -0,0 +1,4 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:46:00 CEST 2015
+ActionUndo=Dispenn
+ActionRedo=Adkregi\u00F1
diff --git a/data/config/Story_br_FR_gallo.properties b/data/config/Story_br_FR_gallo.properties
new file mode 100644
index 0000000..d803e64
--- /dev/null
+++ b/data/config/Story_br_FR_gallo.properties
@@ -0,0 +1,4 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:46:00 CEST 2015
+ActionUndo=D\u00E9marrer
+ActionRedo=Erf\u00E9re
diff --git a/data/config/Story_en_AU.properties b/data/config/Story_en_AU.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_AU.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_BG.properties b/data/config/Story_en_BG.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_BG.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_CA.properties b/data/config/Story_en_CA.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_CA.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_GB.properties b/data/config/Story_en_GB.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_GB.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_IE.properties b/data/config/Story_en_IE.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_IE.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_IN.properties b/data/config/Story_en_IN.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_IN.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_MT.properties b/data/config/Story_en_MT.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_MT.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_NZ.properties b/data/config/Story_en_NZ.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_NZ.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_PH.properties b/data/config/Story_en_PH.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_PH.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_SG.properties b/data/config/Story_en_SG.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_SG.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_en_US.properties b/data/config/Story_en_US.properties
new file mode 100755
index 0000000..c2af387
--- /dev/null
+++ b/data/config/Story_en_US.properties
@@ -0,0 +1,2 @@
+ActionRedo=Redo
+ActionUndo=Undo
diff --git a/data/config/Story_en_ZA.properties b/data/config/Story_en_ZA.properties
new file mode 120000
index 0000000..a4ee065
--- /dev/null
+++ b/data/config/Story_en_ZA.properties
@@ -0,0 +1 @@
+Story_en_US.properties
\ No newline at end of file
diff --git a/data/config/Story_es_ES.properties b/data/config/Story_es_ES.properties
new file mode 100644
index 0000000..728059a
--- /dev/null
+++ b/data/config/Story_es_ES.properties
@@ -0,0 +1,2 @@
+ActionRedo=Repetir
+ActionUndo=Deshacer
diff --git a/data/config/Story_fr_BE.properties b/data/config/Story_fr_BE.properties
new file mode 120000
index 0000000..9f4d1cc
--- /dev/null
+++ b/data/config/Story_fr_BE.properties
@@ -0,0 +1 @@
+Story_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Story_fr_CA.properties b/data/config/Story_fr_CA.properties
new file mode 120000
index 0000000..9f4d1cc
--- /dev/null
+++ b/data/config/Story_fr_CA.properties
@@ -0,0 +1 @@
+Story_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Story_fr_CH.properties b/data/config/Story_fr_CH.properties
new file mode 120000
index 0000000..9f4d1cc
--- /dev/null
+++ b/data/config/Story_fr_CH.properties
@@ -0,0 +1 @@
+Story_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/Story_fr_FR.properties b/data/config/Story_fr_FR.properties
new file mode 100755
index 0000000..2931fb4
--- /dev/null
+++ b/data/config/Story_fr_FR.properties
@@ -0,0 +1,2 @@
+ActionRedo=Refaire
+ActionUndo=D\u00E9faire
diff --git a/data/config/Story_fr_LU.properties b/data/config/Story_fr_LU.properties
new file mode 120000
index 0000000..9f4d1cc
--- /dev/null
+++ b/data/config/Story_fr_LU.properties
@@ -0,0 +1 @@
+Story_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_br_FR_breton.properties b/data/config/ToolBar_br_FR_breton.properties
new file mode 100644
index 0000000..c38e2f9
--- /dev/null
+++ b/data/config/ToolBar_br_FR_breton.properties
@@ -0,0 +1,9 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:49:15 CEST 2015
+NotCardinalPoint=FR {0} n''est pas un point cardinal \!
+ActionUp=Pignat
+AlreadyRegistredTool=Barre d\u00E9tachable {0} d\u00E9j\u00E0 enregistr\u00E9e au {1} \!
+LabelToolBarNamed=Barrenno\u00F9 oustilho\u00F9
+ActionDown=Diskenn
+LabelToolBarShowed=Diskouez
+ActionToolBarProfil=Mererezh barrenno\u00F9 oustilho\u00F9\u2026
diff --git a/data/config/ToolBar_br_FR_gallo.properties b/data/config/ToolBar_br_FR_gallo.properties
new file mode 100644
index 0000000..bbe3f6a
--- /dev/null
+++ b/data/config/ToolBar_br_FR_gallo.properties
@@ -0,0 +1,9 @@
+#Produit automatiquement par BundleManager
+#Sat Oct 03 19:49:15 CEST 2015
+NotCardinalPoint=FR {0} n''est pas un point cardinal \!
+ActionUp=Aler olmont
+AlreadyRegistredTool=FR Barre d\u00E9tachable {0} d\u00E9j\u00E0 enregistr\u00E9e au {1} \!
+ActionDown=Aler olva
+LabelToolBarNamed=Bare \u00E9s outis
+LabelToolBarShowed=Amontr\u00EB
+ActionToolBarProfil=Se chevi de la bare \u00E9s outis\u2026
diff --git a/data/config/ToolBar_en_AU.properties b/data/config/ToolBar_en_AU.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_AU.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_BG.properties b/data/config/ToolBar_en_BG.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_BG.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_CA.properties b/data/config/ToolBar_en_CA.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_CA.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_GB.properties b/data/config/ToolBar_en_GB.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_GB.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_IE.properties b/data/config/ToolBar_en_IE.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_IE.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_IN.properties b/data/config/ToolBar_en_IN.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_IN.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_MT.properties b/data/config/ToolBar_en_MT.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_MT.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_NZ.properties b/data/config/ToolBar_en_NZ.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_NZ.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_PH.properties b/data/config/ToolBar_en_PH.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_PH.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_SG.properties b/data/config/ToolBar_en_SG.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_SG.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_en_US.properties b/data/config/ToolBar_en_US.properties
new file mode 100755
index 0000000..8160ed2
--- /dev/null
+++ b/data/config/ToolBar_en_US.properties
@@ -0,0 +1,9 @@
+#Produit automatiquement par BundleManager
+#Fri Oct 02 10:48:46 CEST 2015
+NotCardinalPoint={0} is not a cardinal point\!
+AlreadyRegistredTool=ToolBar {0} already regitered at {1}\!
+ActionUp=Up
+ActionDown=Down
+LabelToolBarNamed=Tool bar
+LabelToolBarShowed=Showed
+ActionToolBarProfil=Tool bar managment\u2026
diff --git a/data/config/ToolBar_en_ZA.properties b/data/config/ToolBar_en_ZA.properties
new file mode 120000
index 0000000..bac78cd
--- /dev/null
+++ b/data/config/ToolBar_en_ZA.properties
@@ -0,0 +1 @@
+ToolBar_en_US.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_es_ES.properties b/data/config/ToolBar_es_ES.properties
new file mode 100644
index 0000000..ea29cbe
--- /dev/null
+++ b/data/config/ToolBar_es_ES.properties
@@ -0,0 +1,9 @@
+#Produit automatiquement par BundleManager
+#Sun Feb 04 16:01:44 CET 2018
+NotCardinalPoint={0} no es un punto cardinal \!
+ActionUp=Arriba
+AlreadyRegistredTool=Barra de herramientas {0} ya registrada en {1} \!
+LabelToolBarNamed=Barra de herramientas
+ActionDown=Abajo
+LabelToolBarShowed=Ense\u00F1a
+ActionToolBarProfil=Gesti\u00F3n de las barras de herramientas\u2026
diff --git a/data/config/ToolBar_fr_BE.properties b/data/config/ToolBar_fr_BE.properties
new file mode 120000
index 0000000..7a113da
--- /dev/null
+++ b/data/config/ToolBar_fr_BE.properties
@@ -0,0 +1 @@
+ToolBar_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_fr_CA.properties b/data/config/ToolBar_fr_CA.properties
new file mode 120000
index 0000000..7a113da
--- /dev/null
+++ b/data/config/ToolBar_fr_CA.properties
@@ -0,0 +1 @@
+ToolBar_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_fr_CH.properties b/data/config/ToolBar_fr_CH.properties
new file mode 120000
index 0000000..7a113da
--- /dev/null
+++ b/data/config/ToolBar_fr_CH.properties
@@ -0,0 +1 @@
+ToolBar_fr_FR.properties
\ No newline at end of file
diff --git a/data/config/ToolBar_fr_FR.properties b/data/config/ToolBar_fr_FR.properties
new file mode 100755
index 0000000..c5f9b55
--- /dev/null
+++ b/data/config/ToolBar_fr_FR.properties
@@ -0,0 +1,9 @@
+#Produit automatiquement par BundleManager
+#Fri Oct 02 10:48:46 CEST 2015
+NotCardinalPoint={0} n''est pas un point cardinal \!
+AlreadyRegistredTool=Barre d\u00E9tachable {0} d\u00E9j\u00E0 enregistr\u00E9e au {1} \!
+ActionUp=Monter
+ActionDown=Descendre
+LabelToolBarNamed=Barre d''outils
+LabelToolBarShowed=Montr\u00E9e
+ActionToolBarProfil=Gestion des barres d''outils \u2026
diff --git a/data/config/ToolBar_fr_LU.properties b/data/config/ToolBar_fr_LU.properties
new file mode 120000
index 0000000..7a113da
--- /dev/null
+++ b/data/config/ToolBar_fr_LU.properties
@@ -0,0 +1 @@
+ToolBar_fr_FR.properties
\ No newline at end of file
diff --git a/data/images/bundle/bundle.png b/data/images/bundle/bundle.png
new file mode 100644
index 0000000..829f1f9
Binary files /dev/null and b/data/images/bundle/bundle.png differ
diff --git a/data/images/button/Abort.png b/data/images/button/Abort.png
new file mode 100644
index 0000000..d76f030
Binary files /dev/null and b/data/images/button/Abort.png differ
diff --git a/data/images/button/About.png b/data/images/button/About.png
new file mode 100644
index 0000000..04e71de
Binary files /dev/null and b/data/images/button/About.png differ
diff --git a/data/images/button/AddKey.png b/data/images/button/AddKey.png
new file mode 100644
index 0000000..fa0510a
Binary files /dev/null and b/data/images/button/AddKey.png differ
diff --git a/data/images/button/AddLocale.png b/data/images/button/AddLocale.png
new file mode 100644
index 0000000..71fb5e4
Binary files /dev/null and b/data/images/button/AddLocale.png differ
diff --git a/data/images/button/Bad.png b/data/images/button/Bad.png
new file mode 100644
index 0000000..5196d43
Binary files /dev/null and b/data/images/button/Bad.png differ
diff --git a/data/images/button/Begin.png b/data/images/button/Begin.png
new file mode 100644
index 0000000..5f06866
Binary files /dev/null and b/data/images/button/Begin.png differ
diff --git a/data/images/button/Black.png b/data/images/button/Black.png
new file mode 100644
index 0000000..b0974cb
Binary files /dev/null and b/data/images/button/Black.png differ
diff --git a/data/images/button/BugReport.png b/data/images/button/BugReport.png
new file mode 100644
index 0000000..44c7ae1
Binary files /dev/null and b/data/images/button/BugReport.png differ
diff --git a/data/images/button/Clear.png b/data/images/button/Clear.png
new file mode 100644
index 0000000..19a1665
Binary files /dev/null and b/data/images/button/Clear.png differ
diff --git a/data/images/button/Clock.png b/data/images/button/Clock.png
new file mode 100644
index 0000000..28de8fe
Binary files /dev/null and b/data/images/button/Clock.png differ
diff --git a/data/images/button/Computer.png b/data/images/button/Computer.png
new file mode 100644
index 0000000..04c4598
Binary files /dev/null and b/data/images/button/Computer.png differ
diff --git a/data/images/button/ComputerOff.png b/data/images/button/ComputerOff.png
new file mode 100644
index 0000000..d333330
Binary files /dev/null and b/data/images/button/ComputerOff.png differ
diff --git a/data/images/button/ComputerOn.png b/data/images/button/ComputerOn.png
new file mode 100644
index 0000000..f69e182
Binary files /dev/null and b/data/images/button/ComputerOn.png differ
diff --git a/data/images/button/Connect.png b/data/images/button/Connect.png
new file mode 100644
index 0000000..4f031b7
Binary files /dev/null and b/data/images/button/Connect.png differ
diff --git a/data/images/button/Cut.png b/data/images/button/Cut.png
new file mode 100644
index 0000000..f702874
Binary files /dev/null and b/data/images/button/Cut.png differ
diff --git a/data/images/button/Details.png b/data/images/button/Details.png
new file mode 100644
index 0000000..04e71de
Binary files /dev/null and b/data/images/button/Details.png differ
diff --git a/data/images/button/Disconnect.png b/data/images/button/Disconnect.png
new file mode 100644
index 0000000..bc9a1b7
Binary files /dev/null and b/data/images/button/Disconnect.png differ
diff --git a/data/images/button/Down.png b/data/images/button/Down.png
new file mode 100644
index 0000000..bf8cc2a
Binary files /dev/null and b/data/images/button/Down.png differ
diff --git a/data/images/button/DownloadOff.png b/data/images/button/DownloadOff.png
new file mode 100644
index 0000000..b70fa32
Binary files /dev/null and b/data/images/button/DownloadOff.png differ
diff --git a/data/images/button/DownloadOn.png b/data/images/button/DownloadOn.png
new file mode 100644
index 0000000..b0aab71
Binary files /dev/null and b/data/images/button/DownloadOn.png differ
diff --git a/data/images/button/DrawAgreement.png b/data/images/button/DrawAgreement.png
new file mode 100644
index 0000000..9a6f857
Binary files /dev/null and b/data/images/button/DrawAgreement.png differ
diff --git a/data/images/button/DrawReject.png b/data/images/button/DrawReject.png
new file mode 100644
index 0000000..41c1663
Binary files /dev/null and b/data/images/button/DrawReject.png differ
diff --git a/data/images/button/EditGroup.png b/data/images/button/EditGroup.png
new file mode 100644
index 0000000..2015688
Binary files /dev/null and b/data/images/button/EditGroup.png differ
diff --git a/data/images/button/EditLogin.png b/data/images/button/EditLogin.png
new file mode 100644
index 0000000..1188fca
Binary files /dev/null and b/data/images/button/EditLogin.png differ
diff --git a/data/images/button/Empty.png b/data/images/button/Empty.png
new file mode 100644
index 0000000..36ce140
Binary files /dev/null and b/data/images/button/Empty.png differ
diff --git a/data/images/button/End.png b/data/images/button/End.png
new file mode 100644
index 0000000..628c7ee
Binary files /dev/null and b/data/images/button/End.png differ
diff --git a/data/images/button/Find.png b/data/images/button/Find.png
new file mode 100644
index 0000000..bc123a8
Binary files /dev/null and b/data/images/button/Find.png differ
diff --git a/data/images/button/ForcePack.png b/data/images/button/ForcePack.png
new file mode 100644
index 0000000..6dea0c2
Binary files /dev/null and b/data/images/button/ForcePack.png differ
diff --git a/data/images/button/Good.png b/data/images/button/Good.png
new file mode 100644
index 0000000..790f5e1
Binary files /dev/null and b/data/images/button/Good.png differ
diff --git a/data/images/button/Help.png b/data/images/button/Help.png
new file mode 100644
index 0000000..8542495
Binary files /dev/null and b/data/images/button/Help.png differ
diff --git a/data/images/button/Human.png b/data/images/button/Human.png
new file mode 100644
index 0000000..b50ec42
Binary files /dev/null and b/data/images/button/Human.png differ
diff --git a/data/images/button/HumanOff.png b/data/images/button/HumanOff.png
new file mode 100644
index 0000000..b62655e
Binary files /dev/null and b/data/images/button/HumanOff.png differ
diff --git a/data/images/button/HumanOn.png b/data/images/button/HumanOn.png
new file mode 100644
index 0000000..43887aa
Binary files /dev/null and b/data/images/button/HumanOn.png differ
diff --git a/data/images/button/Info.png b/data/images/button/Info.png
new file mode 100644
index 0000000..8eeebdd
Binary files /dev/null and b/data/images/button/Info.png differ
diff --git a/data/images/button/JConsole.png b/data/images/button/JConsole.png
new file mode 100644
index 0000000..5eac167
Binary files /dev/null and b/data/images/button/JConsole.png differ
diff --git a/data/images/button/JConsoleOff.png b/data/images/button/JConsoleOff.png
new file mode 100644
index 0000000..5eac167
Binary files /dev/null and b/data/images/button/JConsoleOff.png differ
diff --git a/data/images/button/JConsoleOn.png b/data/images/button/JConsoleOn.png
new file mode 100644
index 0000000..5eac167
Binary files /dev/null and b/data/images/button/JConsoleOn.png differ
diff --git a/data/images/button/JoinGroup.png b/data/images/button/JoinGroup.png
new file mode 100644
index 0000000..6e497e7
Binary files /dev/null and b/data/images/button/JoinGroup.png differ
diff --git a/data/images/button/LeftGroup.png b/data/images/button/LeftGroup.png
new file mode 100644
index 0000000..bfea85d
Binary files /dev/null and b/data/images/button/LeftGroup.png differ
diff --git a/data/images/button/Licence.png b/data/images/button/Licence.png
new file mode 100644
index 0000000..6a3f5a7
Binary files /dev/null and b/data/images/button/Licence.png differ
diff --git a/data/images/button/LinkType.png b/data/images/button/LinkType.png
new file mode 100644
index 0000000..d376dfb
Binary files /dev/null and b/data/images/button/LinkType.png differ
diff --git a/data/images/button/LocalRemoveOff.png b/data/images/button/LocalRemoveOff.png
new file mode 100644
index 0000000..3a5110c
Binary files /dev/null and b/data/images/button/LocalRemoveOff.png differ
diff --git a/data/images/button/LocalRemoveOn.png b/data/images/button/LocalRemoveOn.png
new file mode 100644
index 0000000..19a1665
Binary files /dev/null and b/data/images/button/LocalRemoveOn.png differ
diff --git a/data/images/button/Locale.png b/data/images/button/Locale.png
new file mode 100644
index 0000000..77ea807
Binary files /dev/null and b/data/images/button/Locale.png differ
diff --git a/data/images/button/Log.png b/data/images/button/Log.png
new file mode 100644
index 0000000..38dbb26
Binary files /dev/null and b/data/images/button/Log.png differ
diff --git a/data/images/button/Manual.png b/data/images/button/Manual.png
new file mode 100644
index 0000000..88e438e
Binary files /dev/null and b/data/images/button/Manual.png differ
diff --git a/data/images/button/Merge.png b/data/images/button/Merge.png
new file mode 100644
index 0000000..2771bbe
Binary files /dev/null and b/data/images/button/Merge.png differ
diff --git a/data/images/button/Network.png b/data/images/button/Network.png
new file mode 100644
index 0000000..8d9a0e7
Binary files /dev/null and b/data/images/button/Network.png differ
diff --git a/data/images/button/NetworkOff.png b/data/images/button/NetworkOff.png
new file mode 100644
index 0000000..0110f89
Binary files /dev/null and b/data/images/button/NetworkOff.png differ
diff --git a/data/images/button/NetworkOn.png b/data/images/button/NetworkOn.png
new file mode 100644
index 0000000..36fff6d
Binary files /dev/null and b/data/images/button/NetworkOn.png differ
diff --git a/data/images/button/Next.png b/data/images/button/Next.png
new file mode 100644
index 0000000..0011e67
Binary files /dev/null and b/data/images/button/Next.png differ
diff --git a/data/images/button/Online.png b/data/images/button/Online.png
new file mode 100644
index 0000000..f30f95a
Binary files /dev/null and b/data/images/button/Online.png differ
diff --git a/data/images/button/Open.png b/data/images/button/Open.png
new file mode 100644
index 0000000..c3bcfcd
Binary files /dev/null and b/data/images/button/Open.png differ
diff --git a/data/images/button/PackBug.png b/data/images/button/PackBug.png
new file mode 100644
index 0000000..8933c01
Binary files /dev/null and b/data/images/button/PackBug.png differ
diff --git a/data/images/button/PackBugOff.png b/data/images/button/PackBugOff.png
new file mode 100644
index 0000000..1de84d5
Binary files /dev/null and b/data/images/button/PackBugOff.png differ
diff --git a/data/images/button/PackBugOn.png b/data/images/button/PackBugOn.png
new file mode 100644
index 0000000..8933c01
Binary files /dev/null and b/data/images/button/PackBugOn.png differ
diff --git a/data/images/button/Players.png b/data/images/button/Players.png
new file mode 100644
index 0000000..42acdfc
Binary files /dev/null and b/data/images/button/Players.png differ
diff --git a/data/images/button/Previous.png b/data/images/button/Previous.png
new file mode 100644
index 0000000..d3bc514
Binary files /dev/null and b/data/images/button/Previous.png differ
diff --git a/data/images/button/Pseudo.png b/data/images/button/Pseudo.png
new file mode 100644
index 0000000..38dbb26
Binary files /dev/null and b/data/images/button/Pseudo.png differ
diff --git a/data/images/button/Quit.png b/data/images/button/Quit.png
new file mode 100644
index 0000000..22a65a4
Binary files /dev/null and b/data/images/button/Quit.png differ
diff --git a/data/images/button/Redo.png b/data/images/button/Redo.png
new file mode 100644
index 0000000..c03bba0
Binary files /dev/null and b/data/images/button/Redo.png differ
diff --git a/data/images/button/RemoteRemoveOff.png b/data/images/button/RemoteRemoveOff.png
new file mode 100644
index 0000000..3a5110c
Binary files /dev/null and b/data/images/button/RemoteRemoveOff.png differ
diff --git a/data/images/button/RemoteRemoveOn.png b/data/images/button/RemoteRemoveOn.png
new file mode 100644
index 0000000..19a1665
Binary files /dev/null and b/data/images/button/RemoteRemoveOn.png differ
diff --git a/data/images/button/RemoveKey.png b/data/images/button/RemoveKey.png
new file mode 100644
index 0000000..ee80592
Binary files /dev/null and b/data/images/button/RemoveKey.png differ
diff --git a/data/images/button/RemoveLocale.png b/data/images/button/RemoveLocale.png
new file mode 100644
index 0000000..60575e9
Binary files /dev/null and b/data/images/button/RemoveLocale.png differ
diff --git a/data/images/button/RenameLocale.png b/data/images/button/RenameLocale.png
new file mode 100644
index 0000000..7f6fcf1
Binary files /dev/null and b/data/images/button/RenameLocale.png differ
diff --git a/data/images/button/Resign.png b/data/images/button/Resign.png
new file mode 100644
index 0000000..322f1b4
Binary files /dev/null and b/data/images/button/Resign.png differ
diff --git a/data/images/button/Save.png b/data/images/button/Save.png
new file mode 100644
index 0000000..7da1d7c
Binary files /dev/null and b/data/images/button/Save.png differ
diff --git a/data/images/button/SaveAs.png b/data/images/button/SaveAs.png
new file mode 100644
index 0000000..a838052
Binary files /dev/null and b/data/images/button/SaveAs.png differ
diff --git a/data/images/button/SetProxy.png b/data/images/button/SetProxy.png
new file mode 100644
index 0000000..111c493
Binary files /dev/null and b/data/images/button/SetProxy.png differ
diff --git a/data/images/button/Stop.png b/data/images/button/Stop.png
new file mode 100644
index 0000000..217e33b
Binary files /dev/null and b/data/images/button/Stop.png differ
diff --git a/data/images/button/ToolBarProfil.png b/data/images/button/ToolBarProfil.png
new file mode 100644
index 0000000..bd731b3
Binary files /dev/null and b/data/images/button/ToolBarProfil.png differ
diff --git a/data/images/button/Undo.png b/data/images/button/Undo.png
new file mode 100644
index 0000000..f123942
Binary files /dev/null and b/data/images/button/Undo.png differ
diff --git a/data/images/button/Unlog.png b/data/images/button/Unlog.png
new file mode 100644
index 0000000..7a2f365
Binary files /dev/null and b/data/images/button/Unlog.png differ
diff --git a/data/images/button/Up.png b/data/images/button/Up.png
new file mode 100644
index 0000000..afca099
Binary files /dev/null and b/data/images/button/Up.png differ
diff --git a/data/images/button/Update.png b/data/images/button/Update.png
new file mode 100644
index 0000000..67f739e
Binary files /dev/null and b/data/images/button/Update.png differ
diff --git a/data/images/button/UploadOff.png b/data/images/button/UploadOff.png
new file mode 100644
index 0000000..7816e7b
Binary files /dev/null and b/data/images/button/UploadOff.png differ
diff --git a/data/images/button/UploadOn.png b/data/images/button/UploadOn.png
new file mode 100644
index 0000000..f30f95a
Binary files /dev/null and b/data/images/button/UploadOn.png differ
diff --git a/data/images/button/Users.png b/data/images/button/Users.png
new file mode 100644
index 0000000..010a249
Binary files /dev/null and b/data/images/button/Users.png differ
diff --git a/data/images/button/Warning.png b/data/images/button/Warning.png
new file mode 100644
index 0000000..4a5c3df
Binary files /dev/null and b/data/images/button/Warning.png differ
diff --git a/data/images/button/White.png b/data/images/button/White.png
new file mode 100644
index 0000000..310a75b
Binary files /dev/null and b/data/images/button/White.png differ
diff --git a/data/images/button/develop.png b/data/images/button/develop.png
new file mode 100644
index 0000000..a437e0a
Binary files /dev/null and b/data/images/button/develop.png differ
diff --git a/data/images/chat/chat.png b/data/images/chat/chat.png
new file mode 100644
index 0000000..ed2d33b
Binary files /dev/null and b/data/images/chat/chat.png differ
diff --git a/data/images/flags/ad.png b/data/images/flags/ad.png
new file mode 100644
index 0000000..5d17202
Binary files /dev/null and b/data/images/flags/ad.png differ
diff --git a/data/images/flags/ae.png b/data/images/flags/ae.png
new file mode 100644
index 0000000..007dc36
Binary files /dev/null and b/data/images/flags/ae.png differ
diff --git a/data/images/flags/af.png b/data/images/flags/af.png
new file mode 100644
index 0000000..9f9cd77
Binary files /dev/null and b/data/images/flags/af.png differ
diff --git a/data/images/flags/ag.png b/data/images/flags/ag.png
new file mode 100644
index 0000000..de7b76c
Binary files /dev/null and b/data/images/flags/ag.png differ
diff --git a/data/images/flags/ai.png b/data/images/flags/ai.png
new file mode 100644
index 0000000..bbbd7b1
Binary files /dev/null and b/data/images/flags/ai.png differ
diff --git a/data/images/flags/al.png b/data/images/flags/al.png
new file mode 100644
index 0000000..c5d218c
Binary files /dev/null and b/data/images/flags/al.png differ
diff --git a/data/images/flags/am.png b/data/images/flags/am.png
new file mode 100644
index 0000000..5154516
Binary files /dev/null and b/data/images/flags/am.png differ
diff --git a/data/images/flags/an.png b/data/images/flags/an.png
new file mode 100644
index 0000000..28d1f98
Binary files /dev/null and b/data/images/flags/an.png differ
diff --git a/data/images/flags/ao.png b/data/images/flags/ao.png
new file mode 100644
index 0000000..9dc5ab7
Binary files /dev/null and b/data/images/flags/ao.png differ
diff --git a/data/images/flags/aq.png b/data/images/flags/aq.png
new file mode 100644
index 0000000..7caeae0
Binary files /dev/null and b/data/images/flags/aq.png differ
diff --git a/data/images/flags/ar.png b/data/images/flags/ar.png
new file mode 100644
index 0000000..dcabc83
Binary files /dev/null and b/data/images/flags/ar.png differ
diff --git a/data/images/flags/as.png b/data/images/flags/as.png
new file mode 100644
index 0000000..d198709
Binary files /dev/null and b/data/images/flags/as.png differ
diff --git a/data/images/flags/at.png b/data/images/flags/at.png
new file mode 100644
index 0000000..fadb6a2
Binary files /dev/null and b/data/images/flags/at.png differ
diff --git a/data/images/flags/au.png b/data/images/flags/au.png
new file mode 100644
index 0000000..c8b5599
Binary files /dev/null and b/data/images/flags/au.png differ
diff --git a/data/images/flags/aw.png b/data/images/flags/aw.png
new file mode 100644
index 0000000..c66e1f1
Binary files /dev/null and b/data/images/flags/aw.png differ
diff --git a/data/images/flags/ax.png b/data/images/flags/ax.png
new file mode 100644
index 0000000..917ff47
Binary files /dev/null and b/data/images/flags/ax.png differ
diff --git a/data/images/flags/az.png b/data/images/flags/az.png
new file mode 100644
index 0000000..381598a
Binary files /dev/null and b/data/images/flags/az.png differ
diff --git a/data/images/flags/ba.png b/data/images/flags/ba.png
new file mode 100644
index 0000000..6eff4f0
Binary files /dev/null and b/data/images/flags/ba.png differ
diff --git a/data/images/flags/bb.png b/data/images/flags/bb.png
new file mode 100644
index 0000000..18a1e0d
Binary files /dev/null and b/data/images/flags/bb.png differ
diff --git a/data/images/flags/bd.png b/data/images/flags/bd.png
new file mode 100644
index 0000000..00770ad
Binary files /dev/null and b/data/images/flags/bd.png differ
diff --git a/data/images/flags/be.png b/data/images/flags/be.png
new file mode 100644
index 0000000..b09b3d6
Binary files /dev/null and b/data/images/flags/be.png differ
diff --git a/data/images/flags/bf.png b/data/images/flags/bf.png
new file mode 100644
index 0000000..fc47278
Binary files /dev/null and b/data/images/flags/bf.png differ
diff --git a/data/images/flags/bg.png b/data/images/flags/bg.png
new file mode 100644
index 0000000..d92441b
Binary files /dev/null and b/data/images/flags/bg.png differ
diff --git a/data/images/flags/bh.png b/data/images/flags/bh.png
new file mode 100644
index 0000000..4f6d433
Binary files /dev/null and b/data/images/flags/bh.png differ
diff --git a/data/images/flags/bi.png b/data/images/flags/bi.png
new file mode 100644
index 0000000..3832f22
Binary files /dev/null and b/data/images/flags/bi.png differ
diff --git a/data/images/flags/bj.png b/data/images/flags/bj.png
new file mode 100644
index 0000000..dd3c688
Binary files /dev/null and b/data/images/flags/bj.png differ
diff --git a/data/images/flags/bl.png b/data/images/flags/bl.png
new file mode 100644
index 0000000..692f8de
Binary files /dev/null and b/data/images/flags/bl.png differ
diff --git a/data/images/flags/bm.png b/data/images/flags/bm.png
new file mode 100644
index 0000000..b53c416
Binary files /dev/null and b/data/images/flags/bm.png differ
diff --git a/data/images/flags/bn.png b/data/images/flags/bn.png
new file mode 100644
index 0000000..d8a6875
Binary files /dev/null and b/data/images/flags/bn.png differ
diff --git a/data/images/flags/bo.png b/data/images/flags/bo.png
new file mode 100644
index 0000000..c8686b5
Binary files /dev/null and b/data/images/flags/bo.png differ
diff --git a/data/images/flags/br.png b/data/images/flags/br.png
new file mode 100644
index 0000000..9a9d5e6
Binary files /dev/null and b/data/images/flags/br.png differ
diff --git a/data/images/flags/br2.png b/data/images/flags/br2.png
new file mode 100644
index 0000000..22a9868
Binary files /dev/null and b/data/images/flags/br2.png differ
diff --git a/data/images/flags/bs.png b/data/images/flags/bs.png
new file mode 100644
index 0000000..dce7bcf
Binary files /dev/null and b/data/images/flags/bs.png differ
diff --git a/data/images/flags/bt.png b/data/images/flags/bt.png
new file mode 100644
index 0000000..b87008a
Binary files /dev/null and b/data/images/flags/bt.png differ
diff --git a/data/images/flags/bv.png b/data/images/flags/bv.png
new file mode 100644
index 0000000..3f24fb5
Binary files /dev/null and b/data/images/flags/bv.png differ
diff --git a/data/images/flags/bw.png b/data/images/flags/bw.png
new file mode 100644
index 0000000..46a79b4
Binary files /dev/null and b/data/images/flags/bw.png differ
diff --git a/data/images/flags/by.png b/data/images/flags/by.png
new file mode 100644
index 0000000..030b0f6
Binary files /dev/null and b/data/images/flags/by.png differ
diff --git a/data/images/flags/bz.png b/data/images/flags/bz.png
new file mode 100644
index 0000000..7ee942e
Binary files /dev/null and b/data/images/flags/bz.png differ
diff --git a/data/images/flags/ca.png b/data/images/flags/ca.png
new file mode 100644
index 0000000..d08962d
Binary files /dev/null and b/data/images/flags/ca.png differ
diff --git a/data/images/flags/cc.png b/data/images/flags/cc.png
new file mode 100644
index 0000000..e61fa76
Binary files /dev/null and b/data/images/flags/cc.png differ
diff --git a/data/images/flags/cd.png b/data/images/flags/cd.png
new file mode 100644
index 0000000..d39385d
Binary files /dev/null and b/data/images/flags/cd.png differ
diff --git a/data/images/flags/cf.png b/data/images/flags/cf.png
new file mode 100644
index 0000000..f136158
Binary files /dev/null and b/data/images/flags/cf.png differ
diff --git a/data/images/flags/cg.png b/data/images/flags/cg.png
new file mode 100644
index 0000000..2ec7d0e
Binary files /dev/null and b/data/images/flags/cg.png differ
diff --git a/data/images/flags/ch.png b/data/images/flags/ch.png
new file mode 100644
index 0000000..e8b1cfc
Binary files /dev/null and b/data/images/flags/ch.png differ
diff --git a/data/images/flags/ci.png b/data/images/flags/ci.png
new file mode 100644
index 0000000..c7644cb
Binary files /dev/null and b/data/images/flags/ci.png differ
diff --git a/data/images/flags/ck.png b/data/images/flags/ck.png
new file mode 100644
index 0000000..a896cc2
Binary files /dev/null and b/data/images/flags/ck.png differ
diff --git a/data/images/flags/cl.png b/data/images/flags/cl.png
new file mode 100644
index 0000000..a113a2b
Binary files /dev/null and b/data/images/flags/cl.png differ
diff --git a/data/images/flags/cm.png b/data/images/flags/cm.png
new file mode 100644
index 0000000..a5d828f
Binary files /dev/null and b/data/images/flags/cm.png differ
diff --git a/data/images/flags/cn.png b/data/images/flags/cn.png
new file mode 100644
index 0000000..2ad03f6
Binary files /dev/null and b/data/images/flags/cn.png differ
diff --git a/data/images/flags/co.png b/data/images/flags/co.png
new file mode 100644
index 0000000..362f006
Binary files /dev/null and b/data/images/flags/co.png differ
diff --git a/data/images/flags/cr.png b/data/images/flags/cr.png
new file mode 100644
index 0000000..a184a8d
Binary files /dev/null and b/data/images/flags/cr.png differ
diff --git a/data/images/flags/cs.png b/data/images/flags/cs.png
new file mode 100644
index 0000000..7a89a78
Binary files /dev/null and b/data/images/flags/cs.png differ
diff --git a/data/images/flags/cu.png b/data/images/flags/cu.png
new file mode 100644
index 0000000..19c6f80
Binary files /dev/null and b/data/images/flags/cu.png differ
diff --git a/data/images/flags/cv.png b/data/images/flags/cv.png
new file mode 100644
index 0000000..4f6bf24
Binary files /dev/null and b/data/images/flags/cv.png differ
diff --git a/data/images/flags/cx.png b/data/images/flags/cx.png
new file mode 100644
index 0000000..5c858ca
Binary files /dev/null and b/data/images/flags/cx.png differ
diff --git a/data/images/flags/cy.png b/data/images/flags/cy.png
new file mode 100644
index 0000000..97ed7e8
Binary files /dev/null and b/data/images/flags/cy.png differ
diff --git a/data/images/flags/cz.png b/data/images/flags/cz.png
new file mode 100644
index 0000000..97ed7e8
Binary files /dev/null and b/data/images/flags/cz.png differ
diff --git a/data/images/flags/de.png b/data/images/flags/de.png
new file mode 100644
index 0000000..24b07b5
Binary files /dev/null and b/data/images/flags/de.png differ
diff --git a/data/images/flags/dj.png b/data/images/flags/dj.png
new file mode 100644
index 0000000..791c251
Binary files /dev/null and b/data/images/flags/dj.png differ
diff --git a/data/images/flags/dk.png b/data/images/flags/dk.png
new file mode 100644
index 0000000..2be6ab1
Binary files /dev/null and b/data/images/flags/dk.png differ
diff --git a/data/images/flags/dm.png b/data/images/flags/dm.png
new file mode 100644
index 0000000..edd7fff
Binary files /dev/null and b/data/images/flags/dm.png differ
diff --git a/data/images/flags/do.png b/data/images/flags/do.png
new file mode 100644
index 0000000..6222762
Binary files /dev/null and b/data/images/flags/do.png differ
diff --git a/data/images/flags/dz.png b/data/images/flags/dz.png
new file mode 100644
index 0000000..743cb1f
Binary files /dev/null and b/data/images/flags/dz.png differ
diff --git a/data/images/flags/ec.png b/data/images/flags/ec.png
new file mode 100644
index 0000000..cb87ce8
Binary files /dev/null and b/data/images/flags/ec.png differ
diff --git a/data/images/flags/ee.png b/data/images/flags/ee.png
new file mode 100644
index 0000000..94e5106
Binary files /dev/null and b/data/images/flags/ee.png differ
diff --git a/data/images/flags/eg.png b/data/images/flags/eg.png
new file mode 100644
index 0000000..dba11a2
Binary files /dev/null and b/data/images/flags/eg.png differ
diff --git a/data/images/flags/eh.png b/data/images/flags/eh.png
new file mode 100644
index 0000000..9fb7b1d
Binary files /dev/null and b/data/images/flags/eh.png differ
diff --git a/data/images/flags/er.png b/data/images/flags/er.png
new file mode 100644
index 0000000..43225fa
Binary files /dev/null and b/data/images/flags/er.png differ
diff --git a/data/images/flags/es.png b/data/images/flags/es.png
new file mode 100644
index 0000000..4b30c49
Binary files /dev/null and b/data/images/flags/es.png differ
diff --git a/data/images/flags/et.png b/data/images/flags/et.png
new file mode 100644
index 0000000..7275abf
Binary files /dev/null and b/data/images/flags/et.png differ
diff --git a/data/images/flags/fi.png b/data/images/flags/fi.png
new file mode 100644
index 0000000..8574dec
Binary files /dev/null and b/data/images/flags/fi.png differ
diff --git a/data/images/flags/fj.png b/data/images/flags/fj.png
new file mode 100644
index 0000000..dd021d5
Binary files /dev/null and b/data/images/flags/fj.png differ
diff --git a/data/images/flags/fk.png b/data/images/flags/fk.png
new file mode 100644
index 0000000..7c277bc
Binary files /dev/null and b/data/images/flags/fk.png differ
diff --git a/data/images/flags/fm.png b/data/images/flags/fm.png
new file mode 100644
index 0000000..6c4e137
Binary files /dev/null and b/data/images/flags/fm.png differ
diff --git a/data/images/flags/fo.png b/data/images/flags/fo.png
new file mode 100644
index 0000000..8eeb7cc
Binary files /dev/null and b/data/images/flags/fo.png differ
diff --git a/data/images/flags/fr.png b/data/images/flags/fr.png
new file mode 100644
index 0000000..798f5ec
Binary files /dev/null and b/data/images/flags/fr.png differ
diff --git a/data/images/flags/fx.png b/data/images/flags/fx.png
new file mode 100644
index 0000000..c1a5395
Binary files /dev/null and b/data/images/flags/fx.png differ
diff --git a/data/images/flags/ga.png b/data/images/flags/ga.png
new file mode 100644
index 0000000..9c72bec
Binary files /dev/null and b/data/images/flags/ga.png differ
diff --git a/data/images/flags/gb.png b/data/images/flags/gb.png
new file mode 100644
index 0000000..8558aa6
Binary files /dev/null and b/data/images/flags/gb.png differ
diff --git a/data/images/flags/gd.png b/data/images/flags/gd.png
new file mode 100644
index 0000000..7535381
Binary files /dev/null and b/data/images/flags/gd.png differ
diff --git a/data/images/flags/ge.png b/data/images/flags/ge.png
new file mode 100644
index 0000000..352d0f3
Binary files /dev/null and b/data/images/flags/ge.png differ
diff --git a/data/images/flags/gf.png b/data/images/flags/gf.png
new file mode 100644
index 0000000..798f5ec
Binary files /dev/null and b/data/images/flags/gf.png differ
diff --git a/data/images/flags/gg.png b/data/images/flags/gg.png
new file mode 100644
index 0000000..cef5a7e
Binary files /dev/null and b/data/images/flags/gg.png differ
diff --git a/data/images/flags/gh.png b/data/images/flags/gh.png
new file mode 100644
index 0000000..f9aa766
Binary files /dev/null and b/data/images/flags/gh.png differ
diff --git a/data/images/flags/gi.png b/data/images/flags/gi.png
new file mode 100644
index 0000000..5de3e79
Binary files /dev/null and b/data/images/flags/gi.png differ
diff --git a/data/images/flags/gl.png b/data/images/flags/gl.png
new file mode 100644
index 0000000..f10fc56
Binary files /dev/null and b/data/images/flags/gl.png differ
diff --git a/data/images/flags/gm.png b/data/images/flags/gm.png
new file mode 100644
index 0000000..c09dc79
Binary files /dev/null and b/data/images/flags/gm.png differ
diff --git a/data/images/flags/gn.png b/data/images/flags/gn.png
new file mode 100644
index 0000000..99748b5
Binary files /dev/null and b/data/images/flags/gn.png differ
diff --git a/data/images/flags/gp.png b/data/images/flags/gp.png
new file mode 100644
index 0000000..798f5ec
Binary files /dev/null and b/data/images/flags/gp.png differ
diff --git a/data/images/flags/gq.png b/data/images/flags/gq.png
new file mode 100644
index 0000000..14c8b43
Binary files /dev/null and b/data/images/flags/gq.png differ
diff --git a/data/images/flags/gr.png b/data/images/flags/gr.png
new file mode 100644
index 0000000..35871f0
Binary files /dev/null and b/data/images/flags/gr.png differ
diff --git a/data/images/flags/gs.png b/data/images/flags/gs.png
new file mode 100644
index 0000000..700656b
Binary files /dev/null and b/data/images/flags/gs.png differ
diff --git a/data/images/flags/gt.png b/data/images/flags/gt.png
new file mode 100644
index 0000000..e8cce58
Binary files /dev/null and b/data/images/flags/gt.png differ
diff --git a/data/images/flags/gu.png b/data/images/flags/gu.png
new file mode 100644
index 0000000..40ddc68
Binary files /dev/null and b/data/images/flags/gu.png differ
diff --git a/data/images/flags/gw.png b/data/images/flags/gw.png
new file mode 100644
index 0000000..ec220ce
Binary files /dev/null and b/data/images/flags/gw.png differ
diff --git a/data/images/flags/gy.png b/data/images/flags/gy.png
new file mode 100644
index 0000000..2daa096
Binary files /dev/null and b/data/images/flags/gy.png differ
diff --git a/data/images/flags/hk.png b/data/images/flags/hk.png
new file mode 100644
index 0000000..a2eeca2
Binary files /dev/null and b/data/images/flags/hk.png differ
diff --git a/data/images/flags/hm.png b/data/images/flags/hm.png
new file mode 100644
index 0000000..c8b5599
Binary files /dev/null and b/data/images/flags/hm.png differ
diff --git a/data/images/flags/hn.png b/data/images/flags/hn.png
new file mode 100644
index 0000000..633abb1
Binary files /dev/null and b/data/images/flags/hn.png differ
diff --git a/data/images/flags/hr.png b/data/images/flags/hr.png
new file mode 100644
index 0000000..ba09f12
Binary files /dev/null and b/data/images/flags/hr.png differ
diff --git a/data/images/flags/ht.png b/data/images/flags/ht.png
new file mode 100644
index 0000000..cf97344
Binary files /dev/null and b/data/images/flags/ht.png differ
diff --git a/data/images/flags/hu.png b/data/images/flags/hu.png
new file mode 100644
index 0000000..3345bde
Binary files /dev/null and b/data/images/flags/hu.png differ
diff --git a/data/images/flags/id.png b/data/images/flags/id.png
new file mode 100644
index 0000000..6aa9fde
Binary files /dev/null and b/data/images/flags/id.png differ
diff --git a/data/images/flags/ie.png b/data/images/flags/ie.png
new file mode 100644
index 0000000..fe977c3
Binary files /dev/null and b/data/images/flags/ie.png differ
diff --git a/data/images/flags/il.png b/data/images/flags/il.png
new file mode 100644
index 0000000..bc8523e
Binary files /dev/null and b/data/images/flags/il.png differ
diff --git a/data/images/flags/in.png b/data/images/flags/in.png
new file mode 100644
index 0000000..b7c5495
Binary files /dev/null and b/data/images/flags/in.png differ
diff --git a/data/images/flags/io.png b/data/images/flags/io.png
new file mode 100644
index 0000000..fd5fb1c
Binary files /dev/null and b/data/images/flags/io.png differ
diff --git a/data/images/flags/iq.png b/data/images/flags/iq.png
new file mode 100644
index 0000000..3721fd3
Binary files /dev/null and b/data/images/flags/iq.png differ
diff --git a/data/images/flags/ir.png b/data/images/flags/ir.png
new file mode 100644
index 0000000..4d7cb1f
Binary files /dev/null and b/data/images/flags/ir.png differ
diff --git a/data/images/flags/is.png b/data/images/flags/is.png
new file mode 100644
index 0000000..aa90114
Binary files /dev/null and b/data/images/flags/is.png differ
diff --git a/data/images/flags/it.png b/data/images/flags/it.png
new file mode 100644
index 0000000..5212ade
Binary files /dev/null and b/data/images/flags/it.png differ
diff --git a/data/images/flags/je.png b/data/images/flags/je.png
new file mode 100644
index 0000000..5930485
Binary files /dev/null and b/data/images/flags/je.png differ
diff --git a/data/images/flags/jm.png b/data/images/flags/jm.png
new file mode 100644
index 0000000..ccedfcd
Binary files /dev/null and b/data/images/flags/jm.png differ
diff --git a/data/images/flags/jo.png b/data/images/flags/jo.png
new file mode 100644
index 0000000..f433260
Binary files /dev/null and b/data/images/flags/jo.png differ
diff --git a/data/images/flags/jp.png b/data/images/flags/jp.png
new file mode 100644
index 0000000..fb4f757
Binary files /dev/null and b/data/images/flags/jp.png differ
diff --git a/data/images/flags/ke.png b/data/images/flags/ke.png
new file mode 100644
index 0000000..3538e8d
Binary files /dev/null and b/data/images/flags/ke.png differ
diff --git a/data/images/flags/kg.png b/data/images/flags/kg.png
new file mode 100644
index 0000000..889b612
Binary files /dev/null and b/data/images/flags/kg.png differ
diff --git a/data/images/flags/kh.png b/data/images/flags/kh.png
new file mode 100644
index 0000000..772f587
Binary files /dev/null and b/data/images/flags/kh.png differ
diff --git a/data/images/flags/ki.png b/data/images/flags/ki.png
new file mode 100644
index 0000000..4c8a67c
Binary files /dev/null and b/data/images/flags/ki.png differ
diff --git a/data/images/flags/km.png b/data/images/flags/km.png
new file mode 100644
index 0000000..e704afb
Binary files /dev/null and b/data/images/flags/km.png differ
diff --git a/data/images/flags/kn.png b/data/images/flags/kn.png
new file mode 100644
index 0000000..042232c
Binary files /dev/null and b/data/images/flags/kn.png differ
diff --git a/data/images/flags/kp.png b/data/images/flags/kp.png
new file mode 100644
index 0000000..f8fbd30
Binary files /dev/null and b/data/images/flags/kp.png differ
diff --git a/data/images/flags/kr.png b/data/images/flags/kr.png
new file mode 100644
index 0000000..f83ebb3
Binary files /dev/null and b/data/images/flags/kr.png differ
diff --git a/data/images/flags/kw.png b/data/images/flags/kw.png
new file mode 100644
index 0000000..24748c6
Binary files /dev/null and b/data/images/flags/kw.png differ
diff --git a/data/images/flags/ky.png b/data/images/flags/ky.png
new file mode 100644
index 0000000..6973771
Binary files /dev/null and b/data/images/flags/ky.png differ
diff --git a/data/images/flags/kz.png b/data/images/flags/kz.png
new file mode 100644
index 0000000..3e102a4
Binary files /dev/null and b/data/images/flags/kz.png differ
diff --git a/data/images/flags/la.png b/data/images/flags/la.png
new file mode 100644
index 0000000..532e3b6
Binary files /dev/null and b/data/images/flags/la.png differ
diff --git a/data/images/flags/lb.png b/data/images/flags/lb.png
new file mode 100644
index 0000000..4f94e9f
Binary files /dev/null and b/data/images/flags/lb.png differ
diff --git a/data/images/flags/lc.png b/data/images/flags/lc.png
new file mode 100644
index 0000000..a1205be
Binary files /dev/null and b/data/images/flags/lc.png differ
diff --git a/data/images/flags/li.png b/data/images/flags/li.png
new file mode 100644
index 0000000..adef5a8
Binary files /dev/null and b/data/images/flags/li.png differ
diff --git a/data/images/flags/lk.png b/data/images/flags/lk.png
new file mode 100644
index 0000000..9ff43b5
Binary files /dev/null and b/data/images/flags/lk.png differ
diff --git a/data/images/flags/lr.png b/data/images/flags/lr.png
new file mode 100644
index 0000000..dc4c555
Binary files /dev/null and b/data/images/flags/lr.png differ
diff --git a/data/images/flags/ls.png b/data/images/flags/ls.png
new file mode 100644
index 0000000..fb9ec79
Binary files /dev/null and b/data/images/flags/ls.png differ
diff --git a/data/images/flags/lt.png b/data/images/flags/lt.png
new file mode 100644
index 0000000..e951f7d
Binary files /dev/null and b/data/images/flags/lt.png differ
diff --git a/data/images/flags/lu.png b/data/images/flags/lu.png
new file mode 100644
index 0000000..4110349
Binary files /dev/null and b/data/images/flags/lu.png differ
diff --git a/data/images/flags/lv.png b/data/images/flags/lv.png
new file mode 100644
index 0000000..9921615
Binary files /dev/null and b/data/images/flags/lv.png differ
diff --git a/data/images/flags/ly.png b/data/images/flags/ly.png
new file mode 100644
index 0000000..55f5edd
Binary files /dev/null and b/data/images/flags/ly.png differ
diff --git a/data/images/flags/ma.png b/data/images/flags/ma.png
new file mode 100644
index 0000000..f6f9d1f
Binary files /dev/null and b/data/images/flags/ma.png differ
diff --git a/data/images/flags/mc.png b/data/images/flags/mc.png
new file mode 100644
index 0000000..05b3bb4
Binary files /dev/null and b/data/images/flags/mc.png differ
diff --git a/data/images/flags/md.png b/data/images/flags/md.png
new file mode 100644
index 0000000..81c36fa
Binary files /dev/null and b/data/images/flags/md.png differ
diff --git a/data/images/flags/me.png b/data/images/flags/me.png
new file mode 100644
index 0000000..5f5199e
Binary files /dev/null and b/data/images/flags/me.png differ
diff --git a/data/images/flags/mf.png b/data/images/flags/mf.png
new file mode 100644
index 0000000..798f5ec
Binary files /dev/null and b/data/images/flags/mf.png differ
diff --git a/data/images/flags/mg.png b/data/images/flags/mg.png
new file mode 100644
index 0000000..ee2a024
Binary files /dev/null and b/data/images/flags/mg.png differ
diff --git a/data/images/flags/mh.png b/data/images/flags/mh.png
new file mode 100644
index 0000000..2a87b00
Binary files /dev/null and b/data/images/flags/mh.png differ
diff --git a/data/images/flags/mk.png b/data/images/flags/mk.png
new file mode 100644
index 0000000..618475d
Binary files /dev/null and b/data/images/flags/mk.png differ
diff --git a/data/images/flags/ml.png b/data/images/flags/ml.png
new file mode 100644
index 0000000..b10bcac
Binary files /dev/null and b/data/images/flags/ml.png differ
diff --git a/data/images/flags/mm.png b/data/images/flags/mm.png
new file mode 100644
index 0000000..f969995
Binary files /dev/null and b/data/images/flags/mm.png differ
diff --git a/data/images/flags/mn.png b/data/images/flags/mn.png
new file mode 100644
index 0000000..2a824d5
Binary files /dev/null and b/data/images/flags/mn.png differ
diff --git a/data/images/flags/mo.png b/data/images/flags/mo.png
new file mode 100644
index 0000000..06a1ead
Binary files /dev/null and b/data/images/flags/mo.png differ
diff --git a/data/images/flags/mp.png b/data/images/flags/mp.png
new file mode 100644
index 0000000..52625e3
Binary files /dev/null and b/data/images/flags/mp.png differ
diff --git a/data/images/flags/mq.png b/data/images/flags/mq.png
new file mode 100644
index 0000000..798f5ec
Binary files /dev/null and b/data/images/flags/mq.png differ
diff --git a/data/images/flags/mr.png b/data/images/flags/mr.png
new file mode 100644
index 0000000..52fcfc2
Binary files /dev/null and b/data/images/flags/mr.png differ
diff --git a/data/images/flags/ms.png b/data/images/flags/ms.png
new file mode 100644
index 0000000..022ca1a
Binary files /dev/null and b/data/images/flags/ms.png differ
diff --git a/data/images/flags/mt.png b/data/images/flags/mt.png
new file mode 100644
index 0000000..ada70c6
Binary files /dev/null and b/data/images/flags/mt.png differ
diff --git a/data/images/flags/mu.png b/data/images/flags/mu.png
new file mode 100644
index 0000000..1126c7a
Binary files /dev/null and b/data/images/flags/mu.png differ
diff --git a/data/images/flags/mv.png b/data/images/flags/mv.png
new file mode 100644
index 0000000..8f12c5b
Binary files /dev/null and b/data/images/flags/mv.png differ
diff --git a/data/images/flags/mw.png b/data/images/flags/mw.png
new file mode 100644
index 0000000..1ff7495
Binary files /dev/null and b/data/images/flags/mw.png differ
diff --git a/data/images/flags/mx.png b/data/images/flags/mx.png
new file mode 100644
index 0000000..0d7c671
Binary files /dev/null and b/data/images/flags/mx.png differ
diff --git a/data/images/flags/my.png b/data/images/flags/my.png
new file mode 100644
index 0000000..4eead54
Binary files /dev/null and b/data/images/flags/my.png differ
diff --git a/data/images/flags/mz.png b/data/images/flags/mz.png
new file mode 100644
index 0000000..10b4b8d
Binary files /dev/null and b/data/images/flags/mz.png differ
diff --git a/data/images/flags/na.png b/data/images/flags/na.png
new file mode 100644
index 0000000..db2580e
Binary files /dev/null and b/data/images/flags/na.png differ
diff --git a/data/images/flags/nc.png b/data/images/flags/nc.png
new file mode 100644
index 0000000..c1a5395
Binary files /dev/null and b/data/images/flags/nc.png differ
diff --git a/data/images/flags/ne.png b/data/images/flags/ne.png
new file mode 100644
index 0000000..fd818af
Binary files /dev/null and b/data/images/flags/ne.png differ
diff --git a/data/images/flags/nf.png b/data/images/flags/nf.png
new file mode 100644
index 0000000..46f61f0
Binary files /dev/null and b/data/images/flags/nf.png differ
diff --git a/data/images/flags/ng.png b/data/images/flags/ng.png
new file mode 100644
index 0000000..e61fcbb
Binary files /dev/null and b/data/images/flags/ng.png differ
diff --git a/data/images/flags/ni.png b/data/images/flags/ni.png
new file mode 100644
index 0000000..50bebdf
Binary files /dev/null and b/data/images/flags/ni.png differ
diff --git a/data/images/flags/nl.png b/data/images/flags/nl.png
new file mode 100644
index 0000000..08d2f2a
Binary files /dev/null and b/data/images/flags/nl.png differ
diff --git a/data/images/flags/no.png b/data/images/flags/no.png
new file mode 100644
index 0000000..3f24fb5
Binary files /dev/null and b/data/images/flags/no.png differ
diff --git a/data/images/flags/np.png b/data/images/flags/np.png
new file mode 100644
index 0000000..f561629
Binary files /dev/null and b/data/images/flags/np.png differ
diff --git a/data/images/flags/nr.png b/data/images/flags/nr.png
new file mode 100644
index 0000000..15474be
Binary files /dev/null and b/data/images/flags/nr.png differ
diff --git a/data/images/flags/nu.png b/data/images/flags/nu.png
new file mode 100644
index 0000000..fd9f9e0
Binary files /dev/null and b/data/images/flags/nu.png differ
diff --git a/data/images/flags/nz.png b/data/images/flags/nz.png
new file mode 100644
index 0000000..5bcbefd
Binary files /dev/null and b/data/images/flags/nz.png differ
diff --git a/data/images/flags/om.png b/data/images/flags/om.png
new file mode 100644
index 0000000..01a3db1
Binary files /dev/null and b/data/images/flags/om.png differ
diff --git a/data/images/flags/pa.png b/data/images/flags/pa.png
new file mode 100644
index 0000000..632bd8e
Binary files /dev/null and b/data/images/flags/pa.png differ
diff --git a/data/images/flags/pe.png b/data/images/flags/pe.png
new file mode 100644
index 0000000..c3b6831
Binary files /dev/null and b/data/images/flags/pe.png differ
diff --git a/data/images/flags/pf.png b/data/images/flags/pf.png
new file mode 100644
index 0000000..c9eaf6d
Binary files /dev/null and b/data/images/flags/pf.png differ
diff --git a/data/images/flags/pg.png b/data/images/flags/pg.png
new file mode 100644
index 0000000..1aa244e
Binary files /dev/null and b/data/images/flags/pg.png differ
diff --git a/data/images/flags/ph.png b/data/images/flags/ph.png
new file mode 100644
index 0000000..bac753b
Binary files /dev/null and b/data/images/flags/ph.png differ
diff --git a/data/images/flags/pk.png b/data/images/flags/pk.png
new file mode 100644
index 0000000..c77f3fd
Binary files /dev/null and b/data/images/flags/pk.png differ
diff --git a/data/images/flags/pl.png b/data/images/flags/pl.png
new file mode 100644
index 0000000..6c83c26
Binary files /dev/null and b/data/images/flags/pl.png differ
diff --git a/data/images/flags/pm.png b/data/images/flags/pm.png
new file mode 100644
index 0000000..798f5ec
Binary files /dev/null and b/data/images/flags/pm.png differ
diff --git a/data/images/flags/pn.png b/data/images/flags/pn.png
new file mode 100644
index 0000000..55f7b91
Binary files /dev/null and b/data/images/flags/pn.png differ
diff --git a/data/images/flags/pr.png b/data/images/flags/pr.png
new file mode 100644
index 0000000..e12c958
Binary files /dev/null and b/data/images/flags/pr.png differ
diff --git a/data/images/flags/ps.png b/data/images/flags/ps.png
new file mode 100644
index 0000000..fe3a676
Binary files /dev/null and b/data/images/flags/ps.png differ
diff --git a/data/images/flags/pt.png b/data/images/flags/pt.png
new file mode 100644
index 0000000..0911015
Binary files /dev/null and b/data/images/flags/pt.png differ
diff --git a/data/images/flags/pw.png b/data/images/flags/pw.png
new file mode 100644
index 0000000..89e9572
Binary files /dev/null and b/data/images/flags/pw.png differ
diff --git a/data/images/flags/py.png b/data/images/flags/py.png
new file mode 100644
index 0000000..78e16f1
Binary files /dev/null and b/data/images/flags/py.png differ
diff --git a/data/images/flags/qa.png b/data/images/flags/qa.png
new file mode 100644
index 0000000..1e63f04
Binary files /dev/null and b/data/images/flags/qa.png differ
diff --git a/data/images/flags/re.png b/data/images/flags/re.png
new file mode 100644
index 0000000..c1a5395
Binary files /dev/null and b/data/images/flags/re.png differ
diff --git a/data/images/flags/ro.png b/data/images/flags/ro.png
new file mode 100644
index 0000000..4a4f7b5
Binary files /dev/null and b/data/images/flags/ro.png differ
diff --git a/data/images/flags/rs.png b/data/images/flags/rs.png
new file mode 100644
index 0000000..ae9e0e1
Binary files /dev/null and b/data/images/flags/rs.png differ
diff --git a/data/images/flags/ru.png b/data/images/flags/ru.png
new file mode 100644
index 0000000..e6f8bb0
Binary files /dev/null and b/data/images/flags/ru.png differ
diff --git a/data/images/flags/rw.png b/data/images/flags/rw.png
new file mode 100644
index 0000000..05543ea
Binary files /dev/null and b/data/images/flags/rw.png differ
diff --git a/data/images/flags/sa.png b/data/images/flags/sa.png
new file mode 100644
index 0000000..a38fc79
Binary files /dev/null and b/data/images/flags/sa.png differ
diff --git a/data/images/flags/sb.png b/data/images/flags/sb.png
new file mode 100644
index 0000000..f274830
Binary files /dev/null and b/data/images/flags/sb.png differ
diff --git a/data/images/flags/sc.png b/data/images/flags/sc.png
new file mode 100644
index 0000000..369368b
Binary files /dev/null and b/data/images/flags/sc.png differ
diff --git a/data/images/flags/sd.png b/data/images/flags/sd.png
new file mode 100644
index 0000000..54c57bf
Binary files /dev/null and b/data/images/flags/sd.png differ
diff --git a/data/images/flags/se.png b/data/images/flags/se.png
new file mode 100644
index 0000000..0b7156f
Binary files /dev/null and b/data/images/flags/se.png differ
diff --git a/data/images/flags/sg.png b/data/images/flags/sg.png
new file mode 100644
index 0000000..5164779
Binary files /dev/null and b/data/images/flags/sg.png differ
diff --git a/data/images/flags/sh.png b/data/images/flags/sh.png
new file mode 100644
index 0000000..243cae2
Binary files /dev/null and b/data/images/flags/sh.png differ
diff --git a/data/images/flags/si.png b/data/images/flags/si.png
new file mode 100644
index 0000000..5c8e9a9
Binary files /dev/null and b/data/images/flags/si.png differ
diff --git a/data/images/flags/sj.png b/data/images/flags/sj.png
new file mode 100644
index 0000000..3f24fb5
Binary files /dev/null and b/data/images/flags/sj.png differ
diff --git a/data/images/flags/sk.png b/data/images/flags/sk.png
new file mode 100644
index 0000000..ee88a07
Binary files /dev/null and b/data/images/flags/sk.png differ
diff --git a/data/images/flags/sl.png b/data/images/flags/sl.png
new file mode 100644
index 0000000..608e0fe
Binary files /dev/null and b/data/images/flags/sl.png differ
diff --git a/data/images/flags/sm.png b/data/images/flags/sm.png
new file mode 100644
index 0000000..e38069d
Binary files /dev/null and b/data/images/flags/sm.png differ
diff --git a/data/images/flags/sn.png b/data/images/flags/sn.png
new file mode 100644
index 0000000..4b99a66
Binary files /dev/null and b/data/images/flags/sn.png differ
diff --git a/data/images/flags/so.png b/data/images/flags/so.png
new file mode 100644
index 0000000..53db903
Binary files /dev/null and b/data/images/flags/so.png differ
diff --git a/data/images/flags/sr.png b/data/images/flags/sr.png
new file mode 100644
index 0000000..8643fae
Binary files /dev/null and b/data/images/flags/sr.png differ
diff --git a/data/images/flags/st.png b/data/images/flags/st.png
new file mode 100644
index 0000000..2704149
Binary files /dev/null and b/data/images/flags/st.png differ
diff --git a/data/images/flags/sv.png b/data/images/flags/sv.png
new file mode 100644
index 0000000..f27b9be
Binary files /dev/null and b/data/images/flags/sv.png differ
diff --git a/data/images/flags/sy.png b/data/images/flags/sy.png
new file mode 100644
index 0000000..8816583
Binary files /dev/null and b/data/images/flags/sy.png differ
diff --git a/data/images/flags/sz.png b/data/images/flags/sz.png
new file mode 100644
index 0000000..fc4bb02
Binary files /dev/null and b/data/images/flags/sz.png differ
diff --git a/data/images/flags/tc.png b/data/images/flags/tc.png
new file mode 100644
index 0000000..162ed8a
Binary files /dev/null and b/data/images/flags/tc.png differ
diff --git a/data/images/flags/td.png b/data/images/flags/td.png
new file mode 100644
index 0000000..3801b2f
Binary files /dev/null and b/data/images/flags/td.png differ
diff --git a/data/images/flags/tf.png b/data/images/flags/tf.png
new file mode 100644
index 0000000..c1a5395
Binary files /dev/null and b/data/images/flags/tf.png differ
diff --git a/data/images/flags/tg.png b/data/images/flags/tg.png
new file mode 100644
index 0000000..2f80fe0
Binary files /dev/null and b/data/images/flags/tg.png differ
diff --git a/data/images/flags/th.png b/data/images/flags/th.png
new file mode 100644
index 0000000..bbe1475
Binary files /dev/null and b/data/images/flags/th.png differ
diff --git a/data/images/flags/tj.png b/data/images/flags/tj.png
new file mode 100644
index 0000000..1f1b0da
Binary files /dev/null and b/data/images/flags/tj.png differ
diff --git a/data/images/flags/tk.png b/data/images/flags/tk.png
new file mode 100644
index 0000000..643c127
Binary files /dev/null and b/data/images/flags/tk.png differ
diff --git a/data/images/flags/tl.png b/data/images/flags/tl.png
new file mode 100644
index 0000000..1babb2b
Binary files /dev/null and b/data/images/flags/tl.png differ
diff --git a/data/images/flags/tm.png b/data/images/flags/tm.png
new file mode 100644
index 0000000..5b75e7a
Binary files /dev/null and b/data/images/flags/tm.png differ
diff --git a/data/images/flags/tn.png b/data/images/flags/tn.png
new file mode 100644
index 0000000..9d7f7e3
Binary files /dev/null and b/data/images/flags/tn.png differ
diff --git a/data/images/flags/to.png b/data/images/flags/to.png
new file mode 100644
index 0000000..bc2d043
Binary files /dev/null and b/data/images/flags/to.png differ
diff --git a/data/images/flags/tp.png b/data/images/flags/tp.png
new file mode 100644
index 0000000..1babb2b
Binary files /dev/null and b/data/images/flags/tp.png differ
diff --git a/data/images/flags/tr.png b/data/images/flags/tr.png
new file mode 100644
index 0000000..a7d1558
Binary files /dev/null and b/data/images/flags/tr.png differ
diff --git a/data/images/flags/tt.png b/data/images/flags/tt.png
new file mode 100644
index 0000000..4d18c03
Binary files /dev/null and b/data/images/flags/tt.png differ
diff --git a/data/images/flags/tv.png b/data/images/flags/tv.png
new file mode 100644
index 0000000..d423b04
Binary files /dev/null and b/data/images/flags/tv.png differ
diff --git a/data/images/flags/tw.png b/data/images/flags/tw.png
new file mode 100644
index 0000000..f233d0a
Binary files /dev/null and b/data/images/flags/tw.png differ
diff --git a/data/images/flags/tz.png b/data/images/flags/tz.png
new file mode 100644
index 0000000..8816583
Binary files /dev/null and b/data/images/flags/tz.png differ
diff --git a/data/images/flags/ua.png b/data/images/flags/ua.png
new file mode 100644
index 0000000..1ff1a18
Binary files /dev/null and b/data/images/flags/ua.png differ
diff --git a/data/images/flags/ug.png b/data/images/flags/ug.png
new file mode 100644
index 0000000..69c83f8
Binary files /dev/null and b/data/images/flags/ug.png differ
diff --git a/data/images/flags/um.png b/data/images/flags/um.png
new file mode 100644
index 0000000..ac54a98
Binary files /dev/null and b/data/images/flags/um.png differ
diff --git a/data/images/flags/us.png b/data/images/flags/us.png
new file mode 100644
index 0000000..ac54a98
Binary files /dev/null and b/data/images/flags/us.png differ
diff --git a/data/images/flags/uy.png b/data/images/flags/uy.png
new file mode 100644
index 0000000..7e58ac4
Binary files /dev/null and b/data/images/flags/uy.png differ
diff --git a/data/images/flags/uz.png b/data/images/flags/uz.png
new file mode 100644
index 0000000..76707c5
Binary files /dev/null and b/data/images/flags/uz.png differ
diff --git a/data/images/flags/va.png b/data/images/flags/va.png
new file mode 100644
index 0000000..2969236
Binary files /dev/null and b/data/images/flags/va.png differ
diff --git a/data/images/flags/vc.png b/data/images/flags/vc.png
new file mode 100644
index 0000000..93164d1
Binary files /dev/null and b/data/images/flags/vc.png differ
diff --git a/data/images/flags/ve.png b/data/images/flags/ve.png
new file mode 100644
index 0000000..92844bb
Binary files /dev/null and b/data/images/flags/ve.png differ
diff --git a/data/images/flags/vg.png b/data/images/flags/vg.png
new file mode 100644
index 0000000..8d226ef
Binary files /dev/null and b/data/images/flags/vg.png differ
diff --git a/data/images/flags/vi.png b/data/images/flags/vi.png
new file mode 100644
index 0000000..7916f3a
Binary files /dev/null and b/data/images/flags/vi.png differ
diff --git a/data/images/flags/vn.png b/data/images/flags/vn.png
new file mode 100644
index 0000000..538b081
Binary files /dev/null and b/data/images/flags/vn.png differ
diff --git a/data/images/flags/vu.png b/data/images/flags/vu.png
new file mode 100644
index 0000000..e514f7b
Binary files /dev/null and b/data/images/flags/vu.png differ
diff --git a/data/images/flags/wf.png b/data/images/flags/wf.png
new file mode 100644
index 0000000..2154ef8
Binary files /dev/null and b/data/images/flags/wf.png differ
diff --git a/data/images/flags/ws.png b/data/images/flags/ws.png
new file mode 100644
index 0000000..8a26405
Binary files /dev/null and b/data/images/flags/ws.png differ
diff --git a/data/images/flags/xt.png b/data/images/flags/xt.png
new file mode 100644
index 0000000..ce3d8b3
Binary files /dev/null and b/data/images/flags/xt.png differ
diff --git a/data/images/flags/ye.png b/data/images/flags/ye.png
new file mode 100644
index 0000000..5b4520f
Binary files /dev/null and b/data/images/flags/ye.png differ
diff --git a/data/images/flags/yt.png b/data/images/flags/yt.png
new file mode 100644
index 0000000..c1a5395
Binary files /dev/null and b/data/images/flags/yt.png differ
diff --git a/data/images/flags/yu.png b/data/images/flags/yu.png
new file mode 100644
index 0000000..7a89a78
Binary files /dev/null and b/data/images/flags/yu.png differ
diff --git a/data/images/flags/za.png b/data/images/flags/za.png
new file mode 100644
index 0000000..38a122c
Binary files /dev/null and b/data/images/flags/za.png differ
diff --git a/data/images/flags/zm.png b/data/images/flags/zm.png
new file mode 100644
index 0000000..7503819
Binary files /dev/null and b/data/images/flags/zm.png differ
diff --git a/data/images/flags/zw.png b/data/images/flags/zw.png
new file mode 100644
index 0000000..0ccea68
Binary files /dev/null and b/data/images/flags/zw.png differ
diff --git a/data/images/login/login.png b/data/images/login/login.png
new file mode 100644
index 0000000..b50ec42
Binary files /dev/null and b/data/images/login/login.png differ
diff --git a/data/images/misc.png b/data/images/misc.png
new file mode 100644
index 0000000..b94c2cf
Binary files /dev/null and b/data/images/misc.png differ
diff --git a/data/texts/AboutBundleManager.html b/data/texts/AboutBundleManager.html
new file mode 100644
index 0000000..7157d1e
--- /dev/null
+++ b/data/texts/AboutBundleManager.html
@@ -0,0 +1,36 @@
+
+
+
+
+ A propos de BundleManager V1
+
+
+
+ BundleManager V1
+
+
+ Ce programme est libre, a été conçu pour illustrer l'apprentissage du langage Java.
+
+
+ Tout ou partie de ce programme à vocation à êre recopié.
+ En revanche, les explications qui accompagnent ce programme ne sont pas libre de droits.
+
+
+
misc@merciol.fr
+
+
+
diff --git a/data/texts/AboutChat.html b/data/texts/AboutChat.html
new file mode 100644
index 0000000..d2cae99
--- /dev/null
+++ b/data/texts/AboutChat.html
@@ -0,0 +1,36 @@
+
+
+
+
+ A propos de BundleManager V1
+
+
+
+ Chat V1
+
+
+ Ce programme est libre, a été conçu pour illustrer l'apprentissage du langage Java.
+
+
+ Tout ou partie de ce programme à vocation à êre recopié.
+ En revanche, les explications qui accompagnent ce programme ne sont pas libre de droits.
+
+
+
misc@merciol.fr
+
+
+
diff --git a/data/texts/AboutLogin.html b/data/texts/AboutLogin.html
new file mode 100644
index 0000000..34ece3f
--- /dev/null
+++ b/data/texts/AboutLogin.html
@@ -0,0 +1,36 @@
+
+
+
+
+ A propos de BundleManager V1
+
+
+
+ Login V1
+
+
+ Ce programme est libre, a été conçu pour illustrer l'apprentissage du langage Java.
+
+
+ Tout ou partie de ce programme à vocation à êre recopié.
+ En revanche, les explications qui accompagnent ce programme ne sont pas libre de droits.
+
+
+
misc@merciol.fr
+
+
+
diff --git a/data/texts/AboutMisc.html b/data/texts/AboutMisc.html
new file mode 100644
index 0000000..baeda63
--- /dev/null
+++ b/data/texts/AboutMisc.html
@@ -0,0 +1,39 @@
+
+
+
+
+ A propos de Misc
+
+
+
+ Misc (23/05/2016)
+
+
+ Ce programme est libre et a été conçu pour illustrer l'apprentissage du langage Java.
+
+
+ Tout ou partie de ce programme à vocation à êre recopié.
+ En revanche, les explications qui accompagnent ce programme ne sont pas libre de droits.
+
+
+ http://misc.parlenet.org/
+
+
+
misc@merciol.fr
+
+
+
diff --git a/data/texts/BundleManagerLicence.html b/data/texts/BundleManagerLicence.html
new file mode 100644
index 0000000..b6f1e61
--- /dev/null
+++ b/data/texts/BundleManagerLicence.html
@@ -0,0 +1,653 @@
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
Avertissement
+
+
Ce contrat est une licence de logiciel libre issue d'une
+ concertation entre ses auteurs afin que le respect de deux
+ grands principes préside à sa rédaction:
+
+ d'une part, le respect des principes de diffusion des
+ logiciels libres: accès au code source, droits étendus
+ conférés aux utilisateurs,
+ d'autre part, la désignation d'un droit applicable, le
+ droit français, auquel elle est conforme, tant au regard du
+ droit de la responsabilité civile que du droit de la
+ propriété intellectuelle et de la protection qu'il offre aux
+ auteurs et titulaires des droits patrimoniaux sur un
+ logiciel.
+
+
+
Les auteurs de la licence
+ CeCILL-B1 sont:
+
+
Commissariat à l'Energie Atomique - CEA, établissement public
+ de recherche à caractère scientifique, technique et
+ industriel, dont le siège est situé 25 rue Leblanc, immeuble
+ Le Ponant D, 75015 Paris.
+
Centre National de la Recherche Scientifique - CNRS,
+ établissement public à caractère scientifique et
+ technologique, dont le siège est situé 3 rue Michel-Ange,
+ 75794 Paris cedex 16.
+
+
Institut National de Recherche en Informatique et en
+ Automatique - INRIA, établissement public à caractère
+ scientifique et technologique, dont le siège est situé Domaine
+ de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex.
+
+
+
+
Préambule
+
Ce contrat est une licence de logiciel libre dont l'objectif
+ est de conférer aux utilisateurs une très large liberté de
+ modification et de redistribution du logiciel régi par cette
+ licence.
+
L'exercice de cette liberté est assorti d'une obligation
+ forte de citation à la charge de ceux qui distribueraient un
+ logiciel incorporant un logiciel régi par la présente licence
+ afin d'assurer que les contributions de tous soient
+ correctement identifiées et reconnues.
+
L'accessibilité au code source et les droits de copie, de
+ modification et de redistribution qui découlent de ce contrat
+ ont pour contrepartie de n'offrir aux utilisateurs qu'une
+ garantie limitée et de ne faire peser sur l'auteur du
+ logiciel, le titulaire des droits patrimoniaux et les
+ concédants successifs qu'une responsabilité restreinte.
+
A cet égard l'attention de l'utilisateur est attirée sur les
+ risques associés au chargement, à l'utilisation, à la
+ modification et/ou au développement et à la reproduction du
+ logiciel par l'utilisateur étant donné sa spécificité de
+ logiciel libre, qui peut le rendre complexe à manipuler et qui
+ le réserve donc à des développeurs ou des professionnels
+ avertis possédant des connaissances informatiques
+ approfondies. Les utilisateurs sont donc invités à charger et
+ tester l'adéquation du logiciel à leurs besoins dans des
+ conditions permettant d'assurer la sécurité de leurs systèmes
+ et/ou de leurs données et, plus généralement, à l'utiliser et
+ l'exploiter dans les mêmes conditions de sécurité. Ce contrat
+ peut être reproduit et diffusé librement, sous réserve de le
+ conserver en l'état, sans ajout ni suppression de
+ clauses.
+
Ce contrat est susceptible de s'appliquer à tout logiciel
+ dont le titulaire des droits patrimoniaux décide de soumettre
+ l'exploitation aux dispositions qu'il contient.
+
+
+
+
Article 1 - DEFINITIONS
+
Dans ce contrat, les termes suivants, lorsqu'ils seront
+ écrits avec une lettre capitale, auront la signification
+ suivante:
+
Contrat :
+ désigne le présent contrat de licence, ses éventuelles
+ versions postérieures et annexes.
+
Logiciel :
+ désigne le logiciel sous sa forme de Code Objet et/ou de Code
+ Source et le cas échéant sa documentation, dans leur état au
+ moment de l'acceptation du Contrat par le Licencié.
+
Logiciel
+ Initial : désigne le Logiciel sous sa forme de Code
+ Source et éventuellement de Code Objet et le cas échéant sa
+ documentation, dans leur état au moment de leur première
+ diffusion sous les termes du Contrat.
+
Logiciel
+ Modifié : désigne le Logiciel modifié par au moins une
+ Contribution.
+
Code
+ Source : désigne l'ensemble des instructions et des
+ lignes de programme du Logiciel et auquel l'accès est
+ nécessaire en vue de modifier le Logiciel.
+
Code
+ Objet : désigne les fichiers binaires issus de la
+ compilation du Code Source.
+
Titulaire :
+ désigne le ou les détenteurs des droits patrimoniaux d'auteur
+ sur le Logiciel Initial.
+
Licencié :
+ désigne le ou les utilisateurs du Logiciel ayant accepté le
+ Contrat.
+
Contributeur :
+ désigne le Licencié auteur d'au moins une Contribution.
+
Concédant :
+ désigne le Titulaire ou toute personne physique ou morale
+ distribuant le Logiciel sous le Contrat.
+
Contribution :
+ désigne l'ensemble des modifications, corrections,
+ traductions, adaptations et/ou nouvelles fonctionnalités
+ intégrées dans le Logiciel par tout Contributeur, ainsi que
+ tout Module Interne.
+
Module :
+ désigne un ensemble de fichiers sources y compris leur
+ documentation qui permet de réaliser des fonctionnalités ou
+ services supplémentaires à ceux fournis par le Logiciel.
+
Module
+ Externe : désigne tout Module, non dérivé du Logiciel, tel
+ que ce Module et le Logiciel s'exécutent dans des espaces
+ d'adressage différents, l'un appelant l'autre au moment de leur
+ exécution.
+
Module
+ Interne : désigne tout Module lié au Logiciel de telle
+ sorte qu'ils s'exécutent dans le même espace
+ d'adressage.
+
Parties :
+ désigne collectivement le Licencié et le Concédant.
+
Ces termes s'entendent au singulier comme au pluriel.
+
+
+
Article 2 - OBJET
+
Le Contrat a pour objet la concession par le Concédant au
+ Licencié d'une licence non exclusive, cessible et mondiale du
+ Logiciel telle que définie ci-après à
+ l'article 5
+ pour toute la durée de protection des droits portant sur ce
+ Logiciel.
+
+
+
Article 3 - ACCEPTATION
+
+
3.1
+ L'acceptation par le Licencié des termes du Contrat est
+ réputée acquise du fait du premier des faits suivants:
+
+ (i) le chargement du Logiciel par tout moyen notamment
+ par téléchargement à partir d'un serveur distant ou par
+ chargement à partir d'un support physique;
+ (ii) le premier exercice par le Licencié de l'un
+ quelconque des droits concédés par le Contrat.
+
+
+
+
3.2 Un exemplaire du
+ Contrat, contenant notamment un avertissement relatif aux
+ spécificités du Logiciel, à la restriction de garantie et à
+ la limitation à un usage par des utilisateurs expérimentés a
+ été mis à disposition du Licencié préalablement à son
+ acceptation telle que définie à
+ l'article 3.1
+ ci dessus et le Licencié reconnaît en avoir pris
+ connaissance.
+
+
+
+
Article 4 - ENTREE EN VIGUEUR ET DUREE
+
+
4.1 ENTREE EN VIGUEUR
+
Le Contrat entre en vigueur à la date de son acceptation
+ par le Licencié telle que définie
+ en 3.1 .
+
+
+
4.2 DUREE
+
Le Contrat produira ses effets pendant toute la durée
+ légale de protection des droits patrimoniaux portant sur le
+ Logiciel.
+
+
+
+
+ Article 5 - ETENDUE DES DROITS
+ CONCEDES
+
Le Concédant concède au Licencié, qui accepte, les droits
+ suivants sur le Logiciel pour toutes destinations et pour la
+ durée du Contrat dans les conditions ci-après
+ détaillées.
+
Par ailleurs, si le Concédant détient ou venait à détenir un
+ ou plusieurs brevets d'invention protégeant tout ou partie des
+ fonctionnalités du Logiciel ou de ses composants, il s'engage
+ à ne pas opposer les éventuels droits conférés par ces brevets
+ aux Licenciés successifs qui utiliseraient, exploiteraient ou
+ modifieraient le Logiciel. En cas de cession de ces brevets,
+ le Concédant s'engage à faire reprendre les obligations du
+ présent alinéa aux cessionnaires.
+
+
5.1 DROIT
+ D'UTILISATION
+
+
Le Licencié est autorisé à utiliser le Logiciel, sans
+ restriction quant aux domaines d'application, étant ci-après
+ précisé que cela comporte:
+
+ la reproduction permanente ou provisoire du Logiciel
+ en tout ou partie par tout moyen et sous toute
+ forme.
+ le chargement, l'affichage, l'exécution, ou le
+ stockage du Logiciel sur tout support.
+ la possibilité d'en observer, d'en étudier, ou d'en
+ tester le fonctionnement afin de déterminer les idées et
+ principes qui sont à la base de n'importe quel élément
+ de ce Logiciel; et ceci, lorsque le Licencié effectue
+ toute opération de chargement, d'affichage, d'exécution,
+ de transmission ou de stockage du Logiciel qu'il est en
+ droit d'effectuer en vertu du Contrat.
+
+
+
+
5.2 DROIT D'APPORTER DES
+ CONTRIBUTIONS
+
Le droit d'apporter des Contributions comporte le droit de
+ traduire, d'adapter, d'arranger ou d'apporter toute autre
+ modification au Logiciel et le droit de reproduire le
+ logiciel en résultant.
+
Le Licencié est autorisé à apporter toute Contribution au
+ Logiciel sous réserve de mentionner, de façon explicite, son
+ nom en tant qu'auteur de cette Contribution et la date de
+ création de celle-ci.
+
+
+
5.3 DROIT DE
+ DISTRIBUTION
+
Le droit de distribution comporte notamment le droit de
+ diffuser, de transmettre et de communiquer le Logiciel au
+ public sur tout support et par tout moyen ainsi que le droit
+ de mettre sur le marché à titre onéreux ou gratuit, un ou
+ des exemplaires du Logiciel par tout procédé.
+
Le Licencié est autorisé à distribuer des copies du
+ Logiciel, modifié ou non, à des tiers dans les conditions
+ ci-après détaillées.
+
+
5.3.1 DISTRIBUTION DU
+ LOGICIEL SANS MODIFICATION
+
Le Licencié est autorisé à distribuer des copies
+ conformes du Logiciel, sous forme de Code Source ou de
+ Code Objet, à condition que cette distribution respecte
+ les dispositions du Contrat dans leur totalité et soit
+ accompagnée:
+
+ d'un exemplaire du Contrat,
+ d'un avertissement relatif à la restriction de
+ garantie et de responsabilité du Concédant telle que
+ prévue aux
+ articles 8
+ et 9 ,
+
+
et que, dans le cas où seul le Code Objet du Logiciel est
+ redistribué, le Licencié permette un accès effectif au
+ Code Source complet du Logiciel pendant au moins toute la
+ durée de sa distribution du Logiciel, étant entendu que le
+ coût additionnel d'acquisition du Code Source ne devra pas
+ excéder le simple coût de transfert des données.
+
+
+
+ 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE
+
Lorsque le Licencié apporte une Contribution au Logiciel,
+ le Logiciel Modifié peut être distribué sous un contrat de
+ licence autre que le présent Contrat sous réserve du
+ respect des dispositions de l'article
+ 5.3.4 .
+
+
+
5.3.3 DISTRIBUTION DES
+ MODULES EXTERNES
+
Lorsque le Licencié a développé un Module Externe les
+ conditions du Contrat ne s'appliquent pas à ce Module
+ Externe, qui peut être distribué sous un contrat de
+ licence différent.
+
+
+
5.3.4 CITATIONS
+
Le Licencié qui distribue un Logiciel Modifié s'engage
+ expressément:
+
+ à indiquer dans sa documentation qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+
+ à faire en sorte que l'utilisation du Logiciel, ses
+ mentions de propriété intellectuelle et le fait qu'il
+ est régi par le Contrat soient indiqués dans un texte
+ facilement accessible depuis l'interface du Logiciel
+ Modifié,
+ à mentionner, sur un site Web librement accessible
+ décrivant le Logiciel Modifié, et pendant au moins
+ toute la durée de sa distribution, qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+ lorsqu'il le distribue à un tiers susceptible de
+ distribuer lui-même un Logiciel Modifié, sans avoir à
+ en distribuer le code source, à faire ses meilleurs
+ efforts pour que les obligations du présent
+ article 5.3.4
+ soient reprises par le dit tiers.
+
+
Lorsque le Logiciel modifié ou non est distribué avec un
+ Module Externe qui a été conçu pour l'utiliser, le
+ Licencié doit soumettre le dit Module Externe aux
+ obligations précédentes.
+
+
+
5.3.5 COMPATIBILITE
+ AVEC LES LICENCES CeCILL et CeCILL-C
+
Lorsqu'un Logiciel Modifié contient une Contribution
+ soumise au contrat de licence CeCILL, les stipulations
+ prévues à
+ l'article 5.3.4
+ sont facultatives.
+
Un Logiciel Modifié peut être distribué sous le contrat
+ de licence CeCILL-C. Les stipulations prévues à
+ l'article 5.3.4
+ sont alors facultatives.
+
+
+
+
+
Article 6 - PROPRIETE INTELLECTUELLE
+
+
6.1 SUR LE LOGICIEL
+ INITIAL
+
Le Titulaire est détenteur des droits patrimoniaux sur le
+ Logiciel Initial. Toute utilisation du Logiciel Initial est
+ soumise au respect des conditions dans lesquelles le
+ Titulaire a choisi de diffuser son oeuvre et nul autre n'a
+ la faculté de modifier les conditions de diffusion de ce
+ Logiciel Initial.
+
Le Titulaire s'engage à ce que le Logiciel Initial reste au
+ moins régi par le Contrat et ce, pour la durée visée à
+ l'article 4.2 .
+
+
+
6.2 SUR LES
+ CONTRIBUTIONS
+
Le Licencié qui a développé une Contribution est titulaire
+ sur celle-ci des droits de propriété intellectuelle dans les
+ conditions définies par la législation applicable.
+
+
+
6.3 SUR LES MODULES
+ EXTERNES
+
Le Licencié qui a développé un Module Externe est
+ titulaire sur celui-ci des droits de propriété
+ intellectuelle dans les conditions définies par la
+ législation applicable et reste libre du choix du contrat
+ régissant sa diffusion.
+
+
+
6.4 DISPOSITIONS
+ COMMUNES
+
+
Le Licencié s'engage expressément:
+
+ à ne pas supprimer ou modifier de quelque manière
+ que ce soit les mentions de propriété intellectuelle
+ apposées sur le Logiciel;
+ à reproduire à l'identique lesdites mentions de
+ propriété intellectuelle sur les copies du Logiciel
+ modifié ou non.
+
+
+
+
Le Licencié s'engage à ne pas porter atteinte,
+ directement ou indirectement, aux droits de propriété
+ intellectuelle du Titulaire et/ou des Contributeurs sur le
+ Logiciel et à prendre, le cas échéant, à l'égard de son
+ personnel toutes les mesures nécessaires pour assurer le
+ respect des dits droits de propriété intellectuelle du
+ Titulaire et/ou des Contributeurs.
+
+
+
+
+
Article 7 - SERVICES ASSOCIES
+
+
7.1 Le Contrat n'oblige en
+ aucun cas le Concédant à la réalisation de prestations
+ d'assistance technique ou de maintenance du Logiciel.
+
Cependant le Concédant reste libre de proposer ce type de
+ services. Les termes et conditions d'une telle assistance
+ technique et/ou d'une telle maintenance seront alors
+ déterminés dans un acte séparé. Ces actes de maintenance
+ et/ou assistance technique n'engageront que la seule
+ responsabilité du Concédant qui les propose.
+
+
+
7.2 De même, tout Concédant
+ est libre de proposer, sous sa seule responsabilité, à ses
+ licenciés une garantie, qui n'engagera que lui, lors de la
+ redistribution du Logiciel et/ou du Logiciel Modifié et ce,
+ dans les conditions qu'il souhaite. Cette garantie et les
+ modalités financières de son application feront l'objet d'un
+ acte séparé entre le Concédant et le Licencié.
+
+
+
+
+ Article 8 -
+ RESPONSABILITE
+
+
8.1 Sous réserve des
+ dispositions de
+ l'article 8.2 ,
+ le Licencié a la faculté, sous réserve de prouver la faute
+ du Concédant concerné, de solliciter la réparation du
+ préjudice direct qu'il subirait du fait du Logiciel et dont
+ il apportera la preuve.
+
+
+
8.2
+ La responsabilité du Concédant est limitée aux engagements
+ pris en application du Contrat et ne saurait être engagée en
+ raison notamment: (i) des dommages dus à l'inexécution,
+ totale ou partielle, de ses obligations par le Licencié,
+ (ii) des dommages directs ou indirects découlant de
+ l'utilisation ou des performances du Logiciel subis par le
+ Licencié et (iii) plus généralement d'un quelconque dommage
+ indirect. En particulier, les Parties conviennent
+ expressément que tout préjudice financier ou commercial (par
+ exemple perte de données, perte de bénéfices, perte
+ d'exploitation, perte de clientèle ou de commandes, manque à
+ gagner, trouble commercial quelconque) ou toute action
+ dirigée contre le Licencié par un tiers, constitue un
+ dommage indirect et n'ouvre pas droit à réparation par le
+ Concédant.
+
+
+
+
+ Article 9 - GARANTIE
+
+
9.1 Le Licencié reconnaît
+ que l'état actuel des connaissances scientifiques et
+ techniques au moment de la mise en circulation du Logiciel
+ ne permet pas d'en tester et d'en vérifier toutes les
+ utilisations ni de détecter l'existence d'éventuels défauts.
+ L'attention du Licencié a été attirée sur ce point sur les
+ risques associés au chargement, à l'utilisation, la
+ modification et/ou au développement et à la reproduction du
+ Logiciel qui sont réservés à des utilisateurs avertis.
+
Il relève de la responsabilité du Licencié de contrôler,
+ par tous moyens, l'adéquation du produit à ses besoins, son
+ bon fonctionnement et de s'assurer qu'il ne causera pas de
+ dommages aux personnes et aux biens.
+
+
+
9.2
+ Le Concédant déclare de bonne foi être en droit de concéder
+ l'ensemble des droits attachés au Logiciel (comprenant
+ notamment les droits visés à l'article
+ 5 ).
+
+
+
9.3 Le Licencié reconnaît
+ que le Logiciel est fourni "en l'état" par le Concédant sans
+ autre garantie, expresse ou tacite, que celle prévue à
+ l'article 9.2
+ et notamment sans aucune garantie sur sa valeur commerciale,
+ son caractère sécurisé, innovant ou pertinent.
+
En particulier, le Concédant ne garantit pas que le
+ Logiciel est exempt d'erreur, qu'il fonctionnera sans
+ interruption, qu'il sera compatible avec l'équipement du
+ Licencié et sa configuration logicielle ni qu'il remplira
+ les besoins du Licencié.
+
+
+
9.4 Le Concédant ne garantit
+ pas, de manière expresse ou tacite, que le Logiciel ne porte
+ pas atteinte à un quelconque droit de propriété
+ intellectuelle d'un tiers portant sur un brevet, un logiciel
+ ou sur tout autre droit de propriété. Ainsi, le Concédant
+ exclut toute garantie au profit du Licencié contre les
+ actions en contrefaçon qui pourraient être diligentées au
+ titre de l'utilisation, de la modification, et de la
+ redistribution du Logiciel. Néanmoins, si de telles actions
+ sont exercées contre le Licencié, le Concédant lui apportera
+ son aide technique et juridique pour sa défense. Cette aide
+ technique et juridique est déterminée au cas par cas entre
+ le Concédant concerné et le Licencié dans le cadre d'un
+ protocole d'accord. Le Concédant dégage toute responsabilité
+ quant à l'utilisation de la dénomination du Logiciel par le
+ Licencié. Aucune garantie n'est apportée quant à l'existence
+ de droits antérieurs sur le nom du Logiciel et sur
+ l'existence d'une marque.
+
+
+
+
Article 10 -
+ RESILIATION
+
+
10.1 En cas de manquement
+ par le Licencié aux obligations mises à sa charge par le
+ Contrat, le Concédant pourra résilier de plein droit le
+ Contrat trente (30) jours après notification adressée au
+ Licencié et restée sans effet.
+
+
+
10.2 Le Licencié dont le
+ Contrat est résilié n'est plus autorisé à utiliser, modifier
+ ou distribuer le Logiciel. Cependant, toutes les licences
+ qu'il aura concédées antérieurement à la résiliation du
+ Contrat resteront valides sous réserve qu'elles aient été
+ effectuées en conformité avec le Contrat.
+
+
+
+
Article 11 - DISPOSITIONS
+ DIVERSES
+
+
+ 11.1 CAUSE EXTERIEURE
+
Aucune
+ des Parties ne sera responsable d'un retard ou d'une
+ défaillance d'exécution du Contrat qui serait dû
+ à un cas de force majeure, un cas fortuit ou une cause
+ extérieure, telle que, notamment, le mauvais fonctionnement
+ ou les interruptions du réseau électrique ou de
+ télécommunication, la paralysie du réseau liée
+ à une attaque informatique, l'intervention des
+ autorités gouvernementales, les catastrophes naturelles, les
+ dégâts des eaux, les tremblements de terre, le feu, les
+ explosions, les grèves et les conflits sociaux, l'état
+ de guerre...
+
+
+
11.2 Le
+ fait, par l'une ou l'autre des Parties, d'omettre
+ en une ou plusieurs occasions de se prévaloir d'une ou
+ plusieurs dispositions du Contrat, ne pourra en aucun cas impliquer
+ renonciation par la Partie intéressée à s'en
+ prévaloir ultérieurement.
+
+
+
11.3 Le Contrat annule et
+ remplace toute convention antérieure, écrite ou orale, entre
+ les Parties sur le même objet et constitue l'accord entier
+ entre les Parties sur cet objet. Aucune addition ou
+ modification aux termes du Contrat n'aura d'effet à l'égard
+ des Parties à moins d'être faite par écrit et signée par
+ leurs représentants dûment habilités.
+
+
+
11.4 Dans l'hypothèse où une
+ ou plusieurs des dispositions du Contrat s'avèrerait
+ contraire à une loi ou à un texte applicable, existants ou
+ futurs, cette loi ou ce texte prévaudrait, et les Parties
+ feraient les amendements nécessaires pour se conformer à
+ cette loi ou à ce texte. Toutes les autres dispositions
+ resteront en vigueur. De même, la nullité, pour quelque
+ raison que ce soit, d'une des dispositions du Contrat ne
+ saurait entraîner la nullité de l'ensemble du Contrat.
+
+
+
+ 11.5 LANGUE
+
Le Contrat est rédigé en langue française et en langue
+ anglaise, ces deux versions faisant également foi.
+
+
+
+
+
Article 12 - NOUVELLES
+ VERSIONS DU CONTRAT
+
+
12.1 Toute personne est
+ autorisée à copier et distribuer des copies de ce
+ Contrat.
+
+
+
12.2 Afin d'en préserver la
+ cohérence, le texte du Contrat est protégé et ne peut être
+ modifié que par les auteurs de la licence, lesquels se
+ réservent le droit de publier périodiquement des mises à
+ jour ou de nouvelles versions du Contrat, qui posséderont
+ chacune un numéro distinct. Ces versions ultérieures seront
+ susceptibles de prendre en compte de nouvelles
+ problématiques rencontrées par les logiciels libres.
+
+
+
12.3 Tout Logiciel diffusé
+ sous une version donnée du Contrat ne pourra faire l'objet
+ d'une diffusion ultérieure que sous la même version du
+ Contrat ou une version postérieure.
+
+
+
+
Article 13 - LOI APPLICABLE
+ ET COMPETENCE TERRITORIALE
+
+
13.1 Le Contrat est régi
+ par la loi française. Les Parties conviennent de tenter de
+ régler à l'amiable les différends ou litiges qui viendraient
+ à se produire par suite ou à l'occasion du Contrat.
+
+
+
+
13.2 A défaut d'accord
+ amiable dans un délai de deux (2) mois à compter de leur
+ survenance et sauf situation relevant d'une procédure
+ d'urgence, les différends ou litiges seront portés par la
+ Partie la plus diligente devant les Tribunaux compétents de
+ Paris.
+
+
+
+ Version 1.0 du 2006-09-05.
+
+
diff --git a/data/texts/ChatLicence.html b/data/texts/ChatLicence.html
new file mode 100644
index 0000000..b6f1e61
--- /dev/null
+++ b/data/texts/ChatLicence.html
@@ -0,0 +1,653 @@
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
Avertissement
+
+
Ce contrat est une licence de logiciel libre issue d'une
+ concertation entre ses auteurs afin que le respect de deux
+ grands principes préside à sa rédaction:
+
+ d'une part, le respect des principes de diffusion des
+ logiciels libres: accès au code source, droits étendus
+ conférés aux utilisateurs,
+ d'autre part, la désignation d'un droit applicable, le
+ droit français, auquel elle est conforme, tant au regard du
+ droit de la responsabilité civile que du droit de la
+ propriété intellectuelle et de la protection qu'il offre aux
+ auteurs et titulaires des droits patrimoniaux sur un
+ logiciel.
+
+
+
Les auteurs de la licence
+ CeCILL-B1 sont:
+
+
Commissariat à l'Energie Atomique - CEA, établissement public
+ de recherche à caractère scientifique, technique et
+ industriel, dont le siège est situé 25 rue Leblanc, immeuble
+ Le Ponant D, 75015 Paris.
+
Centre National de la Recherche Scientifique - CNRS,
+ établissement public à caractère scientifique et
+ technologique, dont le siège est situé 3 rue Michel-Ange,
+ 75794 Paris cedex 16.
+
+
Institut National de Recherche en Informatique et en
+ Automatique - INRIA, établissement public à caractère
+ scientifique et technologique, dont le siège est situé Domaine
+ de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex.
+
+
+
+
Préambule
+
Ce contrat est une licence de logiciel libre dont l'objectif
+ est de conférer aux utilisateurs une très large liberté de
+ modification et de redistribution du logiciel régi par cette
+ licence.
+
L'exercice de cette liberté est assorti d'une obligation
+ forte de citation à la charge de ceux qui distribueraient un
+ logiciel incorporant un logiciel régi par la présente licence
+ afin d'assurer que les contributions de tous soient
+ correctement identifiées et reconnues.
+
L'accessibilité au code source et les droits de copie, de
+ modification et de redistribution qui découlent de ce contrat
+ ont pour contrepartie de n'offrir aux utilisateurs qu'une
+ garantie limitée et de ne faire peser sur l'auteur du
+ logiciel, le titulaire des droits patrimoniaux et les
+ concédants successifs qu'une responsabilité restreinte.
+
A cet égard l'attention de l'utilisateur est attirée sur les
+ risques associés au chargement, à l'utilisation, à la
+ modification et/ou au développement et à la reproduction du
+ logiciel par l'utilisateur étant donné sa spécificité de
+ logiciel libre, qui peut le rendre complexe à manipuler et qui
+ le réserve donc à des développeurs ou des professionnels
+ avertis possédant des connaissances informatiques
+ approfondies. Les utilisateurs sont donc invités à charger et
+ tester l'adéquation du logiciel à leurs besoins dans des
+ conditions permettant d'assurer la sécurité de leurs systèmes
+ et/ou de leurs données et, plus généralement, à l'utiliser et
+ l'exploiter dans les mêmes conditions de sécurité. Ce contrat
+ peut être reproduit et diffusé librement, sous réserve de le
+ conserver en l'état, sans ajout ni suppression de
+ clauses.
+
Ce contrat est susceptible de s'appliquer à tout logiciel
+ dont le titulaire des droits patrimoniaux décide de soumettre
+ l'exploitation aux dispositions qu'il contient.
+
+
+
+
Article 1 - DEFINITIONS
+
Dans ce contrat, les termes suivants, lorsqu'ils seront
+ écrits avec une lettre capitale, auront la signification
+ suivante:
+
Contrat :
+ désigne le présent contrat de licence, ses éventuelles
+ versions postérieures et annexes.
+
Logiciel :
+ désigne le logiciel sous sa forme de Code Objet et/ou de Code
+ Source et le cas échéant sa documentation, dans leur état au
+ moment de l'acceptation du Contrat par le Licencié.
+
Logiciel
+ Initial : désigne le Logiciel sous sa forme de Code
+ Source et éventuellement de Code Objet et le cas échéant sa
+ documentation, dans leur état au moment de leur première
+ diffusion sous les termes du Contrat.
+
Logiciel
+ Modifié : désigne le Logiciel modifié par au moins une
+ Contribution.
+
Code
+ Source : désigne l'ensemble des instructions et des
+ lignes de programme du Logiciel et auquel l'accès est
+ nécessaire en vue de modifier le Logiciel.
+
Code
+ Objet : désigne les fichiers binaires issus de la
+ compilation du Code Source.
+
Titulaire :
+ désigne le ou les détenteurs des droits patrimoniaux d'auteur
+ sur le Logiciel Initial.
+
Licencié :
+ désigne le ou les utilisateurs du Logiciel ayant accepté le
+ Contrat.
+
Contributeur :
+ désigne le Licencié auteur d'au moins une Contribution.
+
Concédant :
+ désigne le Titulaire ou toute personne physique ou morale
+ distribuant le Logiciel sous le Contrat.
+
Contribution :
+ désigne l'ensemble des modifications, corrections,
+ traductions, adaptations et/ou nouvelles fonctionnalités
+ intégrées dans le Logiciel par tout Contributeur, ainsi que
+ tout Module Interne.
+
Module :
+ désigne un ensemble de fichiers sources y compris leur
+ documentation qui permet de réaliser des fonctionnalités ou
+ services supplémentaires à ceux fournis par le Logiciel.
+
Module
+ Externe : désigne tout Module, non dérivé du Logiciel, tel
+ que ce Module et le Logiciel s'exécutent dans des espaces
+ d'adressage différents, l'un appelant l'autre au moment de leur
+ exécution.
+
Module
+ Interne : désigne tout Module lié au Logiciel de telle
+ sorte qu'ils s'exécutent dans le même espace
+ d'adressage.
+
Parties :
+ désigne collectivement le Licencié et le Concédant.
+
Ces termes s'entendent au singulier comme au pluriel.
+
+
+
Article 2 - OBJET
+
Le Contrat a pour objet la concession par le Concédant au
+ Licencié d'une licence non exclusive, cessible et mondiale du
+ Logiciel telle que définie ci-après à
+ l'article 5
+ pour toute la durée de protection des droits portant sur ce
+ Logiciel.
+
+
+
Article 3 - ACCEPTATION
+
+
3.1
+ L'acceptation par le Licencié des termes du Contrat est
+ réputée acquise du fait du premier des faits suivants:
+
+ (i) le chargement du Logiciel par tout moyen notamment
+ par téléchargement à partir d'un serveur distant ou par
+ chargement à partir d'un support physique;
+ (ii) le premier exercice par le Licencié de l'un
+ quelconque des droits concédés par le Contrat.
+
+
+
+
3.2 Un exemplaire du
+ Contrat, contenant notamment un avertissement relatif aux
+ spécificités du Logiciel, à la restriction de garantie et à
+ la limitation à un usage par des utilisateurs expérimentés a
+ été mis à disposition du Licencié préalablement à son
+ acceptation telle que définie à
+ l'article 3.1
+ ci dessus et le Licencié reconnaît en avoir pris
+ connaissance.
+
+
+
+
Article 4 - ENTREE EN VIGUEUR ET DUREE
+
+
4.1 ENTREE EN VIGUEUR
+
Le Contrat entre en vigueur à la date de son acceptation
+ par le Licencié telle que définie
+ en 3.1 .
+
+
+
4.2 DUREE
+
Le Contrat produira ses effets pendant toute la durée
+ légale de protection des droits patrimoniaux portant sur le
+ Logiciel.
+
+
+
+
+ Article 5 - ETENDUE DES DROITS
+ CONCEDES
+
Le Concédant concède au Licencié, qui accepte, les droits
+ suivants sur le Logiciel pour toutes destinations et pour la
+ durée du Contrat dans les conditions ci-après
+ détaillées.
+
Par ailleurs, si le Concédant détient ou venait à détenir un
+ ou plusieurs brevets d'invention protégeant tout ou partie des
+ fonctionnalités du Logiciel ou de ses composants, il s'engage
+ à ne pas opposer les éventuels droits conférés par ces brevets
+ aux Licenciés successifs qui utiliseraient, exploiteraient ou
+ modifieraient le Logiciel. En cas de cession de ces brevets,
+ le Concédant s'engage à faire reprendre les obligations du
+ présent alinéa aux cessionnaires.
+
+
5.1 DROIT
+ D'UTILISATION
+
+
Le Licencié est autorisé à utiliser le Logiciel, sans
+ restriction quant aux domaines d'application, étant ci-après
+ précisé que cela comporte:
+
+ la reproduction permanente ou provisoire du Logiciel
+ en tout ou partie par tout moyen et sous toute
+ forme.
+ le chargement, l'affichage, l'exécution, ou le
+ stockage du Logiciel sur tout support.
+ la possibilité d'en observer, d'en étudier, ou d'en
+ tester le fonctionnement afin de déterminer les idées et
+ principes qui sont à la base de n'importe quel élément
+ de ce Logiciel; et ceci, lorsque le Licencié effectue
+ toute opération de chargement, d'affichage, d'exécution,
+ de transmission ou de stockage du Logiciel qu'il est en
+ droit d'effectuer en vertu du Contrat.
+
+
+
+
5.2 DROIT D'APPORTER DES
+ CONTRIBUTIONS
+
Le droit d'apporter des Contributions comporte le droit de
+ traduire, d'adapter, d'arranger ou d'apporter toute autre
+ modification au Logiciel et le droit de reproduire le
+ logiciel en résultant.
+
Le Licencié est autorisé à apporter toute Contribution au
+ Logiciel sous réserve de mentionner, de façon explicite, son
+ nom en tant qu'auteur de cette Contribution et la date de
+ création de celle-ci.
+
+
+
5.3 DROIT DE
+ DISTRIBUTION
+
Le droit de distribution comporte notamment le droit de
+ diffuser, de transmettre et de communiquer le Logiciel au
+ public sur tout support et par tout moyen ainsi que le droit
+ de mettre sur le marché à titre onéreux ou gratuit, un ou
+ des exemplaires du Logiciel par tout procédé.
+
Le Licencié est autorisé à distribuer des copies du
+ Logiciel, modifié ou non, à des tiers dans les conditions
+ ci-après détaillées.
+
+
5.3.1 DISTRIBUTION DU
+ LOGICIEL SANS MODIFICATION
+
Le Licencié est autorisé à distribuer des copies
+ conformes du Logiciel, sous forme de Code Source ou de
+ Code Objet, à condition que cette distribution respecte
+ les dispositions du Contrat dans leur totalité et soit
+ accompagnée:
+
+ d'un exemplaire du Contrat,
+ d'un avertissement relatif à la restriction de
+ garantie et de responsabilité du Concédant telle que
+ prévue aux
+ articles 8
+ et 9 ,
+
+
et que, dans le cas où seul le Code Objet du Logiciel est
+ redistribué, le Licencié permette un accès effectif au
+ Code Source complet du Logiciel pendant au moins toute la
+ durée de sa distribution du Logiciel, étant entendu que le
+ coût additionnel d'acquisition du Code Source ne devra pas
+ excéder le simple coût de transfert des données.
+
+
+
+ 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE
+
Lorsque le Licencié apporte une Contribution au Logiciel,
+ le Logiciel Modifié peut être distribué sous un contrat de
+ licence autre que le présent Contrat sous réserve du
+ respect des dispositions de l'article
+ 5.3.4 .
+
+
+
5.3.3 DISTRIBUTION DES
+ MODULES EXTERNES
+
Lorsque le Licencié a développé un Module Externe les
+ conditions du Contrat ne s'appliquent pas à ce Module
+ Externe, qui peut être distribué sous un contrat de
+ licence différent.
+
+
+
5.3.4 CITATIONS
+
Le Licencié qui distribue un Logiciel Modifié s'engage
+ expressément:
+
+ à indiquer dans sa documentation qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+
+ à faire en sorte que l'utilisation du Logiciel, ses
+ mentions de propriété intellectuelle et le fait qu'il
+ est régi par le Contrat soient indiqués dans un texte
+ facilement accessible depuis l'interface du Logiciel
+ Modifié,
+ à mentionner, sur un site Web librement accessible
+ décrivant le Logiciel Modifié, et pendant au moins
+ toute la durée de sa distribution, qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+ lorsqu'il le distribue à un tiers susceptible de
+ distribuer lui-même un Logiciel Modifié, sans avoir à
+ en distribuer le code source, à faire ses meilleurs
+ efforts pour que les obligations du présent
+ article 5.3.4
+ soient reprises par le dit tiers.
+
+
Lorsque le Logiciel modifié ou non est distribué avec un
+ Module Externe qui a été conçu pour l'utiliser, le
+ Licencié doit soumettre le dit Module Externe aux
+ obligations précédentes.
+
+
+
5.3.5 COMPATIBILITE
+ AVEC LES LICENCES CeCILL et CeCILL-C
+
Lorsqu'un Logiciel Modifié contient une Contribution
+ soumise au contrat de licence CeCILL, les stipulations
+ prévues à
+ l'article 5.3.4
+ sont facultatives.
+
Un Logiciel Modifié peut être distribué sous le contrat
+ de licence CeCILL-C. Les stipulations prévues à
+ l'article 5.3.4
+ sont alors facultatives.
+
+
+
+
+
Article 6 - PROPRIETE INTELLECTUELLE
+
+
6.1 SUR LE LOGICIEL
+ INITIAL
+
Le Titulaire est détenteur des droits patrimoniaux sur le
+ Logiciel Initial. Toute utilisation du Logiciel Initial est
+ soumise au respect des conditions dans lesquelles le
+ Titulaire a choisi de diffuser son oeuvre et nul autre n'a
+ la faculté de modifier les conditions de diffusion de ce
+ Logiciel Initial.
+
Le Titulaire s'engage à ce que le Logiciel Initial reste au
+ moins régi par le Contrat et ce, pour la durée visée à
+ l'article 4.2 .
+
+
+
6.2 SUR LES
+ CONTRIBUTIONS
+
Le Licencié qui a développé une Contribution est titulaire
+ sur celle-ci des droits de propriété intellectuelle dans les
+ conditions définies par la législation applicable.
+
+
+
6.3 SUR LES MODULES
+ EXTERNES
+
Le Licencié qui a développé un Module Externe est
+ titulaire sur celui-ci des droits de propriété
+ intellectuelle dans les conditions définies par la
+ législation applicable et reste libre du choix du contrat
+ régissant sa diffusion.
+
+
+
6.4 DISPOSITIONS
+ COMMUNES
+
+
Le Licencié s'engage expressément:
+
+ à ne pas supprimer ou modifier de quelque manière
+ que ce soit les mentions de propriété intellectuelle
+ apposées sur le Logiciel;
+ à reproduire à l'identique lesdites mentions de
+ propriété intellectuelle sur les copies du Logiciel
+ modifié ou non.
+
+
+
+
Le Licencié s'engage à ne pas porter atteinte,
+ directement ou indirectement, aux droits de propriété
+ intellectuelle du Titulaire et/ou des Contributeurs sur le
+ Logiciel et à prendre, le cas échéant, à l'égard de son
+ personnel toutes les mesures nécessaires pour assurer le
+ respect des dits droits de propriété intellectuelle du
+ Titulaire et/ou des Contributeurs.
+
+
+
+
+
Article 7 - SERVICES ASSOCIES
+
+
7.1 Le Contrat n'oblige en
+ aucun cas le Concédant à la réalisation de prestations
+ d'assistance technique ou de maintenance du Logiciel.
+
Cependant le Concédant reste libre de proposer ce type de
+ services. Les termes et conditions d'une telle assistance
+ technique et/ou d'une telle maintenance seront alors
+ déterminés dans un acte séparé. Ces actes de maintenance
+ et/ou assistance technique n'engageront que la seule
+ responsabilité du Concédant qui les propose.
+
+
+
7.2 De même, tout Concédant
+ est libre de proposer, sous sa seule responsabilité, à ses
+ licenciés une garantie, qui n'engagera que lui, lors de la
+ redistribution du Logiciel et/ou du Logiciel Modifié et ce,
+ dans les conditions qu'il souhaite. Cette garantie et les
+ modalités financières de son application feront l'objet d'un
+ acte séparé entre le Concédant et le Licencié.
+
+
+
+
+ Article 8 -
+ RESPONSABILITE
+
+
8.1 Sous réserve des
+ dispositions de
+ l'article 8.2 ,
+ le Licencié a la faculté, sous réserve de prouver la faute
+ du Concédant concerné, de solliciter la réparation du
+ préjudice direct qu'il subirait du fait du Logiciel et dont
+ il apportera la preuve.
+
+
+
8.2
+ La responsabilité du Concédant est limitée aux engagements
+ pris en application du Contrat et ne saurait être engagée en
+ raison notamment: (i) des dommages dus à l'inexécution,
+ totale ou partielle, de ses obligations par le Licencié,
+ (ii) des dommages directs ou indirects découlant de
+ l'utilisation ou des performances du Logiciel subis par le
+ Licencié et (iii) plus généralement d'un quelconque dommage
+ indirect. En particulier, les Parties conviennent
+ expressément que tout préjudice financier ou commercial (par
+ exemple perte de données, perte de bénéfices, perte
+ d'exploitation, perte de clientèle ou de commandes, manque à
+ gagner, trouble commercial quelconque) ou toute action
+ dirigée contre le Licencié par un tiers, constitue un
+ dommage indirect et n'ouvre pas droit à réparation par le
+ Concédant.
+
+
+
+
+ Article 9 - GARANTIE
+
+
9.1 Le Licencié reconnaît
+ que l'état actuel des connaissances scientifiques et
+ techniques au moment de la mise en circulation du Logiciel
+ ne permet pas d'en tester et d'en vérifier toutes les
+ utilisations ni de détecter l'existence d'éventuels défauts.
+ L'attention du Licencié a été attirée sur ce point sur les
+ risques associés au chargement, à l'utilisation, la
+ modification et/ou au développement et à la reproduction du
+ Logiciel qui sont réservés à des utilisateurs avertis.
+
Il relève de la responsabilité du Licencié de contrôler,
+ par tous moyens, l'adéquation du produit à ses besoins, son
+ bon fonctionnement et de s'assurer qu'il ne causera pas de
+ dommages aux personnes et aux biens.
+
+
+
9.2
+ Le Concédant déclare de bonne foi être en droit de concéder
+ l'ensemble des droits attachés au Logiciel (comprenant
+ notamment les droits visés à l'article
+ 5 ).
+
+
+
9.3 Le Licencié reconnaît
+ que le Logiciel est fourni "en l'état" par le Concédant sans
+ autre garantie, expresse ou tacite, que celle prévue à
+ l'article 9.2
+ et notamment sans aucune garantie sur sa valeur commerciale,
+ son caractère sécurisé, innovant ou pertinent.
+
En particulier, le Concédant ne garantit pas que le
+ Logiciel est exempt d'erreur, qu'il fonctionnera sans
+ interruption, qu'il sera compatible avec l'équipement du
+ Licencié et sa configuration logicielle ni qu'il remplira
+ les besoins du Licencié.
+
+
+
9.4 Le Concédant ne garantit
+ pas, de manière expresse ou tacite, que le Logiciel ne porte
+ pas atteinte à un quelconque droit de propriété
+ intellectuelle d'un tiers portant sur un brevet, un logiciel
+ ou sur tout autre droit de propriété. Ainsi, le Concédant
+ exclut toute garantie au profit du Licencié contre les
+ actions en contrefaçon qui pourraient être diligentées au
+ titre de l'utilisation, de la modification, et de la
+ redistribution du Logiciel. Néanmoins, si de telles actions
+ sont exercées contre le Licencié, le Concédant lui apportera
+ son aide technique et juridique pour sa défense. Cette aide
+ technique et juridique est déterminée au cas par cas entre
+ le Concédant concerné et le Licencié dans le cadre d'un
+ protocole d'accord. Le Concédant dégage toute responsabilité
+ quant à l'utilisation de la dénomination du Logiciel par le
+ Licencié. Aucune garantie n'est apportée quant à l'existence
+ de droits antérieurs sur le nom du Logiciel et sur
+ l'existence d'une marque.
+
+
+
+
Article 10 -
+ RESILIATION
+
+
10.1 En cas de manquement
+ par le Licencié aux obligations mises à sa charge par le
+ Contrat, le Concédant pourra résilier de plein droit le
+ Contrat trente (30) jours après notification adressée au
+ Licencié et restée sans effet.
+
+
+
10.2 Le Licencié dont le
+ Contrat est résilié n'est plus autorisé à utiliser, modifier
+ ou distribuer le Logiciel. Cependant, toutes les licences
+ qu'il aura concédées antérieurement à la résiliation du
+ Contrat resteront valides sous réserve qu'elles aient été
+ effectuées en conformité avec le Contrat.
+
+
+
+
Article 11 - DISPOSITIONS
+ DIVERSES
+
+
+ 11.1 CAUSE EXTERIEURE
+
Aucune
+ des Parties ne sera responsable d'un retard ou d'une
+ défaillance d'exécution du Contrat qui serait dû
+ à un cas de force majeure, un cas fortuit ou une cause
+ extérieure, telle que, notamment, le mauvais fonctionnement
+ ou les interruptions du réseau électrique ou de
+ télécommunication, la paralysie du réseau liée
+ à une attaque informatique, l'intervention des
+ autorités gouvernementales, les catastrophes naturelles, les
+ dégâts des eaux, les tremblements de terre, le feu, les
+ explosions, les grèves et les conflits sociaux, l'état
+ de guerre...
+
+
+
11.2 Le
+ fait, par l'une ou l'autre des Parties, d'omettre
+ en une ou plusieurs occasions de se prévaloir d'une ou
+ plusieurs dispositions du Contrat, ne pourra en aucun cas impliquer
+ renonciation par la Partie intéressée à s'en
+ prévaloir ultérieurement.
+
+
+
11.3 Le Contrat annule et
+ remplace toute convention antérieure, écrite ou orale, entre
+ les Parties sur le même objet et constitue l'accord entier
+ entre les Parties sur cet objet. Aucune addition ou
+ modification aux termes du Contrat n'aura d'effet à l'égard
+ des Parties à moins d'être faite par écrit et signée par
+ leurs représentants dûment habilités.
+
+
+
11.4 Dans l'hypothèse où une
+ ou plusieurs des dispositions du Contrat s'avèrerait
+ contraire à une loi ou à un texte applicable, existants ou
+ futurs, cette loi ou ce texte prévaudrait, et les Parties
+ feraient les amendements nécessaires pour se conformer à
+ cette loi ou à ce texte. Toutes les autres dispositions
+ resteront en vigueur. De même, la nullité, pour quelque
+ raison que ce soit, d'une des dispositions du Contrat ne
+ saurait entraîner la nullité de l'ensemble du Contrat.
+
+
+
+ 11.5 LANGUE
+
Le Contrat est rédigé en langue française et en langue
+ anglaise, ces deux versions faisant également foi.
+
+
+
+
+
Article 12 - NOUVELLES
+ VERSIONS DU CONTRAT
+
+
12.1 Toute personne est
+ autorisée à copier et distribuer des copies de ce
+ Contrat.
+
+
+
12.2 Afin d'en préserver la
+ cohérence, le texte du Contrat est protégé et ne peut être
+ modifié que par les auteurs de la licence, lesquels se
+ réservent le droit de publier périodiquement des mises à
+ jour ou de nouvelles versions du Contrat, qui posséderont
+ chacune un numéro distinct. Ces versions ultérieures seront
+ susceptibles de prendre en compte de nouvelles
+ problématiques rencontrées par les logiciels libres.
+
+
+
12.3 Tout Logiciel diffusé
+ sous une version donnée du Contrat ne pourra faire l'objet
+ d'une diffusion ultérieure que sous la même version du
+ Contrat ou une version postérieure.
+
+
+
+
Article 13 - LOI APPLICABLE
+ ET COMPETENCE TERRITORIALE
+
+
13.1 Le Contrat est régi
+ par la loi française. Les Parties conviennent de tenter de
+ régler à l'amiable les différends ou litiges qui viendraient
+ à se produire par suite ou à l'occasion du Contrat.
+
+
+
+
13.2 A défaut d'accord
+ amiable dans un délai de deux (2) mois à compter de leur
+ survenance et sauf situation relevant d'une procédure
+ d'urgence, les différends ou litiges seront portés par la
+ Partie la plus diligente devant les Tribunaux compétents de
+ Paris.
+
+
+
+ Version 1.0 du 2006-09-05.
+
+
diff --git a/data/texts/LoginLicence.html b/data/texts/LoginLicence.html
new file mode 100644
index 0000000..b6f1e61
--- /dev/null
+++ b/data/texts/LoginLicence.html
@@ -0,0 +1,653 @@
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
Avertissement
+
+
Ce contrat est une licence de logiciel libre issue d'une
+ concertation entre ses auteurs afin que le respect de deux
+ grands principes préside à sa rédaction:
+
+ d'une part, le respect des principes de diffusion des
+ logiciels libres: accès au code source, droits étendus
+ conférés aux utilisateurs,
+ d'autre part, la désignation d'un droit applicable, le
+ droit français, auquel elle est conforme, tant au regard du
+ droit de la responsabilité civile que du droit de la
+ propriété intellectuelle et de la protection qu'il offre aux
+ auteurs et titulaires des droits patrimoniaux sur un
+ logiciel.
+
+
+
Les auteurs de la licence
+ CeCILL-B1 sont:
+
+
Commissariat à l'Energie Atomique - CEA, établissement public
+ de recherche à caractère scientifique, technique et
+ industriel, dont le siège est situé 25 rue Leblanc, immeuble
+ Le Ponant D, 75015 Paris.
+
Centre National de la Recherche Scientifique - CNRS,
+ établissement public à caractère scientifique et
+ technologique, dont le siège est situé 3 rue Michel-Ange,
+ 75794 Paris cedex 16.
+
+
Institut National de Recherche en Informatique et en
+ Automatique - INRIA, établissement public à caractère
+ scientifique et technologique, dont le siège est situé Domaine
+ de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex.
+
+
+
+
Préambule
+
Ce contrat est une licence de logiciel libre dont l'objectif
+ est de conférer aux utilisateurs une très large liberté de
+ modification et de redistribution du logiciel régi par cette
+ licence.
+
L'exercice de cette liberté est assorti d'une obligation
+ forte de citation à la charge de ceux qui distribueraient un
+ logiciel incorporant un logiciel régi par la présente licence
+ afin d'assurer que les contributions de tous soient
+ correctement identifiées et reconnues.
+
L'accessibilité au code source et les droits de copie, de
+ modification et de redistribution qui découlent de ce contrat
+ ont pour contrepartie de n'offrir aux utilisateurs qu'une
+ garantie limitée et de ne faire peser sur l'auteur du
+ logiciel, le titulaire des droits patrimoniaux et les
+ concédants successifs qu'une responsabilité restreinte.
+
A cet égard l'attention de l'utilisateur est attirée sur les
+ risques associés au chargement, à l'utilisation, à la
+ modification et/ou au développement et à la reproduction du
+ logiciel par l'utilisateur étant donné sa spécificité de
+ logiciel libre, qui peut le rendre complexe à manipuler et qui
+ le réserve donc à des développeurs ou des professionnels
+ avertis possédant des connaissances informatiques
+ approfondies. Les utilisateurs sont donc invités à charger et
+ tester l'adéquation du logiciel à leurs besoins dans des
+ conditions permettant d'assurer la sécurité de leurs systèmes
+ et/ou de leurs données et, plus généralement, à l'utiliser et
+ l'exploiter dans les mêmes conditions de sécurité. Ce contrat
+ peut être reproduit et diffusé librement, sous réserve de le
+ conserver en l'état, sans ajout ni suppression de
+ clauses.
+
Ce contrat est susceptible de s'appliquer à tout logiciel
+ dont le titulaire des droits patrimoniaux décide de soumettre
+ l'exploitation aux dispositions qu'il contient.
+
+
+
+
Article 1 - DEFINITIONS
+
Dans ce contrat, les termes suivants, lorsqu'ils seront
+ écrits avec une lettre capitale, auront la signification
+ suivante:
+
Contrat :
+ désigne le présent contrat de licence, ses éventuelles
+ versions postérieures et annexes.
+
Logiciel :
+ désigne le logiciel sous sa forme de Code Objet et/ou de Code
+ Source et le cas échéant sa documentation, dans leur état au
+ moment de l'acceptation du Contrat par le Licencié.
+
Logiciel
+ Initial : désigne le Logiciel sous sa forme de Code
+ Source et éventuellement de Code Objet et le cas échéant sa
+ documentation, dans leur état au moment de leur première
+ diffusion sous les termes du Contrat.
+
Logiciel
+ Modifié : désigne le Logiciel modifié par au moins une
+ Contribution.
+
Code
+ Source : désigne l'ensemble des instructions et des
+ lignes de programme du Logiciel et auquel l'accès est
+ nécessaire en vue de modifier le Logiciel.
+
Code
+ Objet : désigne les fichiers binaires issus de la
+ compilation du Code Source.
+
Titulaire :
+ désigne le ou les détenteurs des droits patrimoniaux d'auteur
+ sur le Logiciel Initial.
+
Licencié :
+ désigne le ou les utilisateurs du Logiciel ayant accepté le
+ Contrat.
+
Contributeur :
+ désigne le Licencié auteur d'au moins une Contribution.
+
Concédant :
+ désigne le Titulaire ou toute personne physique ou morale
+ distribuant le Logiciel sous le Contrat.
+
Contribution :
+ désigne l'ensemble des modifications, corrections,
+ traductions, adaptations et/ou nouvelles fonctionnalités
+ intégrées dans le Logiciel par tout Contributeur, ainsi que
+ tout Module Interne.
+
Module :
+ désigne un ensemble de fichiers sources y compris leur
+ documentation qui permet de réaliser des fonctionnalités ou
+ services supplémentaires à ceux fournis par le Logiciel.
+
Module
+ Externe : désigne tout Module, non dérivé du Logiciel, tel
+ que ce Module et le Logiciel s'exécutent dans des espaces
+ d'adressage différents, l'un appelant l'autre au moment de leur
+ exécution.
+
Module
+ Interne : désigne tout Module lié au Logiciel de telle
+ sorte qu'ils s'exécutent dans le même espace
+ d'adressage.
+
Parties :
+ désigne collectivement le Licencié et le Concédant.
+
Ces termes s'entendent au singulier comme au pluriel.
+
+
+
Article 2 - OBJET
+
Le Contrat a pour objet la concession par le Concédant au
+ Licencié d'une licence non exclusive, cessible et mondiale du
+ Logiciel telle que définie ci-après à
+ l'article 5
+ pour toute la durée de protection des droits portant sur ce
+ Logiciel.
+
+
+
Article 3 - ACCEPTATION
+
+
3.1
+ L'acceptation par le Licencié des termes du Contrat est
+ réputée acquise du fait du premier des faits suivants:
+
+ (i) le chargement du Logiciel par tout moyen notamment
+ par téléchargement à partir d'un serveur distant ou par
+ chargement à partir d'un support physique;
+ (ii) le premier exercice par le Licencié de l'un
+ quelconque des droits concédés par le Contrat.
+
+
+
+
3.2 Un exemplaire du
+ Contrat, contenant notamment un avertissement relatif aux
+ spécificités du Logiciel, à la restriction de garantie et à
+ la limitation à un usage par des utilisateurs expérimentés a
+ été mis à disposition du Licencié préalablement à son
+ acceptation telle que définie à
+ l'article 3.1
+ ci dessus et le Licencié reconnaît en avoir pris
+ connaissance.
+
+
+
+
Article 4 - ENTREE EN VIGUEUR ET DUREE
+
+
4.1 ENTREE EN VIGUEUR
+
Le Contrat entre en vigueur à la date de son acceptation
+ par le Licencié telle que définie
+ en 3.1 .
+
+
+
4.2 DUREE
+
Le Contrat produira ses effets pendant toute la durée
+ légale de protection des droits patrimoniaux portant sur le
+ Logiciel.
+
+
+
+
+ Article 5 - ETENDUE DES DROITS
+ CONCEDES
+
Le Concédant concède au Licencié, qui accepte, les droits
+ suivants sur le Logiciel pour toutes destinations et pour la
+ durée du Contrat dans les conditions ci-après
+ détaillées.
+
Par ailleurs, si le Concédant détient ou venait à détenir un
+ ou plusieurs brevets d'invention protégeant tout ou partie des
+ fonctionnalités du Logiciel ou de ses composants, il s'engage
+ à ne pas opposer les éventuels droits conférés par ces brevets
+ aux Licenciés successifs qui utiliseraient, exploiteraient ou
+ modifieraient le Logiciel. En cas de cession de ces brevets,
+ le Concédant s'engage à faire reprendre les obligations du
+ présent alinéa aux cessionnaires.
+
+
5.1 DROIT
+ D'UTILISATION
+
+
Le Licencié est autorisé à utiliser le Logiciel, sans
+ restriction quant aux domaines d'application, étant ci-après
+ précisé que cela comporte:
+
+ la reproduction permanente ou provisoire du Logiciel
+ en tout ou partie par tout moyen et sous toute
+ forme.
+ le chargement, l'affichage, l'exécution, ou le
+ stockage du Logiciel sur tout support.
+ la possibilité d'en observer, d'en étudier, ou d'en
+ tester le fonctionnement afin de déterminer les idées et
+ principes qui sont à la base de n'importe quel élément
+ de ce Logiciel; et ceci, lorsque le Licencié effectue
+ toute opération de chargement, d'affichage, d'exécution,
+ de transmission ou de stockage du Logiciel qu'il est en
+ droit d'effectuer en vertu du Contrat.
+
+
+
+
5.2 DROIT D'APPORTER DES
+ CONTRIBUTIONS
+
Le droit d'apporter des Contributions comporte le droit de
+ traduire, d'adapter, d'arranger ou d'apporter toute autre
+ modification au Logiciel et le droit de reproduire le
+ logiciel en résultant.
+
Le Licencié est autorisé à apporter toute Contribution au
+ Logiciel sous réserve de mentionner, de façon explicite, son
+ nom en tant qu'auteur de cette Contribution et la date de
+ création de celle-ci.
+
+
+
5.3 DROIT DE
+ DISTRIBUTION
+
Le droit de distribution comporte notamment le droit de
+ diffuser, de transmettre et de communiquer le Logiciel au
+ public sur tout support et par tout moyen ainsi que le droit
+ de mettre sur le marché à titre onéreux ou gratuit, un ou
+ des exemplaires du Logiciel par tout procédé.
+
Le Licencié est autorisé à distribuer des copies du
+ Logiciel, modifié ou non, à des tiers dans les conditions
+ ci-après détaillées.
+
+
5.3.1 DISTRIBUTION DU
+ LOGICIEL SANS MODIFICATION
+
Le Licencié est autorisé à distribuer des copies
+ conformes du Logiciel, sous forme de Code Source ou de
+ Code Objet, à condition que cette distribution respecte
+ les dispositions du Contrat dans leur totalité et soit
+ accompagnée:
+
+ d'un exemplaire du Contrat,
+ d'un avertissement relatif à la restriction de
+ garantie et de responsabilité du Concédant telle que
+ prévue aux
+ articles 8
+ et 9 ,
+
+
et que, dans le cas où seul le Code Objet du Logiciel est
+ redistribué, le Licencié permette un accès effectif au
+ Code Source complet du Logiciel pendant au moins toute la
+ durée de sa distribution du Logiciel, étant entendu que le
+ coût additionnel d'acquisition du Code Source ne devra pas
+ excéder le simple coût de transfert des données.
+
+
+
+ 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE
+
Lorsque le Licencié apporte une Contribution au Logiciel,
+ le Logiciel Modifié peut être distribué sous un contrat de
+ licence autre que le présent Contrat sous réserve du
+ respect des dispositions de l'article
+ 5.3.4 .
+
+
+
5.3.3 DISTRIBUTION DES
+ MODULES EXTERNES
+
Lorsque le Licencié a développé un Module Externe les
+ conditions du Contrat ne s'appliquent pas à ce Module
+ Externe, qui peut être distribué sous un contrat de
+ licence différent.
+
+
+
5.3.4 CITATIONS
+
Le Licencié qui distribue un Logiciel Modifié s'engage
+ expressément:
+
+ à indiquer dans sa documentation qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+
+ à faire en sorte que l'utilisation du Logiciel, ses
+ mentions de propriété intellectuelle et le fait qu'il
+ est régi par le Contrat soient indiqués dans un texte
+ facilement accessible depuis l'interface du Logiciel
+ Modifié,
+ à mentionner, sur un site Web librement accessible
+ décrivant le Logiciel Modifié, et pendant au moins
+ toute la durée de sa distribution, qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+ lorsqu'il le distribue à un tiers susceptible de
+ distribuer lui-même un Logiciel Modifié, sans avoir à
+ en distribuer le code source, à faire ses meilleurs
+ efforts pour que les obligations du présent
+ article 5.3.4
+ soient reprises par le dit tiers.
+
+
Lorsque le Logiciel modifié ou non est distribué avec un
+ Module Externe qui a été conçu pour l'utiliser, le
+ Licencié doit soumettre le dit Module Externe aux
+ obligations précédentes.
+
+
+
5.3.5 COMPATIBILITE
+ AVEC LES LICENCES CeCILL et CeCILL-C
+
Lorsqu'un Logiciel Modifié contient une Contribution
+ soumise au contrat de licence CeCILL, les stipulations
+ prévues à
+ l'article 5.3.4
+ sont facultatives.
+
Un Logiciel Modifié peut être distribué sous le contrat
+ de licence CeCILL-C. Les stipulations prévues à
+ l'article 5.3.4
+ sont alors facultatives.
+
+
+
+
+
Article 6 - PROPRIETE INTELLECTUELLE
+
+
6.1 SUR LE LOGICIEL
+ INITIAL
+
Le Titulaire est détenteur des droits patrimoniaux sur le
+ Logiciel Initial. Toute utilisation du Logiciel Initial est
+ soumise au respect des conditions dans lesquelles le
+ Titulaire a choisi de diffuser son oeuvre et nul autre n'a
+ la faculté de modifier les conditions de diffusion de ce
+ Logiciel Initial.
+
Le Titulaire s'engage à ce que le Logiciel Initial reste au
+ moins régi par le Contrat et ce, pour la durée visée à
+ l'article 4.2 .
+
+
+
6.2 SUR LES
+ CONTRIBUTIONS
+
Le Licencié qui a développé une Contribution est titulaire
+ sur celle-ci des droits de propriété intellectuelle dans les
+ conditions définies par la législation applicable.
+
+
+
6.3 SUR LES MODULES
+ EXTERNES
+
Le Licencié qui a développé un Module Externe est
+ titulaire sur celui-ci des droits de propriété
+ intellectuelle dans les conditions définies par la
+ législation applicable et reste libre du choix du contrat
+ régissant sa diffusion.
+
+
+
6.4 DISPOSITIONS
+ COMMUNES
+
+
Le Licencié s'engage expressément:
+
+ à ne pas supprimer ou modifier de quelque manière
+ que ce soit les mentions de propriété intellectuelle
+ apposées sur le Logiciel;
+ à reproduire à l'identique lesdites mentions de
+ propriété intellectuelle sur les copies du Logiciel
+ modifié ou non.
+
+
+
+
Le Licencié s'engage à ne pas porter atteinte,
+ directement ou indirectement, aux droits de propriété
+ intellectuelle du Titulaire et/ou des Contributeurs sur le
+ Logiciel et à prendre, le cas échéant, à l'égard de son
+ personnel toutes les mesures nécessaires pour assurer le
+ respect des dits droits de propriété intellectuelle du
+ Titulaire et/ou des Contributeurs.
+
+
+
+
+
Article 7 - SERVICES ASSOCIES
+
+
7.1 Le Contrat n'oblige en
+ aucun cas le Concédant à la réalisation de prestations
+ d'assistance technique ou de maintenance du Logiciel.
+
Cependant le Concédant reste libre de proposer ce type de
+ services. Les termes et conditions d'une telle assistance
+ technique et/ou d'une telle maintenance seront alors
+ déterminés dans un acte séparé. Ces actes de maintenance
+ et/ou assistance technique n'engageront que la seule
+ responsabilité du Concédant qui les propose.
+
+
+
7.2 De même, tout Concédant
+ est libre de proposer, sous sa seule responsabilité, à ses
+ licenciés une garantie, qui n'engagera que lui, lors de la
+ redistribution du Logiciel et/ou du Logiciel Modifié et ce,
+ dans les conditions qu'il souhaite. Cette garantie et les
+ modalités financières de son application feront l'objet d'un
+ acte séparé entre le Concédant et le Licencié.
+
+
+
+
+ Article 8 -
+ RESPONSABILITE
+
+
8.1 Sous réserve des
+ dispositions de
+ l'article 8.2 ,
+ le Licencié a la faculté, sous réserve de prouver la faute
+ du Concédant concerné, de solliciter la réparation du
+ préjudice direct qu'il subirait du fait du Logiciel et dont
+ il apportera la preuve.
+
+
+
8.2
+ La responsabilité du Concédant est limitée aux engagements
+ pris en application du Contrat et ne saurait être engagée en
+ raison notamment: (i) des dommages dus à l'inexécution,
+ totale ou partielle, de ses obligations par le Licencié,
+ (ii) des dommages directs ou indirects découlant de
+ l'utilisation ou des performances du Logiciel subis par le
+ Licencié et (iii) plus généralement d'un quelconque dommage
+ indirect. En particulier, les Parties conviennent
+ expressément que tout préjudice financier ou commercial (par
+ exemple perte de données, perte de bénéfices, perte
+ d'exploitation, perte de clientèle ou de commandes, manque à
+ gagner, trouble commercial quelconque) ou toute action
+ dirigée contre le Licencié par un tiers, constitue un
+ dommage indirect et n'ouvre pas droit à réparation par le
+ Concédant.
+
+
+
+
+ Article 9 - GARANTIE
+
+
9.1 Le Licencié reconnaît
+ que l'état actuel des connaissances scientifiques et
+ techniques au moment de la mise en circulation du Logiciel
+ ne permet pas d'en tester et d'en vérifier toutes les
+ utilisations ni de détecter l'existence d'éventuels défauts.
+ L'attention du Licencié a été attirée sur ce point sur les
+ risques associés au chargement, à l'utilisation, la
+ modification et/ou au développement et à la reproduction du
+ Logiciel qui sont réservés à des utilisateurs avertis.
+
Il relève de la responsabilité du Licencié de contrôler,
+ par tous moyens, l'adéquation du produit à ses besoins, son
+ bon fonctionnement et de s'assurer qu'il ne causera pas de
+ dommages aux personnes et aux biens.
+
+
+
9.2
+ Le Concédant déclare de bonne foi être en droit de concéder
+ l'ensemble des droits attachés au Logiciel (comprenant
+ notamment les droits visés à l'article
+ 5 ).
+
+
+
9.3 Le Licencié reconnaît
+ que le Logiciel est fourni "en l'état" par le Concédant sans
+ autre garantie, expresse ou tacite, que celle prévue à
+ l'article 9.2
+ et notamment sans aucune garantie sur sa valeur commerciale,
+ son caractère sécurisé, innovant ou pertinent.
+
En particulier, le Concédant ne garantit pas que le
+ Logiciel est exempt d'erreur, qu'il fonctionnera sans
+ interruption, qu'il sera compatible avec l'équipement du
+ Licencié et sa configuration logicielle ni qu'il remplira
+ les besoins du Licencié.
+
+
+
9.4 Le Concédant ne garantit
+ pas, de manière expresse ou tacite, que le Logiciel ne porte
+ pas atteinte à un quelconque droit de propriété
+ intellectuelle d'un tiers portant sur un brevet, un logiciel
+ ou sur tout autre droit de propriété. Ainsi, le Concédant
+ exclut toute garantie au profit du Licencié contre les
+ actions en contrefaçon qui pourraient être diligentées au
+ titre de l'utilisation, de la modification, et de la
+ redistribution du Logiciel. Néanmoins, si de telles actions
+ sont exercées contre le Licencié, le Concédant lui apportera
+ son aide technique et juridique pour sa défense. Cette aide
+ technique et juridique est déterminée au cas par cas entre
+ le Concédant concerné et le Licencié dans le cadre d'un
+ protocole d'accord. Le Concédant dégage toute responsabilité
+ quant à l'utilisation de la dénomination du Logiciel par le
+ Licencié. Aucune garantie n'est apportée quant à l'existence
+ de droits antérieurs sur le nom du Logiciel et sur
+ l'existence d'une marque.
+
+
+
+
Article 10 -
+ RESILIATION
+
+
10.1 En cas de manquement
+ par le Licencié aux obligations mises à sa charge par le
+ Contrat, le Concédant pourra résilier de plein droit le
+ Contrat trente (30) jours après notification adressée au
+ Licencié et restée sans effet.
+
+
+
10.2 Le Licencié dont le
+ Contrat est résilié n'est plus autorisé à utiliser, modifier
+ ou distribuer le Logiciel. Cependant, toutes les licences
+ qu'il aura concédées antérieurement à la résiliation du
+ Contrat resteront valides sous réserve qu'elles aient été
+ effectuées en conformité avec le Contrat.
+
+
+
+
Article 11 - DISPOSITIONS
+ DIVERSES
+
+
+ 11.1 CAUSE EXTERIEURE
+
Aucune
+ des Parties ne sera responsable d'un retard ou d'une
+ défaillance d'exécution du Contrat qui serait dû
+ à un cas de force majeure, un cas fortuit ou une cause
+ extérieure, telle que, notamment, le mauvais fonctionnement
+ ou les interruptions du réseau électrique ou de
+ télécommunication, la paralysie du réseau liée
+ à une attaque informatique, l'intervention des
+ autorités gouvernementales, les catastrophes naturelles, les
+ dégâts des eaux, les tremblements de terre, le feu, les
+ explosions, les grèves et les conflits sociaux, l'état
+ de guerre...
+
+
+
11.2 Le
+ fait, par l'une ou l'autre des Parties, d'omettre
+ en une ou plusieurs occasions de se prévaloir d'une ou
+ plusieurs dispositions du Contrat, ne pourra en aucun cas impliquer
+ renonciation par la Partie intéressée à s'en
+ prévaloir ultérieurement.
+
+
+
11.3 Le Contrat annule et
+ remplace toute convention antérieure, écrite ou orale, entre
+ les Parties sur le même objet et constitue l'accord entier
+ entre les Parties sur cet objet. Aucune addition ou
+ modification aux termes du Contrat n'aura d'effet à l'égard
+ des Parties à moins d'être faite par écrit et signée par
+ leurs représentants dûment habilités.
+
+
+
11.4 Dans l'hypothèse où une
+ ou plusieurs des dispositions du Contrat s'avèrerait
+ contraire à une loi ou à un texte applicable, existants ou
+ futurs, cette loi ou ce texte prévaudrait, et les Parties
+ feraient les amendements nécessaires pour se conformer à
+ cette loi ou à ce texte. Toutes les autres dispositions
+ resteront en vigueur. De même, la nullité, pour quelque
+ raison que ce soit, d'une des dispositions du Contrat ne
+ saurait entraîner la nullité de l'ensemble du Contrat.
+
+
+
+ 11.5 LANGUE
+
Le Contrat est rédigé en langue française et en langue
+ anglaise, ces deux versions faisant également foi.
+
+
+
+
+
Article 12 - NOUVELLES
+ VERSIONS DU CONTRAT
+
+
12.1 Toute personne est
+ autorisée à copier et distribuer des copies de ce
+ Contrat.
+
+
+
12.2 Afin d'en préserver la
+ cohérence, le texte du Contrat est protégé et ne peut être
+ modifié que par les auteurs de la licence, lesquels se
+ réservent le droit de publier périodiquement des mises à
+ jour ou de nouvelles versions du Contrat, qui posséderont
+ chacune un numéro distinct. Ces versions ultérieures seront
+ susceptibles de prendre en compte de nouvelles
+ problématiques rencontrées par les logiciels libres.
+
+
+
12.3 Tout Logiciel diffusé
+ sous une version donnée du Contrat ne pourra faire l'objet
+ d'une diffusion ultérieure que sous la même version du
+ Contrat ou une version postérieure.
+
+
+
+
Article 13 - LOI APPLICABLE
+ ET COMPETENCE TERRITORIALE
+
+
13.1 Le Contrat est régi
+ par la loi française. Les Parties conviennent de tenter de
+ régler à l'amiable les différends ou litiges qui viendraient
+ à se produire par suite ou à l'occasion du Contrat.
+
+
+
+
13.2 A défaut d'accord
+ amiable dans un délai de deux (2) mois à compter de leur
+ survenance et sauf situation relevant d'une procédure
+ d'urgence, les différends ou litiges seront portés par la
+ Partie la plus diligente devant les Tribunaux compétents de
+ Paris.
+
+
+
+ Version 1.0 du 2006-09-05.
+
+
diff --git a/data/texts/MiscLicence.html b/data/texts/MiscLicence.html
new file mode 100644
index 0000000..b6f1e61
--- /dev/null
+++ b/data/texts/MiscLicence.html
@@ -0,0 +1,653 @@
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
+
+ CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B
+
+
+
Avertissement
+
+
Ce contrat est une licence de logiciel libre issue d'une
+ concertation entre ses auteurs afin que le respect de deux
+ grands principes préside à sa rédaction:
+
+ d'une part, le respect des principes de diffusion des
+ logiciels libres: accès au code source, droits étendus
+ conférés aux utilisateurs,
+ d'autre part, la désignation d'un droit applicable, le
+ droit français, auquel elle est conforme, tant au regard du
+ droit de la responsabilité civile que du droit de la
+ propriété intellectuelle et de la protection qu'il offre aux
+ auteurs et titulaires des droits patrimoniaux sur un
+ logiciel.
+
+
+
Les auteurs de la licence
+ CeCILL-B1 sont:
+
+
Commissariat à l'Energie Atomique - CEA, établissement public
+ de recherche à caractère scientifique, technique et
+ industriel, dont le siège est situé 25 rue Leblanc, immeuble
+ Le Ponant D, 75015 Paris.
+
Centre National de la Recherche Scientifique - CNRS,
+ établissement public à caractère scientifique et
+ technologique, dont le siège est situé 3 rue Michel-Ange,
+ 75794 Paris cedex 16.
+
+
Institut National de Recherche en Informatique et en
+ Automatique - INRIA, établissement public à caractère
+ scientifique et technologique, dont le siège est situé Domaine
+ de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex.
+
+
+
+
Préambule
+
Ce contrat est une licence de logiciel libre dont l'objectif
+ est de conférer aux utilisateurs une très large liberté de
+ modification et de redistribution du logiciel régi par cette
+ licence.
+
L'exercice de cette liberté est assorti d'une obligation
+ forte de citation à la charge de ceux qui distribueraient un
+ logiciel incorporant un logiciel régi par la présente licence
+ afin d'assurer que les contributions de tous soient
+ correctement identifiées et reconnues.
+
L'accessibilité au code source et les droits de copie, de
+ modification et de redistribution qui découlent de ce contrat
+ ont pour contrepartie de n'offrir aux utilisateurs qu'une
+ garantie limitée et de ne faire peser sur l'auteur du
+ logiciel, le titulaire des droits patrimoniaux et les
+ concédants successifs qu'une responsabilité restreinte.
+
A cet égard l'attention de l'utilisateur est attirée sur les
+ risques associés au chargement, à l'utilisation, à la
+ modification et/ou au développement et à la reproduction du
+ logiciel par l'utilisateur étant donné sa spécificité de
+ logiciel libre, qui peut le rendre complexe à manipuler et qui
+ le réserve donc à des développeurs ou des professionnels
+ avertis possédant des connaissances informatiques
+ approfondies. Les utilisateurs sont donc invités à charger et
+ tester l'adéquation du logiciel à leurs besoins dans des
+ conditions permettant d'assurer la sécurité de leurs systèmes
+ et/ou de leurs données et, plus généralement, à l'utiliser et
+ l'exploiter dans les mêmes conditions de sécurité. Ce contrat
+ peut être reproduit et diffusé librement, sous réserve de le
+ conserver en l'état, sans ajout ni suppression de
+ clauses.
+
Ce contrat est susceptible de s'appliquer à tout logiciel
+ dont le titulaire des droits patrimoniaux décide de soumettre
+ l'exploitation aux dispositions qu'il contient.
+
+
+
+
Article 1 - DEFINITIONS
+
Dans ce contrat, les termes suivants, lorsqu'ils seront
+ écrits avec une lettre capitale, auront la signification
+ suivante:
+
Contrat :
+ désigne le présent contrat de licence, ses éventuelles
+ versions postérieures et annexes.
+
Logiciel :
+ désigne le logiciel sous sa forme de Code Objet et/ou de Code
+ Source et le cas échéant sa documentation, dans leur état au
+ moment de l'acceptation du Contrat par le Licencié.
+
Logiciel
+ Initial : désigne le Logiciel sous sa forme de Code
+ Source et éventuellement de Code Objet et le cas échéant sa
+ documentation, dans leur état au moment de leur première
+ diffusion sous les termes du Contrat.
+
Logiciel
+ Modifié : désigne le Logiciel modifié par au moins une
+ Contribution.
+
Code
+ Source : désigne l'ensemble des instructions et des
+ lignes de programme du Logiciel et auquel l'accès est
+ nécessaire en vue de modifier le Logiciel.
+
Code
+ Objet : désigne les fichiers binaires issus de la
+ compilation du Code Source.
+
Titulaire :
+ désigne le ou les détenteurs des droits patrimoniaux d'auteur
+ sur le Logiciel Initial.
+
Licencié :
+ désigne le ou les utilisateurs du Logiciel ayant accepté le
+ Contrat.
+
Contributeur :
+ désigne le Licencié auteur d'au moins une Contribution.
+
Concédant :
+ désigne le Titulaire ou toute personne physique ou morale
+ distribuant le Logiciel sous le Contrat.
+
Contribution :
+ désigne l'ensemble des modifications, corrections,
+ traductions, adaptations et/ou nouvelles fonctionnalités
+ intégrées dans le Logiciel par tout Contributeur, ainsi que
+ tout Module Interne.
+
Module :
+ désigne un ensemble de fichiers sources y compris leur
+ documentation qui permet de réaliser des fonctionnalités ou
+ services supplémentaires à ceux fournis par le Logiciel.
+
Module
+ Externe : désigne tout Module, non dérivé du Logiciel, tel
+ que ce Module et le Logiciel s'exécutent dans des espaces
+ d'adressage différents, l'un appelant l'autre au moment de leur
+ exécution.
+
Module
+ Interne : désigne tout Module lié au Logiciel de telle
+ sorte qu'ils s'exécutent dans le même espace
+ d'adressage.
+
Parties :
+ désigne collectivement le Licencié et le Concédant.
+
Ces termes s'entendent au singulier comme au pluriel.
+
+
+
Article 2 - OBJET
+
Le Contrat a pour objet la concession par le Concédant au
+ Licencié d'une licence non exclusive, cessible et mondiale du
+ Logiciel telle que définie ci-après à
+ l'article 5
+ pour toute la durée de protection des droits portant sur ce
+ Logiciel.
+
+
+
Article 3 - ACCEPTATION
+
+
3.1
+ L'acceptation par le Licencié des termes du Contrat est
+ réputée acquise du fait du premier des faits suivants:
+
+ (i) le chargement du Logiciel par tout moyen notamment
+ par téléchargement à partir d'un serveur distant ou par
+ chargement à partir d'un support physique;
+ (ii) le premier exercice par le Licencié de l'un
+ quelconque des droits concédés par le Contrat.
+
+
+
+
3.2 Un exemplaire du
+ Contrat, contenant notamment un avertissement relatif aux
+ spécificités du Logiciel, à la restriction de garantie et à
+ la limitation à un usage par des utilisateurs expérimentés a
+ été mis à disposition du Licencié préalablement à son
+ acceptation telle que définie à
+ l'article 3.1
+ ci dessus et le Licencié reconnaît en avoir pris
+ connaissance.
+
+
+
+
Article 4 - ENTREE EN VIGUEUR ET DUREE
+
+
4.1 ENTREE EN VIGUEUR
+
Le Contrat entre en vigueur à la date de son acceptation
+ par le Licencié telle que définie
+ en 3.1 .
+
+
+
4.2 DUREE
+
Le Contrat produira ses effets pendant toute la durée
+ légale de protection des droits patrimoniaux portant sur le
+ Logiciel.
+
+
+
+
+ Article 5 - ETENDUE DES DROITS
+ CONCEDES
+
Le Concédant concède au Licencié, qui accepte, les droits
+ suivants sur le Logiciel pour toutes destinations et pour la
+ durée du Contrat dans les conditions ci-après
+ détaillées.
+
Par ailleurs, si le Concédant détient ou venait à détenir un
+ ou plusieurs brevets d'invention protégeant tout ou partie des
+ fonctionnalités du Logiciel ou de ses composants, il s'engage
+ à ne pas opposer les éventuels droits conférés par ces brevets
+ aux Licenciés successifs qui utiliseraient, exploiteraient ou
+ modifieraient le Logiciel. En cas de cession de ces brevets,
+ le Concédant s'engage à faire reprendre les obligations du
+ présent alinéa aux cessionnaires.
+
+
5.1 DROIT
+ D'UTILISATION
+
+
Le Licencié est autorisé à utiliser le Logiciel, sans
+ restriction quant aux domaines d'application, étant ci-après
+ précisé que cela comporte:
+
+ la reproduction permanente ou provisoire du Logiciel
+ en tout ou partie par tout moyen et sous toute
+ forme.
+ le chargement, l'affichage, l'exécution, ou le
+ stockage du Logiciel sur tout support.
+ la possibilité d'en observer, d'en étudier, ou d'en
+ tester le fonctionnement afin de déterminer les idées et
+ principes qui sont à la base de n'importe quel élément
+ de ce Logiciel; et ceci, lorsque le Licencié effectue
+ toute opération de chargement, d'affichage, d'exécution,
+ de transmission ou de stockage du Logiciel qu'il est en
+ droit d'effectuer en vertu du Contrat.
+
+
+
+
5.2 DROIT D'APPORTER DES
+ CONTRIBUTIONS
+
Le droit d'apporter des Contributions comporte le droit de
+ traduire, d'adapter, d'arranger ou d'apporter toute autre
+ modification au Logiciel et le droit de reproduire le
+ logiciel en résultant.
+
Le Licencié est autorisé à apporter toute Contribution au
+ Logiciel sous réserve de mentionner, de façon explicite, son
+ nom en tant qu'auteur de cette Contribution et la date de
+ création de celle-ci.
+
+
+
5.3 DROIT DE
+ DISTRIBUTION
+
Le droit de distribution comporte notamment le droit de
+ diffuser, de transmettre et de communiquer le Logiciel au
+ public sur tout support et par tout moyen ainsi que le droit
+ de mettre sur le marché à titre onéreux ou gratuit, un ou
+ des exemplaires du Logiciel par tout procédé.
+
Le Licencié est autorisé à distribuer des copies du
+ Logiciel, modifié ou non, à des tiers dans les conditions
+ ci-après détaillées.
+
+
5.3.1 DISTRIBUTION DU
+ LOGICIEL SANS MODIFICATION
+
Le Licencié est autorisé à distribuer des copies
+ conformes du Logiciel, sous forme de Code Source ou de
+ Code Objet, à condition que cette distribution respecte
+ les dispositions du Contrat dans leur totalité et soit
+ accompagnée:
+
+ d'un exemplaire du Contrat,
+ d'un avertissement relatif à la restriction de
+ garantie et de responsabilité du Concédant telle que
+ prévue aux
+ articles 8
+ et 9 ,
+
+
et que, dans le cas où seul le Code Objet du Logiciel est
+ redistribué, le Licencié permette un accès effectif au
+ Code Source complet du Logiciel pendant au moins toute la
+ durée de sa distribution du Logiciel, étant entendu que le
+ coût additionnel d'acquisition du Code Source ne devra pas
+ excéder le simple coût de transfert des données.
+
+
+
+ 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE
+
Lorsque le Licencié apporte une Contribution au Logiciel,
+ le Logiciel Modifié peut être distribué sous un contrat de
+ licence autre que le présent Contrat sous réserve du
+ respect des dispositions de l'article
+ 5.3.4 .
+
+
+
5.3.3 DISTRIBUTION DES
+ MODULES EXTERNES
+
Lorsque le Licencié a développé un Module Externe les
+ conditions du Contrat ne s'appliquent pas à ce Module
+ Externe, qui peut être distribué sous un contrat de
+ licence différent.
+
+
+
5.3.4 CITATIONS
+
Le Licencié qui distribue un Logiciel Modifié s'engage
+ expressément:
+
+ à indiquer dans sa documentation qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+
+ à faire en sorte que l'utilisation du Logiciel, ses
+ mentions de propriété intellectuelle et le fait qu'il
+ est régi par le Contrat soient indiqués dans un texte
+ facilement accessible depuis l'interface du Logiciel
+ Modifié,
+ à mentionner, sur un site Web librement accessible
+ décrivant le Logiciel Modifié, et pendant au moins
+ toute la durée de sa distribution, qu'il a été réalisé
+ à partir du Logiciel régi par le Contrat, en
+ reproduisant les mentions de propriété intellectuelle
+ du Logiciel,
+ lorsqu'il le distribue à un tiers susceptible de
+ distribuer lui-même un Logiciel Modifié, sans avoir à
+ en distribuer le code source, à faire ses meilleurs
+ efforts pour que les obligations du présent
+ article 5.3.4
+ soient reprises par le dit tiers.
+
+
Lorsque le Logiciel modifié ou non est distribué avec un
+ Module Externe qui a été conçu pour l'utiliser, le
+ Licencié doit soumettre le dit Module Externe aux
+ obligations précédentes.
+
+
+
5.3.5 COMPATIBILITE
+ AVEC LES LICENCES CeCILL et CeCILL-C
+
Lorsqu'un Logiciel Modifié contient une Contribution
+ soumise au contrat de licence CeCILL, les stipulations
+ prévues à
+ l'article 5.3.4
+ sont facultatives.
+
Un Logiciel Modifié peut être distribué sous le contrat
+ de licence CeCILL-C. Les stipulations prévues à
+ l'article 5.3.4
+ sont alors facultatives.
+
+
+
+
+
Article 6 - PROPRIETE INTELLECTUELLE
+
+
6.1 SUR LE LOGICIEL
+ INITIAL
+
Le Titulaire est détenteur des droits patrimoniaux sur le
+ Logiciel Initial. Toute utilisation du Logiciel Initial est
+ soumise au respect des conditions dans lesquelles le
+ Titulaire a choisi de diffuser son oeuvre et nul autre n'a
+ la faculté de modifier les conditions de diffusion de ce
+ Logiciel Initial.
+
Le Titulaire s'engage à ce que le Logiciel Initial reste au
+ moins régi par le Contrat et ce, pour la durée visée à
+ l'article 4.2 .
+
+
+
6.2 SUR LES
+ CONTRIBUTIONS
+
Le Licencié qui a développé une Contribution est titulaire
+ sur celle-ci des droits de propriété intellectuelle dans les
+ conditions définies par la législation applicable.
+
+
+
6.3 SUR LES MODULES
+ EXTERNES
+
Le Licencié qui a développé un Module Externe est
+ titulaire sur celui-ci des droits de propriété
+ intellectuelle dans les conditions définies par la
+ législation applicable et reste libre du choix du contrat
+ régissant sa diffusion.
+
+
+
6.4 DISPOSITIONS
+ COMMUNES
+
+
Le Licencié s'engage expressément:
+
+ à ne pas supprimer ou modifier de quelque manière
+ que ce soit les mentions de propriété intellectuelle
+ apposées sur le Logiciel;
+ à reproduire à l'identique lesdites mentions de
+ propriété intellectuelle sur les copies du Logiciel
+ modifié ou non.
+
+
+
+
Le Licencié s'engage à ne pas porter atteinte,
+ directement ou indirectement, aux droits de propriété
+ intellectuelle du Titulaire et/ou des Contributeurs sur le
+ Logiciel et à prendre, le cas échéant, à l'égard de son
+ personnel toutes les mesures nécessaires pour assurer le
+ respect des dits droits de propriété intellectuelle du
+ Titulaire et/ou des Contributeurs.
+
+
+
+
+
Article 7 - SERVICES ASSOCIES
+
+
7.1 Le Contrat n'oblige en
+ aucun cas le Concédant à la réalisation de prestations
+ d'assistance technique ou de maintenance du Logiciel.
+
Cependant le Concédant reste libre de proposer ce type de
+ services. Les termes et conditions d'une telle assistance
+ technique et/ou d'une telle maintenance seront alors
+ déterminés dans un acte séparé. Ces actes de maintenance
+ et/ou assistance technique n'engageront que la seule
+ responsabilité du Concédant qui les propose.
+
+
+
7.2 De même, tout Concédant
+ est libre de proposer, sous sa seule responsabilité, à ses
+ licenciés une garantie, qui n'engagera que lui, lors de la
+ redistribution du Logiciel et/ou du Logiciel Modifié et ce,
+ dans les conditions qu'il souhaite. Cette garantie et les
+ modalités financières de son application feront l'objet d'un
+ acte séparé entre le Concédant et le Licencié.
+
+
+
+
+ Article 8 -
+ RESPONSABILITE
+
+
8.1 Sous réserve des
+ dispositions de
+ l'article 8.2 ,
+ le Licencié a la faculté, sous réserve de prouver la faute
+ du Concédant concerné, de solliciter la réparation du
+ préjudice direct qu'il subirait du fait du Logiciel et dont
+ il apportera la preuve.
+
+
+
8.2
+ La responsabilité du Concédant est limitée aux engagements
+ pris en application du Contrat et ne saurait être engagée en
+ raison notamment: (i) des dommages dus à l'inexécution,
+ totale ou partielle, de ses obligations par le Licencié,
+ (ii) des dommages directs ou indirects découlant de
+ l'utilisation ou des performances du Logiciel subis par le
+ Licencié et (iii) plus généralement d'un quelconque dommage
+ indirect. En particulier, les Parties conviennent
+ expressément que tout préjudice financier ou commercial (par
+ exemple perte de données, perte de bénéfices, perte
+ d'exploitation, perte de clientèle ou de commandes, manque à
+ gagner, trouble commercial quelconque) ou toute action
+ dirigée contre le Licencié par un tiers, constitue un
+ dommage indirect et n'ouvre pas droit à réparation par le
+ Concédant.
+
+
+
+
+ Article 9 - GARANTIE
+
+
9.1 Le Licencié reconnaît
+ que l'état actuel des connaissances scientifiques et
+ techniques au moment de la mise en circulation du Logiciel
+ ne permet pas d'en tester et d'en vérifier toutes les
+ utilisations ni de détecter l'existence d'éventuels défauts.
+ L'attention du Licencié a été attirée sur ce point sur les
+ risques associés au chargement, à l'utilisation, la
+ modification et/ou au développement et à la reproduction du
+ Logiciel qui sont réservés à des utilisateurs avertis.
+
Il relève de la responsabilité du Licencié de contrôler,
+ par tous moyens, l'adéquation du produit à ses besoins, son
+ bon fonctionnement et de s'assurer qu'il ne causera pas de
+ dommages aux personnes et aux biens.
+
+
+
9.2
+ Le Concédant déclare de bonne foi être en droit de concéder
+ l'ensemble des droits attachés au Logiciel (comprenant
+ notamment les droits visés à l'article
+ 5 ).
+
+
+
9.3 Le Licencié reconnaît
+ que le Logiciel est fourni "en l'état" par le Concédant sans
+ autre garantie, expresse ou tacite, que celle prévue à
+ l'article 9.2
+ et notamment sans aucune garantie sur sa valeur commerciale,
+ son caractère sécurisé, innovant ou pertinent.
+
En particulier, le Concédant ne garantit pas que le
+ Logiciel est exempt d'erreur, qu'il fonctionnera sans
+ interruption, qu'il sera compatible avec l'équipement du
+ Licencié et sa configuration logicielle ni qu'il remplira
+ les besoins du Licencié.
+
+
+
9.4 Le Concédant ne garantit
+ pas, de manière expresse ou tacite, que le Logiciel ne porte
+ pas atteinte à un quelconque droit de propriété
+ intellectuelle d'un tiers portant sur un brevet, un logiciel
+ ou sur tout autre droit de propriété. Ainsi, le Concédant
+ exclut toute garantie au profit du Licencié contre les
+ actions en contrefaçon qui pourraient être diligentées au
+ titre de l'utilisation, de la modification, et de la
+ redistribution du Logiciel. Néanmoins, si de telles actions
+ sont exercées contre le Licencié, le Concédant lui apportera
+ son aide technique et juridique pour sa défense. Cette aide
+ technique et juridique est déterminée au cas par cas entre
+ le Concédant concerné et le Licencié dans le cadre d'un
+ protocole d'accord. Le Concédant dégage toute responsabilité
+ quant à l'utilisation de la dénomination du Logiciel par le
+ Licencié. Aucune garantie n'est apportée quant à l'existence
+ de droits antérieurs sur le nom du Logiciel et sur
+ l'existence d'une marque.
+
+
+
+
Article 10 -
+ RESILIATION
+
+
10.1 En cas de manquement
+ par le Licencié aux obligations mises à sa charge par le
+ Contrat, le Concédant pourra résilier de plein droit le
+ Contrat trente (30) jours après notification adressée au
+ Licencié et restée sans effet.
+
+
+
10.2 Le Licencié dont le
+ Contrat est résilié n'est plus autorisé à utiliser, modifier
+ ou distribuer le Logiciel. Cependant, toutes les licences
+ qu'il aura concédées antérieurement à la résiliation du
+ Contrat resteront valides sous réserve qu'elles aient été
+ effectuées en conformité avec le Contrat.
+
+
+
+
Article 11 - DISPOSITIONS
+ DIVERSES
+
+
+ 11.1 CAUSE EXTERIEURE
+
Aucune
+ des Parties ne sera responsable d'un retard ou d'une
+ défaillance d'exécution du Contrat qui serait dû
+ à un cas de force majeure, un cas fortuit ou une cause
+ extérieure, telle que, notamment, le mauvais fonctionnement
+ ou les interruptions du réseau électrique ou de
+ télécommunication, la paralysie du réseau liée
+ à une attaque informatique, l'intervention des
+ autorités gouvernementales, les catastrophes naturelles, les
+ dégâts des eaux, les tremblements de terre, le feu, les
+ explosions, les grèves et les conflits sociaux, l'état
+ de guerre...
+
+
+
11.2 Le
+ fait, par l'une ou l'autre des Parties, d'omettre
+ en une ou plusieurs occasions de se prévaloir d'une ou
+ plusieurs dispositions du Contrat, ne pourra en aucun cas impliquer
+ renonciation par la Partie intéressée à s'en
+ prévaloir ultérieurement.
+
+
+
11.3 Le Contrat annule et
+ remplace toute convention antérieure, écrite ou orale, entre
+ les Parties sur le même objet et constitue l'accord entier
+ entre les Parties sur cet objet. Aucune addition ou
+ modification aux termes du Contrat n'aura d'effet à l'égard
+ des Parties à moins d'être faite par écrit et signée par
+ leurs représentants dûment habilités.
+
+
+
11.4 Dans l'hypothèse où une
+ ou plusieurs des dispositions du Contrat s'avèrerait
+ contraire à une loi ou à un texte applicable, existants ou
+ futurs, cette loi ou ce texte prévaudrait, et les Parties
+ feraient les amendements nécessaires pour se conformer à
+ cette loi ou à ce texte. Toutes les autres dispositions
+ resteront en vigueur. De même, la nullité, pour quelque
+ raison que ce soit, d'une des dispositions du Contrat ne
+ saurait entraîner la nullité de l'ensemble du Contrat.
+
+
+
+ 11.5 LANGUE
+
Le Contrat est rédigé en langue française et en langue
+ anglaise, ces deux versions faisant également foi.
+
+
+
+
+
Article 12 - NOUVELLES
+ VERSIONS DU CONTRAT
+
+
12.1 Toute personne est
+ autorisée à copier et distribuer des copies de ce
+ Contrat.
+
+
+
12.2 Afin d'en préserver la
+ cohérence, le texte du Contrat est protégé et ne peut être
+ modifié que par les auteurs de la licence, lesquels se
+ réservent le droit de publier périodiquement des mises à
+ jour ou de nouvelles versions du Contrat, qui posséderont
+ chacune un numéro distinct. Ces versions ultérieures seront
+ susceptibles de prendre en compte de nouvelles
+ problématiques rencontrées par les logiciels libres.
+
+
+
12.3 Tout Logiciel diffusé
+ sous une version donnée du Contrat ne pourra faire l'objet
+ d'une diffusion ultérieure que sous la même version du
+ Contrat ou une version postérieure.
+
+
+
+
Article 13 - LOI APPLICABLE
+ ET COMPETENCE TERRITORIALE
+
+
13.1 Le Contrat est régi
+ par la loi française. Les Parties conviennent de tenter de
+ régler à l'amiable les différends ou litiges qui viendraient
+ à se produire par suite ou à l'occasion du Contrat.
+
+
+
+
13.2 A défaut d'accord
+ amiable dans un délai de deux (2) mois à compter de leur
+ survenance et sauf situation relevant d'une procédure
+ d'urgence, les différends ou litiges seront portés par la
+ Partie la plus diligente devant les Tribunaux compétents de
+ Paris.
+
+
+
+ Version 1.0 du 2006-09-05.
+
+
diff --git a/src/java/misc/ApplicationManager.java b/src/java/misc/ApplicationManager.java
new file mode 100644
index 0000000..4fe4368
--- /dev/null
+++ b/src/java/misc/ApplicationManager.java
@@ -0,0 +1,12 @@
+package misc;
+
+import java.awt.Container;
+import java.util.Hashtable;
+import javax.swing.AbstractButton;
+import javax.swing.JMenu;
+
+public interface ApplicationManager {
+ public void addMenuItem (JMenu... jMenu);
+ public void addIconButtons (Container... containers);
+ public void addActiveButtons (Hashtable buttons);
+}
diff --git a/src/java/misc/Bundle.java b/src/java/misc/Bundle.java
new file mode 100644
index 0000000..c2ba267
--- /dev/null
+++ b/src/java/misc/Bundle.java
@@ -0,0 +1,532 @@
+package misc;
+
+import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.Graphics2D;
+import java.awt.Polygon;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLConnection;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.Vector;
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.border.TitledBorder;
+
+/**
+ Managed the internalization by using files properties and ResourceBundle.
+ This class could be used to managed all texts show in a application (buttons, menus, labels).
+ The files properties could be embedded in a jar (mix of class and data) or a dedicated directory.
+ The name file look like : applicationBundle[_langage[_COUNTRY[_VARIANT]]].properties .
+ Each file contains a "bundle" of key/value association.
+ The values are string represent message or formated sentences (with numbered holes to put variables values).
+*/
+public class Bundle {
+
+ static public final String FS = System.getProperty ("file.separator");
+
+ // = Constants ============================
+ /** Bundle file extension. */
+ static public final String bundleExt = ".properties";
+
+ /** Postfix for title. */
+ static public final String titlePostfix = "Title";
+
+ /** Prefixe for all actioners (button, menus, menuItem) */
+ static public final String actionPrefix = "Action";
+
+ /** XXX commentaire */
+ static public final String labelPrefix = "Label";
+ static public final String storyPrefix = "Story";
+
+ /** XXX commentaire */
+ static public final String messagePrefix = "Message";
+
+ /** XXX commentaire */
+ static public final String exceptionPrefix = "Exception";
+
+ /** XXX commentaire */
+ static public final String userPrefix = "User_";
+
+ /** XXX commentaire */
+ static public final String enumPrefix = "Enum";
+
+ /** Message shows when when try use bundle before load it. */
+ static private final String bundleUseException = "Can''t find token \"{0}\" in Bundle. Continue?";
+ static private final String bundleSaveException = "Bundle {0} can''t be save.";
+
+ // = Attributs ============================
+ static class ApplicationInfo {
+ public ResourceBundle messages;
+ public Hashtable patch = new Hashtable ();
+ public boolean modified;
+ public ApplicationInfo (ResourceBundle messages) { this.messages = messages; }
+ }
+
+ /** Labels to bundle to find to display.*/
+ static private Hashtable labels = new Hashtable ();
+ /** Applications bundle name to bundle. */
+ static private Hashtable applications = new Hashtable ();
+ static private ArrayList applicationsOrder = new ArrayList ();
+ /** The current locale used to display messages. */
+ static private Locale locale;
+
+
+ // = Accessors ============================
+ /**
+ Accessors to locale.
+ @return current locale.
+ */
+ static public Locale getLocale () { return locale; }
+ /**
+ Accesor to locale.
+ @param locale the new locale value.
+ */
+ static public void setLocale (Locale locale) {
+ resetLocale (locale);
+ broadcastBundleReloaded ();
+ }
+
+ static private final void initLocale () {
+ if (locale != null)
+ return;
+ Locale locale = Locale.getDefault ();
+ if (Config.getString ("Language") != null)
+ try {
+ locale = new Locale (Config.getString ("Language"),
+ Config.getString ("Country"),
+ Config.getString ("Variant"));
+ } catch (Exception e) {
+ }
+ resetLocale (locale);
+ }
+
+ static private void resetLocale (Locale locale) {
+ if (Bundle.locale == locale ||
+ (Bundle.locale != null && Bundle.locale.equals (locale)))
+ return;
+ Locale.setDefault (locale);
+ Bundle.locale = locale;
+ for (String application : applicationsOrder) {
+ ResourceBundle messages = ResourceBundle.getBundle (application, locale, bundleControl);
+ applications.put (application, new ApplicationInfo (messages));
+ }
+ }
+
+ static ResourceBundle.Control bundleControl = new ResourceBundle.Control () {
+ private String toResourceName0 (String bundleName, String suffix) {
+ if (bundleName.contains ("://"))
+ return null;
+ else
+ return toResourceName (bundleName, suffix);
+ }
+ public ResourceBundle newBundle (String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
+ throws IllegalAccessException, InstantiationException, IOException {
+ String bundleName = toBundleName (baseName, locale);
+ ResourceBundle bundle = null;
+ final String resourceName = toResourceName0 (bundleName, "properties");
+ if (resourceName == null)
+ return bundle;
+ URLConnection connection = Config.getDataUrl (Config.dataDirname, Config.configDirname, resourceName).openConnection ();
+ connection.setUseCaches (false);
+ InputStream stream = connection.getInputStream ();
+ try {
+ bundle = new PropertyResourceBundle (stream);
+ } finally {
+ stream.close ();
+ }
+ return bundle;
+ }
+ };
+
+ // = Reading files ========================
+ /**
+ Set the new application and load bundle with parameter saved in configuration or the default system locale.
+ @param application the application bundle name.
+ */
+ static public final void load (String application) {
+ initLocale ();
+ load (application, locale);
+ }
+
+ /**
+ Set the new application and load bundle according the locale in parameter.
+ @param application the application bundle name.
+ @param locale the localization to used.
+ */
+ static public final void load (String application, Locale locale) {
+ try {
+ resetLocale (locale);
+ if (applicationsOrder.contains (application))
+ return;
+ applicationsOrder.add (application);
+ ResourceBundle messages = ResourceBundle.getBundle (application, locale, bundleControl);
+ // XXX anciennes valeurs de patch perdues
+ applications.put (application, new ApplicationInfo (messages));
+ for (String key : messages.keySet ())
+ labels.put (key, application);
+ boolean needSetLanguage = Config.getString ("Language") == null;
+ broadcastBundleReloaded ();
+ if (needSetLanguage)
+ HelpManager.actionLocale (null);
+ } catch (RuntimeException e) {
+ if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog
+ (null, "Would you like to continue?",
+ " Can't load Bundle "+application, JOptionPane.YES_NO_OPTION))
+ throw e;
+ }
+ }
+
+ static public final void save (String applicationName) {
+ File configDir = new File (Config.findDataDir (true), Config.configDirname);
+ File bundleFile = new File (configDir, applicationName+"_"+locale+bundleExt);
+ try {
+ save (applicationName, bundleFile);
+ } catch (IOException e) {
+ try {
+ configDir.mkdirs ();
+ save (applicationName, bundleFile);
+ } catch (IOException e2) {
+ System.err.println (MessageFormat.format (bundleSaveException, applicationName));
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException (bundleUseException);
+ }
+ }
+ static private boolean configurationModified = false;
+ static public final void save (String applicationName, File file)
+ throws IOException {
+ ApplicationInfo applicationInfo = applications.get (applicationName);
+ if (!applicationInfo.modified && file.exists ())
+ return;
+ if (!file.exists ())
+ file.createNewFile ();
+ Properties properties = new Properties ();
+ ResourceBundle messages = applicationInfo.messages;
+ for (String key : messages.keySet ())
+ properties.setProperty (key, messages.getString (key));
+ Hashtable patch = applicationInfo.patch;
+ for (String key : patch.keySet ())
+ properties.setProperty (key, patch.get (key));
+ FileOutputStream fileOutputStream = new FileOutputStream (file);
+ properties.store (fileOutputStream, "Produit automatiquement par Bundle");
+ fileOutputStream.close ();
+ FileInputStream fileInputStream = new FileInputStream (file);
+ applicationInfo.messages = new PropertyResourceBundle (fileInputStream);
+ fileInputStream.close ();
+ applicationInfo.patch.clear ();
+ applicationInfo.modified = false;
+ }
+ static public void setString (String applicationName, String key, String val) {
+ ApplicationInfo applicationInfo = applications.get (applicationName);
+ String oldVal = null;
+ try {
+ oldVal = applicationInfo.messages.getString (key);
+ } catch (Exception e) {
+ }
+ if (val == oldVal || val.equals (oldVal)) {
+ applicationInfo.patch.remove (key);
+ return;
+ }
+ oldVal = applicationInfo.patch.get (key);
+ if (val == oldVal || val.equals (oldVal))
+ return;
+ applicationInfo.patch.put (key, val);
+ applicationInfo.modified = true;
+ labels.put (key, applicationName);
+ }
+
+ // = Available files ======================
+ /**
+ Give the list of locale available for a dedicated application.
+ @param application the application bundle name.
+ @return a array of string denoted locale that could be used for this application.
+ */
+ static public final Locale[] getApplicationsLocales () {
+ Vector result = new Vector ();
+ scanLocale: for (Locale locale : getAvailableLocales ()) {
+ for (String application : applications.keySet ())
+ if (ClassLoader.getSystemResource (Config.configSystemDir+application+"_"+locale+bundleExt) == null &&
+ ClassLoader.getSystemResource (Config.configJarDir+application+"_"+locale+bundleExt) == null)
+ continue scanLocale;
+ result.add (locale);
+ }
+ Locale [] locales = result.toArray (new Locale[0]);
+ Arrays.sort (locales, new Comparator () {
+ public int compare(Locale o1, Locale o2) {
+ return o1.toString ().compareTo (o2.toString ());
+ }
+ });
+ return locales;
+ }
+
+ // ========================================
+
+ static public Locale[] getAvailableLocales () {
+ ArrayList all = new ArrayList (Arrays.asList (Locale.getAvailableLocales ()));
+ //all.add (new Locale.Builder ().setLanguage ("br").setRegion ("BR").setVariant ("gallo").build ());
+ //all.add (new Locale.Builder ().setLanguage ("br").setRegion ("BR").setVariant ("breton").build ());
+ all.add (new Locale.Builder ().setLanguage ("br").setRegion ("FR").setVariant ("gallo").build ());
+ all.add (new Locale.Builder ().setLanguage ("br").setRegion ("FR").setVariant ("breton").build ());
+ //all.add (new Locale.Builder ().setLanguage ("es").setRegion ("ES").build ());
+ return all.toArray (new Locale[0]);
+ }
+ static public final Locale[] getAllLocales () {
+ Locale[] locales = getAvailableLocales ();
+ Arrays.sort (locales, new Comparator () {
+ public int compare(Locale o1, Locale o2) {
+ return o1.toString ().compareTo (o2.toString ());
+ }
+ });
+ return locales;
+ }
+
+ static public ImageIcon getMixFlag (String language, String country) {
+ ImageIcon countryFlag = Util.loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.flagsDirname,
+ country.toLowerCase () + Config.iconsExt);
+ ImageIcon langFlag = Util.loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.flagsDirname,
+ language.toLowerCase () + Config.iconsExt);
+ if (countryFlag == null)
+ return langFlag;
+ if (langFlag == null)
+ return countryFlag;
+ int width = countryFlag.getIconWidth ();
+ int height = countryFlag.getIconHeight ();
+ BufferedImage newFlag = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2 = newFlag.createGraphics ();
+ Polygon topLeftCorner = new Polygon (new int[] {0, width, 0}, new int[] {0, 0, height}, 3);
+ g2.setClip (topLeftCorner);
+ g2.drawImage (langFlag.getImage (), 0, 0, width, height, null);
+ Polygon bottomRightCorner = new Polygon (new int[] {0, width, width}, new int[] {height, 0, height}, 3);
+ g2.setClip (bottomRightCorner);
+ g2.drawImage (countryFlag.getImage (), 0, 0, width, height, null);
+ return new ImageIcon (newFlag);
+ }
+
+ // ========================================
+ static public final JComboBox getJComboFlags (final Locale[] locales) {
+ final ImageIcon [] flags = new ImageIcon [locales.length];
+ String [] labels = new String [locales.length];
+ final Hashtable labelIndex = new Hashtable ();
+ for (int i = 0; i < locales.length; i++) {
+ labelIndex.put (labels [i] = locales[i].toString (), i);
+ flags [i] = getMixFlag (locales[i].getLanguage (), locales[i].getCountry ());
+ if (flags [i] != null)
+ flags [i].setDescription (locales [i].toString ());
+ }
+ JComboBox localesList = new JComboBox (labels);
+ localesList.setRenderer (new DefaultListCellRenderer () {
+ {
+ setOpaque (true);
+ setVerticalAlignment (CENTER);
+ }
+ static private final long serialVersionUID = 1L;
+ public Component getListCellRendererComponent (JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ int selectedIndex = labelIndex.get (value);
+
+ if (isSelected) {
+ setBackground (list.getSelectionBackground ());
+ setForeground (list.getSelectionForeground ());
+ } else {
+ setBackground (list.getBackground ());
+ setForeground (list.getForeground ());
+ }
+ setIcon (flags[selectedIndex]);
+ setText (locales[selectedIndex].toString ());
+ return this;
+ }
+ });
+ return localesList;
+ }
+
+ // = Use localized texts ==================
+ /**
+ Give the string to display according to the message identifier.
+ @param messageId a sting used to tag message.
+ @return the string to display.
+ */
+ static public boolean askBundleUseException = true;
+ static public final String getString (String messageId, String defaultValue) {
+ try {
+ ApplicationInfo applicationInfo = applications.get (labels.get (messageId));
+ String val = applicationInfo.patch.get (messageId);
+ if (val != null)
+ return val;
+ return applicationInfo.messages.getString (messageId);
+ } catch (Exception e) {
+ if (defaultValue != null)
+ return defaultValue;
+ if (askBundleUseException && JOptionPane.YES_OPTION !=
+ JOptionPane.showConfirmDialog (null, MessageFormat.format (bundleUseException, messageId),
+ " Bundle corrupted ", JOptionPane.YES_NO_OPTION))
+ throw new IllegalArgumentException (MessageFormat.format (bundleUseException, messageId));
+ askBundleUseException = false;
+ System.err.println (messageId+"= ### Bundle ###");
+ return messageId;
+ }
+ }
+ static public final String getStory (String messageId) { return getString (storyPrefix+messageId, messageId); }
+ static public final String getLabel (String messageId) { return messageId == null ? "" : getString (labelPrefix+messageId, null); }
+ static public final String getMessage (String messageId) { return getString (messagePrefix+messageId, null); }
+ static public final String getException (String messageId) { return getString (exceptionPrefix+messageId, null); }
+ static public final String getAction (String messageId) { return getString (actionPrefix+messageId, null); }
+ static public final String getTitle (String messageId) { return getString (messageId+titlePostfix, null); }
+ static public final String getUser (String messageId) { return getString (userPrefix+messageId, messageId); }
+ static public final void setUser (String applicationName, String messageId, String value) {
+ setString (applicationName, userPrefix+messageId, value);
+ }
+ static public final String getEnum (String enumId, String valueId) { return getString (enumPrefix+enumId+valueId, null); }
+ static public final String getEnum (Enum> enumValue) { return getEnum (enumValue.getClass ().getSimpleName (), enumValue.toString ()); }
+ static public final JComboBox getEnum (Class> enumClass, Enum> defaultValue) {
+ String enumName = enumClass.getSimpleName ();
+ if (!enumClass.isEnum ())
+ throw new IllegalArgumentException (enumName+" is not Enum!");
+ JComboBox jComboBox = new JComboBox ();
+ try {
+ Object[] values = (Object[]) enumClass.getMethod ("values").invoke (null);
+ for (Object value : values)
+ jComboBox.addItem (getEnum (enumName, value.toString ()));
+ jComboBox.setEditable (false);
+ if (defaultValue != null)
+ jComboBox.setSelectedIndex (defaultValue.ordinal ());
+ } catch (Exception e) {
+ throw new IllegalArgumentException (enumName+" is not Enum!");
+ }
+ return jComboBox;
+ }
+
+ // = Automatic update =====================
+
+ static public void setBorder (JComponent jComponent) {
+ jComponent.setBorder (BorderFactory.createTitledBorder (Bundle.getTitle (Util.getClassName (jComponent.getClass ()))));
+ }
+ static public void updateBorder (JComponent jComponent) {
+ ((TitledBorder) jComponent.getBorder ()).setTitle (Bundle.getTitle (Util.getClassName (jComponent.getClass ())));
+ }
+
+ /** List of actioners (button, ...) to update if the locale is updated. */
+ static private Vector allActioners = new Vector ();
+
+ /** List of actioners (menu, ...) to update if the locale is updated. */
+ static private Vector allMenus = new Vector ();
+
+ /** List of frame to update if the locale is updated. */
+ static private Hashtable allDialogs = new Hashtable ();
+
+ /** List of icon ToolTips to update if the locale is updated. */
+ static private Vector allIconToolTips = new Vector ();
+
+ /** List of application module which managed localized texts to update if the locale is updated. */
+ static private Hashtable allLabels = new Hashtable ();
+
+ /** XXX commentaire. */
+ static private Hashtable, Class>> allEnums = new Hashtable, Class>> ();
+
+ /** XXX commentaire. */
+ static private StateNotifier bundleObservable = new StateNotifier ();
+
+ /**
+ Say to each actioner and application module that locale change.
+ */
+ static void broadcastBundleReloaded () {
+ if (Config.isLoaded ()) {
+ Config.setString ("Country", locale.getCountry ());
+ Config.setString ("Language", locale.getLanguage ());
+ Config.setString ("Variant", locale.getVariant ());
+ }
+ for (AbstractButton actioner : allActioners)
+ if (!actioner.getText ().isEmpty ())
+ actioner.setText (getAction (actioner.getActionCommand ()));
+ for (AbstractButton menu : allMenus)
+ if (!menu.getText ().isEmpty ())
+ menu.setText (getTitle (menu.getActionCommand ()));
+ for (Dialog dialog : allDialogs.keySet ())
+ dialog.setTitle (getTitle (allDialogs.get (dialog)));
+ for (AbstractButton actioner : allIconToolTips)
+ actioner.setToolTipText (Bundle.getAction (actioner.getActionCommand ()));
+ for (JLabel jLabel : allLabels.keySet ())
+ jLabel.setText (getLabel (allLabels.get (jLabel)));
+ for (JComboBox jComboBox : allEnums.keySet ())
+ try {
+ Class> enumClass = allEnums.get (jComboBox);
+ String enumName = enumClass.getSimpleName ();
+ // XXX remove listeners
+ // XXX sauve selection multiple ?
+ int idx = jComboBox.getSelectedIndex ();
+ jComboBox.removeAllItems ();
+ Object[] values = (Object[]) enumClass.getMethod ("values").invoke (null);
+ for (Object value : values)
+ jComboBox.addItem (getEnum (enumName, value.toString ()));
+ jComboBox.setEditable (false);
+ jComboBox.setSelectedIndex (idx);
+ // XXX add listeners
+ } catch (Exception e) {
+ }
+ bundleObservable.broadcastUpdate ("Bundle");
+ }
+
+ /**
+ Declare an actioner to updated if the locale is updated.
+ @param button the actioner to update. The messageId is find by performed getActionCommand method on it.
+ */
+ static public void addLocalizedActioner (AbstractButton button) {
+ allActioners.add (button);
+ }
+
+ static public void addLocalizedMenu (AbstractButton button) {
+ allMenus.add (button);
+ }
+
+ static public void addLocalizedDialog (Dialog dialog, String titleId) {
+ allDialogs.put (dialog, titleId);
+ }
+ /**
+ XXX commentaire
+ */
+ static public void addLocalizedToolTip (AbstractButton button) {
+ allIconToolTips.add (button);
+ }
+
+ /**
+ XXX commentaire
+ */
+ static public void addLocalizedLabel (JLabel jLabel, String messageId) {
+ allLabels.put (jLabel, messageId);
+ }
+
+ /**
+ XXX commentaire
+ */
+ static public void addLocalizedEnum (JComboBox jComboBox, Class> enumClass) {
+ allEnums.put (jComboBox, enumClass);
+ }
+
+ /**
+ Declare an application module which managed localized to updated if the locale is updated.
+ @param object the application module that managed some texts to localized.
+ */
+ static public void addBundleObserver (Object object) {
+ bundleObservable.addUpdateObserver (object, "Bundle");
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/ColorCheckedLine.java b/src/java/misc/ColorCheckedLine.java
new file mode 100644
index 0000000..3cd828b
--- /dev/null
+++ b/src/java/misc/ColorCheckedLine.java
@@ -0,0 +1,24 @@
+package misc;
+
+public class ColorCheckedLine {
+
+ // ============================================================
+ static public final int NBV = 8;
+ static public final int NBT = 60;
+
+ /** voir http://www.termsys.demon.co.uk/vtansi.htm */
+ static public final String
+ MOVE_TO_COL_START = "\033[300C\033[",
+ MOVE_TO_COL_END = "D",
+ SETCOLOR_SUCCESS = "\033[1;32m",
+ SETCOLOR_FAILURE ="\033[1;31m",
+ SETCOLOR_WARNING ="\033[1;33m",
+ SETCOLOR_NORMAL ="\033[0;39m";
+
+ static public final String
+ MOVE_TO_60 = MOVE_TO_COL_START+(80-60)+MOVE_TO_COL_END,
+ MSG_OK = MOVE_TO_60+"["+SETCOLOR_SUCCESS+"OK"+SETCOLOR_NORMAL+"]",
+ MSG_KO = MOVE_TO_60+"["+SETCOLOR_FAILURE+"KO"+SETCOLOR_NORMAL+"]";
+
+ // ========================================
+}
diff --git a/src/java/misc/CommandLineServer.java b/src/java/misc/CommandLineServer.java
new file mode 100644
index 0000000..0b9d2b6
--- /dev/null
+++ b/src/java/misc/CommandLineServer.java
@@ -0,0 +1,154 @@
+package misc;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.TreeSet;
+import java.util.Vector;
+
+public class CommandLineServer {
+
+ // ========================================
+ private Model model;
+ private Class extends CommandLineWaiter> classWaiter;
+ private String classWaiterName;
+ /** List of commands. */
+ private TreeSet commands = new TreeSet ();
+ /** Help for each command. */
+ private Hashtable help = new Hashtable ();
+ private Hashtable actionsMethod = new Hashtable ();
+
+ // ========================================
+ public TreeSet getCommands () { return commands; }
+ public Hashtable getHelp () { return help; }
+ public Hashtable getActionsMethod () { return actionsMethod; }
+ public String getClassWaiterName () { return classWaiterName; }
+
+ // ========================================
+ public void showMsg (String msg) {}
+ public void showStatus (String msg) {}
+
+ // ========================================
+ public CommandLineServer (Model model, Class extends CommandLineWaiter> classWaiter, Collection commands) {
+ this.model = model;
+
+ this.classWaiter = classWaiter;
+ String[] path = classWaiter.getName ().split ("\\.");
+ classWaiterName = path [path.length-1];
+
+ for (String action : commands)
+ this.commands.add (action.toLowerCase ());
+ for (String action : this.commands) {
+ try {
+ String methodName = "action"+Util.toCapital (action);
+ actionsMethod.put (action, classWaiter.getMethod (methodName));
+ } catch (NoSuchMethodException e) {
+ Log.keepLastException ("CommandLineServer", e);
+ }
+ }
+ updateBundle ();
+ Bundle.addBundleObserver (this);
+ }
+
+ // ========================================
+ public void updateBundle () {
+ help.clear ();
+ for (String cmd : commands)
+ help.put (cmd, Bundle.getString ("Help"+classWaiterName+"_"+cmd, null).replaceAll ("\\\\n", "\n"));
+ }
+
+ /** In case of multiple started, this is the only thread wich have right to run. */
+ private Thread thread;
+
+ // ========================================
+ public boolean isAliveServer () {
+ return thread != null && thread.isAlive ();
+ }
+
+ // ========================================
+ private int lastPort;
+ /** Interrupt the server after a TIME_OUT. */
+ public void stopServer () {
+ thread = null;
+ try {
+ // force le accept pour sortir du run
+ (new Socket ("localhost", lastPort)).close ();
+ } catch (Exception e) {
+ }
+ stopCalls ();
+ }
+
+ Vector calls = new Vector ();
+ public synchronized void addCall (Socket call) {
+ calls.add (call);
+ }
+ public synchronized void removeCall (Socket call) {
+ calls.remove (call);
+ }
+ public synchronized void stopCalls () {
+ for (Socket call : calls) {
+ try {
+ call.close ();
+ } catch (Exception e) {
+ }
+ }
+ calls.clear ();
+ }
+
+ // ========================================
+ /**
+ * Start a server on a dedicated port.
+ * @param port the internet port number.
+ */
+ public void startServer (final int port) {
+ (new Thread () {
+ public void run () {
+ ServerSocket serverSocket = null;
+ try {
+ serverSocket = new ServerSocket (port);
+ CommandLineServer.this.lastPort = port;
+ } catch (IOException e) {
+ showMsg (Bundle.getMessage ("CanTCreateSocket"));
+ Log.keepLastException ("CommandLineServer::startServer", e);
+ return;
+ }
+ showMsg (MessageFormat.format (Bundle.getMessage (classWaiterName+"Starts"), port));
+ showStatus (MessageFormat.format (Bundle.getMessage (classWaiterName+"Starts"), port));
+ thread = Thread.currentThread ();
+ try {
+ while (thread == Thread.currentThread ()) {
+ try {
+ Socket call = serverSocket.accept ();
+ addCall (call);
+ classWaiter.getConstructor (CommandLineServer.class, model.getClass (), Socket.class).
+ newInstance (CommandLineServer.this, model, call);
+ } catch (IOException e) {
+ showMsg (Bundle.getMessage ("ClientAbort"));
+ Log.keepLastException ("CommandLineServer::startServer", e);
+ }
+ }
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ Log.keepLastException ("CommandLineServer::startServer", e);
+ } catch (NoSuchMethodException e) {
+ Log.keepLastException ("CommandLineServer::startServer", e);
+ } catch (IllegalAccessException e) {
+ Log.keepLastException ("CommandLineServer::startServer", e);
+ } catch (InstantiationException e) {
+ Log.keepLastException ("CommandLineServer::startServer", e);
+ }
+ try {
+ showMsg (Bundle.getMessage (classWaiterName+"Stopped"));
+ showStatus (Bundle.getMessage (classWaiterName+"Stopped"));
+ serverSocket.close ();
+ } catch (IOException e) {
+ }
+ }
+ }).start();
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/CommandLineWaiter.java b/src/java/misc/CommandLineWaiter.java
new file mode 100644
index 0000000..c5aa906
--- /dev/null
+++ b/src/java/misc/CommandLineWaiter.java
@@ -0,0 +1,165 @@
+package misc;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.net.SocketException;
+import java.text.MessageFormat;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+public class CommandLineWaiter {
+
+ // ========================================
+ static public final int MAX_COL = 6;
+
+ // ========================================
+ protected Model model;
+ protected CommandLineServer commandLineServer;
+
+ private TreeSet commands;
+ private Hashtable help;
+ private Hashtable actionsMethod;
+
+ /** The original call socket to be close at the end of analyse. */
+ protected Socket call;
+ /** Input chanel (of the socket). */
+ protected BufferedReader in;
+ /** Output chanel (of the socket). */
+ protected PrintWriter out;
+ protected String line;
+ protected StringTokenizer arguments;
+
+ public boolean hasMoreArg () {
+ return arguments.hasMoreTokens ();
+ }
+ public String nextArg () {
+ return arguments.nextToken ().trim ();
+ }
+
+ public void startCall () {}
+
+ // ========================================
+ public String getCommandLine (BufferedReader in)
+ throws IOException {
+ try {
+ return in.readLine ().trim ();
+ } catch (SocketException e) {
+ return null;
+ } catch (NullPointerException e) {
+ return null;
+ }
+ }
+ // ========================================
+ /**
+ * Send a answer to the client with a newline and flush the output chanel.
+ * @param str the answer to send.
+ */
+ public void answerln (String str) {
+ out.println (str);
+ out.flush ();
+ }
+
+ public void syntaxError () {
+ answerln (Bundle.getMessage ("SyntaxeError"));
+ }
+
+ // ========================================
+ /**
+ * Give a help to the client.
+ * @param cmd is null or empty, give the list of commands. Else, give a appropriate help for the command cmd.
+ */
+ public void actionHelp () {
+ String arg = null;
+ if (hasMoreArg ())
+ arg = nextArg ().toLowerCase ();
+ if (arg == null || arg.isEmpty ())
+ answerln (Bundle.getString ("Help"+commandLineServer.getClassWaiterName ()+"_", null).replaceAll ("\\\\n", "\n")+
+ Util.toColumn (Util.set2string (commands), MAX_COL));
+ else {
+ String explanation = help.get (arg);
+ if (explanation == null)
+ answerln (MessageFormat.format (Bundle.getMessage ("NotACommand"), arg));
+ else
+ answerln (arg.toLowerCase ()+" "+explanation);
+ }
+ }
+
+ // ========================================
+ public void actionQuit () {
+ answerln (Bundle.getMessage ("SeeYouSoon").replaceAll ("\\\\n", "\n"));
+ try {
+ call.close ();
+ } catch (Exception e) {
+ }
+ }
+
+ // ========================================
+ public void actionExit () {
+ answerln (Bundle.getMessage ("GoodBye").replaceAll ("\\\\n", "\n"));
+ System.exit (0);
+ }
+
+ // ========================================
+ /**
+ * Open a chanel and start a shell interpretor.
+ * @param call the client connection.
+ */
+ public CommandLineWaiter (CommandLineServer commandLineServer, Model model, Socket call) {
+ this.commandLineServer = commandLineServer;
+ this.model = model;
+ this.call = call;
+
+ commands = commandLineServer.getCommands ();
+ help = commandLineServer.getHelp ();
+ actionsMethod = commandLineServer.getActionsMethod ();
+ try {
+ in = new BufferedReader (new InputStreamReader (call.getInputStream ()));
+ out = new PrintWriter (call.getOutputStream ());
+ startCall ();
+ (new Thread () {
+ public void run() {
+ analyse ();
+ }
+ }).start();
+ } catch (IOException e) {
+ if (!call.isClosed ())
+ Log.keepLastException ("CommandLineWaiter", e);
+ }
+ }
+
+ // ========================================
+ public void analyse () {
+ String cmd = null;
+ try {
+ for (; ! call.isClosed (); ) {
+ line = getCommandLine (in);
+ if (line == null)
+ break;
+ if (line.isEmpty ())
+ continue;
+ arguments = new StringTokenizer (line);
+ if (!arguments.hasMoreTokens ())
+ continue;
+ cmd = arguments.nextToken ().trim ().toLowerCase ();
+ if (commands.contains (cmd))
+ actionsMethod.get (cmd).invoke (this);
+ else
+ answerln (MessageFormat.format (Bundle.getMessage ("NotACommand"), cmd));
+ }
+ } catch (Exception e) {
+ Log.keepLastException ("CommandLineWaiter::analyse ("+cmd+")", e);
+ } finally {
+ try {
+ call.close ();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/Config.java b/src/java/misc/Config.java
new file mode 100644
index 0000000..9b263d8
--- /dev/null
+++ b/src/java/misc/Config.java
@@ -0,0 +1,523 @@
+package misc;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Vector;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.ListModel;
+
+/**
+ Managed the persistance key/value strings association.
+ This class could be used to managed all constants values in a application.
+ The values commme from a bundle jar (mix of class and data) or a dedicated directeory.
+*/
+public class Config {
+
+ static public final String FS = System.getProperty ("file.separator");
+
+ static public final String
+ dataDirname = "data",
+ configDirname = "config",
+ textsDirname = "texts",
+ logDirname = "log",
+ imagesDirname = "images",
+ iconsDirname = "images",
+ buttonDirname = "button",
+ flagsDirname = "flags";
+
+ /** Path to configuration files in files system. */
+ static public final String
+ configSystemDir = dataDirname+FS+configDirname+FS,
+ logSystemDir = dataDirname+FS+logDirname+FS,
+ buttonSystemDir = dataDirname+FS+imagesDirname+FS+buttonDirname+FS;
+
+ /** Path to configuration files in jar. */
+ static public final String
+ configJarDir = dataDirname+"/"+configDirname+"/",
+ imagesJarDir = dataDirname+"/"+imagesDirname+"/",
+ textsJarDir = dataDirname+"/"+textsDirname+"/";
+
+ /** Configuration file extension. */
+ static public final String
+ configExt = ".xml",
+ iconsExt = ".png",
+ imagesExt = ".png",
+ htmlExt = ".html",
+ logExt = ".log";
+
+
+ /** Enconding charset for saving configuration. */
+ static public final String configEncoding = "UTF8";
+
+ /** Comment used as header configuration file. */
+ static public final String configHeaderFile =
+ "This file is automaticaly generated by {0} application at {1,time,short} on {1,date}.";
+
+ /** Somme postfix for constants name in configuration file. */
+ static public final String
+ checkedPostfix = "Checked",
+ undockedPostfix = "Undocked",
+ locationPostfix = "Location";
+
+ /** Message shows when trying to get string with a null key. */
+ static private final String configNullKeyException = "No configuration associates with null key.";
+
+ /** Message shows when trying to use configuration before load it. */
+ static private final String configUseException = "No configuration loaded.";
+
+ /** Message shows when load exception appears. */
+ static private final String configLoadException = "Configuration {0} can''t be load (corrupted file ?).";
+
+ /** Message shows when save exception appears. */
+ static private final String configSaveException = "Configuration {0} can''t be save.";
+
+ /** Liste of constants (key/value strings association). */
+ //static private Properties configuration;
+ static public Properties configuration;
+
+ /** True if configuration need to be saved. */
+ static private boolean configurationModified = false;
+
+ // ========================================
+ static private File PWD;
+ static private String[] dataPath;
+ static {
+ setPWD (Util.class);
+ setDataPath (".:..");
+ }
+
+ static public File getJarFileOrClassDir (Class> applicationClass) {
+ try {
+ return new File (applicationClass.getProtectionDomain ().getCodeSource ().getLocation ().toURI ());
+ } catch (Exception e) {
+ // dosn't work for applet
+ return null;
+ }
+ }
+ static public File getPWD () { return PWD; }
+ // XXX static public String getPWD () { return PWD.getAbsolutePath (); }
+ static public void setPWD (Class> applicationClass) {
+ try {
+ PWD = getJarFileOrClassDir (applicationClass).getParentFile ();
+ } catch (Exception e) {
+ }
+ }
+ static public void setDataPath (String path) {
+ dataPath = path.split (":");
+ }
+ static public File findDataDir () {
+ return findDataDir (false);
+ }
+ static public File findDataDir (boolean writable) {
+ String name = dataDirname;
+ try {
+ // search from excecution dir
+ File file = (new File (name));
+ if (file.exists () && file.isDirectory () && (!writable || file.canWrite ()))
+ return file;
+ } catch (Exception e) {
+ }
+ for (String path : dataPath) {
+ try {
+ // search in relative path from jar
+ File file = (new File (PWD, path+FS+name));
+ if (file.exists () && file.isDirectory () && (!writable || file.canWrite ()))
+ return file;
+ } catch (Exception e) {
+ }
+ }
+ return null;
+ }
+
+ static public URL getDataUrl (String... names) {
+ if (names.length < 1)
+ return null;
+ String name = names[names.length - 1];
+ String jarPath = "", systemPath = "";
+ for (int i = 0; i < names.length - 1; i++) {
+ jarPath += names[i]+"/";
+ systemPath += names[i]+FS;
+ }
+ try {
+ // search from excecution dir
+ File file = new File (systemPath+name);
+ if (file.exists ())
+ return file.toURI ().toURL ();
+ } catch (Exception e) {
+ }
+ for (String path : dataPath) {
+ try {
+ // search in relative path from jar
+ File file = new File (PWD, path+FS+systemPath+name);
+ if (file.exists ())
+ return file.getCanonicalFile ().toURI ().toURL ();
+ } catch (Exception e) {
+ }
+ }
+ try {
+ // search in jar
+ URL result = ClassLoader.getSystemResource (jarPath+name);
+ return result;
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ // ========================================
+ /**
+ Load XML configuration file contains constants (key/value strings association).
+ @param applicationName the application name use to find file.
+ */
+ static public final void load (String applicationName) {
+ configuration = new Properties ();
+ try {
+ File configDir = new File (findDataDir (), configDirname);
+ File configFile = new File (configDir, applicationName+configExt);
+ FileInputStream fileInputStream = new FileInputStream (configFile);
+ configuration.loadFromXML (fileInputStream);
+ fileInputStream.close ();
+ configurationModified = false;
+ } catch (Exception e) {
+ try {
+ configuration.loadFromXML (ClassLoader.getSystemResourceAsStream
+ (configJarDir+applicationName+configExt));
+ configurationModified = false;
+ } catch (Exception e2) {
+ try {
+ configuration.loadFromXML (ClassLoader.getSystemResourceAsStream
+ (configJarDir+applicationName+configExt));
+ configurationModified = false;
+ } catch (Exception e3) {
+ if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog
+ (null, "Would you like to continue?",
+ " Can't load Configuration ", JOptionPane.YES_NO_OPTION))
+ throw new IllegalArgumentException (MessageFormat.format (configLoadException, applicationName));
+ }
+ }
+ }
+ }
+
+ // ========================================
+ /**
+ Return the loading state of the configuration.
+ @return true if the configuration is loaded.
+ */
+ static public boolean isLoaded () {
+ return configuration != null;
+ }
+
+ // ========================================
+ /**
+ Save XML configuration file contains key/value strings association.
+ The file is not writing if no modification occure.
+ @param applicationName the application name use to save file.
+ */
+ static public final void save (String applicationName) {
+ File configDir = new File (findDataDir (true), configDirname);
+ File configFile = new File (configDir, applicationName+configExt);
+ try {
+ save (applicationName, configFile);
+ } catch (IOException e) {
+ try {
+ e.printStackTrace ();
+ configDir.mkdirs ();
+ save (applicationName,configFile);
+ } catch (IOException e2) {
+ System.err.println (MessageFormat.format (configSaveException, applicationName));
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException (configUseException);
+ }
+ }
+
+ static public final void save (String applicationName, File file)
+ throws IOException {
+ if (!configurationModified && file.exists ())
+ return;
+ if (!file.exists ())
+ file.createNewFile ();
+ FileOutputStream fileOutputStream = new FileOutputStream (file);
+ configuration.storeToXML (fileOutputStream,
+ (new MessageFormat (configHeaderFile, Locale.US)).format (new Object[] {applicationName, new Date ()},
+ new StringBuffer(), null).toString (),
+ configEncoding);
+ fileOutputStream.close ();
+ configurationModified = false;
+ }
+
+ // ========================================
+
+ // XXX defaultValue peut être placé systématiquement (voir à null)
+ /**
+ Searches for the value with the specified key in this configuration list.
+ @param key the name of the configuration parameter.
+ @return the configuration value associated with the key or null if not found.
+ */
+ static public final String getString (String key) {
+ if (key == null)
+ throw new IllegalArgumentException (configNullKeyException);
+ try {
+ return configuration.getProperty (key);
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException (configUseException);
+ }
+ }
+
+ /**
+ Searches for the value with the specified key in this configuration list.
+ @param key the name of the configuration parameter.
+ @param defaultValue the defaultValue in case the key is not found.
+ @return the configuration value associated with the key or defaultValue if not found.
+ */
+ static public final String getString (String key, String defaultValue) {
+ String value = configuration.getProperty (key);
+ if (value != null)
+ return value;
+ configuration.setProperty (key, defaultValue);
+ return defaultValue;
+ }
+
+ /**
+ Change the value with the specified key in this configuration list.
+ @param key the name of the configuration parameter.
+ @param value the new configuration value associated with the key.
+ */
+ static public final void setString (String key, String value) {
+ try {
+ configuration.setProperty (key, value);
+ configurationModified = true;
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException (configUseException);
+ }
+ }
+
+ // ========================================
+ static public final File getFile (String key) {
+ String fileName = getString (key);
+ if (fileName == null)
+ return null;
+ return new File (fileName);
+ }
+
+ static public final void setFile (String key, File file) {
+ setString (key, file.getPath ());
+ }
+
+ // ========================================
+ static public final boolean getBoolean (String key) {
+ return Boolean.parseBoolean (getString (key));
+ }
+
+ static public final boolean getBoolean (String key, boolean defaultValue) {
+ return Boolean.parseBoolean (getString (key, ""+defaultValue));
+ }
+
+ static public final void setBoolean (String key, boolean value) {
+ setString (key, ""+value);
+ }
+
+ // ========================================
+ static public final int getInt (String key) {
+ return Integer.parseInt (getString (key));
+ }
+
+ static public final int getInt (String key, int defaultValue) {
+ try {
+ return Integer.parseInt (getString (key, ""+defaultValue));
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ static public final void setInt (String key, int value) {
+ setString (key, ""+value);
+ }
+
+ // ========================================
+ static public final float getFloat (String key) {
+ return Float.parseFloat (getString (key));
+ }
+
+ static public final float getFloat (String key, float defaultValue) {
+ try {
+ return Float.parseFloat (getString (key, ""+defaultValue));
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ static public final void setFloat (String key, float value) {
+ setString (key, ""+value);
+ }
+
+ // ========================================
+ static public final double getDouble (String key) {
+ return Double.parseDouble (getString (key));
+ }
+
+ static public final double getDouble (String key, double defaultValue) {
+ try {
+ return Double.parseDouble (getString (key, ""+defaultValue));
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ static public final void setDouble (String key, double value) {
+ setString (key, ""+value);
+ }
+
+ // ========================================
+ static public final T getEnum (String key, T defaultValue) {
+ return Util.toEnum (getString (key, ""+defaultValue), defaultValue);
+ }
+
+ // ========================================
+ static public final DecimalFormat indexFormat = new DecimalFormat ("-0000");
+
+ static public final Vector getList (String key, String defaultValue) {
+ Vector result = new Vector ();
+ int size = Integer.parseInt (getString (key+"-size", "1"));
+ result.add (getString (key, defaultValue));
+ for (int i = 1; i < size; i++)
+ result.add (getString (key+indexFormat.format (i)));
+ return result;
+ }
+
+ static public final void setList (String key, Vector value) {
+ // XXX suppression des anciennes valeurs
+ int size = value.size ();
+ int max = Integer.parseInt (getString (key+"-max", "10"));
+ setString (key+"-max", ""+max);
+ setString (key+"-size", ""+size);
+ setString (key, value.elementAt (0));
+ size = Math.min (size, max);
+ for (int i = 1; i < size; i++)
+ setString (key+indexFormat.format (i), value.elementAt (i));
+ }
+
+ // ========================================
+ // XXX faire un defaultValue en vector
+ static public final void loadJList (String key, JList jList, String defaultValue) {
+ Vector list = getList (key, defaultValue);
+ jList.setListData (list);
+ jList.setSelectedIndex (0);
+ }
+
+ static public final void saveJList (String key, JList jList) {
+ Vector result = new Vector ();
+ ListModel model = jList.getModel ();
+ int size = model.getSize ();
+ for (int i = 0; i < size; i++)
+ result.add (model.getElementAt (i));
+ int index = jList.getSelectedIndex ();
+ if (index >= 0) {
+ result.insertElementAt (result.remove (index), 0);
+ jList.setListData (result);
+ jList.setSelectedIndex (0);
+ }
+ setList (key, result);
+ }
+
+ // ========================================
+ // XXX faire un defaultValue en vector
+ static public final void loadJComboBox (String key, JComboBox jComboBox, String defaultValue) {
+ Vector list = getList (key, defaultValue);
+ jComboBox.removeAllItems ();
+ for (int i = 0; i < list.size (); i++)
+ jComboBox.addItem (list.elementAt (i));
+ jComboBox.setSelectedIndex (0);
+ }
+
+ static public final void loadJComboBoxInteger (String key, JComboBox jComboBox, String defaultValue) {
+ Vector list = getList (key, defaultValue);
+ jComboBox.removeAllItems ();
+ for (int i = 0; i < list.size (); i++) {
+ try {
+ jComboBox.addItem (Integer.parseInt (list.elementAt (i)));
+ } catch (Exception e) {
+ }
+ }
+ jComboBox.setSelectedIndex (0);
+ }
+
+ static public final void saveJComboBox (String key, JComboBox jComboBox) {
+ // XX peut être ajouter la valeur éditer dans la liste
+ Vector result = new Vector ();
+ int size = jComboBox.getItemCount ();
+ for (int i = 0; i < size; i++)
+ result.add (jComboBox.getItemAt (i));
+ int index = jComboBox.getSelectedIndex ();
+ if (index < 0)
+ result.insertElementAt ((String) jComboBox.getSelectedItem (), 0);
+ else
+ result.insertElementAt (result.remove (index), 0);
+ if (index != 0) {
+ jComboBox.removeAllItems ();
+ for (int i = 0; i < result.size (); i++)
+ jComboBox.addItem (result.elementAt (i));
+ jComboBox.setSelectedIndex (0);
+ }
+ setList (key, result);
+ }
+
+ static public final void saveJComboBoxInteger (String key, JComboBox jComboBox) {
+ // XX peut être ajouter la valeur éditer dans la liste
+ Vector result = new Vector ();
+ int size = jComboBox.getItemCount ();
+ for (int i = 0; i < size; i++)
+ result.add (""+jComboBox.getItemAt (i));
+ int index = jComboBox.getSelectedIndex ();
+ if (index < 0)
+ result.insertElementAt ((String) jComboBox.getSelectedItem (), 0);
+ else
+ result.insertElementAt (result.remove (index), 0);
+ setList (key, result);
+ }
+
+ // ========================================
+ /** Text format used to represent coordonates (i.e. [x=123,y=456] ). */
+ static public final MessageFormat coordonateFormat = new MessageFormat ("[x={0,number,integer},y={1,number,integer}]");
+
+ /**
+ Set component location from a constant coordonates in configuration.
+ @param key the name used to denoted the contant.
+ @param component modified by the coordonates retreived in configuration.
+ @param defaultLocation default coordonates used if non key present.
+ */
+ static public final void loadLocation (String key, Component component, Point defaultLocation) {
+ try {
+ Object [] location = coordonateFormat.parse (getString (key+locationPostfix),
+ new java.text.ParsePosition (0));
+ component.setLocation (((Number) location [0]).intValue (), ((Number) location [1]).intValue ());
+ } catch (Exception e) {
+ component.setLocation (defaultLocation);
+ }
+ }
+
+ /**
+ Save constant coordonates to configuration form a component location.
+ @param key the name used to denoted the contant.
+ @param component used to set the contant coordonates value.
+ */
+ static public final void saveLocation (String key, Component component) {
+ Point location = component.getLocation ();
+ setString (key+locationPostfix,
+ coordonateFormat.format (new Object [] {location.x, location.y},
+ new StringBuffer(), null).toString ());
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/Controller.java b/src/java/misc/Controller.java
new file mode 100644
index 0000000..15b4c31
--- /dev/null
+++ b/src/java/misc/Controller.java
@@ -0,0 +1,216 @@
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.swing.AbstractButton;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+public abstract class Controller implements ApplicationManager, OwnFrame, ActionListener {
+
+ // ========================================
+ // remplace
+ // a placer avant la création de socket (y compris celle pour X11 faite par swing)
+ static {
+ java.util.Properties props = System.getProperties ();
+ props.setProperty ("java.net.preferIPv4Stack", ""+true);
+ System.setProperties (props);
+ }
+
+ // ========================================
+ static public final List actionsNames = Arrays.asList ("Quit");
+ @SuppressWarnings("unchecked")
+ static public final Hashtable actionsMethod = Util.collectMethod (Controller.class, actionsNames);
+
+ public void actionPerformed (ActionEvent e) {
+ Util.actionPerformed (actionsMethod, e, this);
+ }
+
+ // ========================================
+ protected JFrame jFrame;
+ protected Component component;
+ protected JMenuBar menuBar;
+ public JFrame getJFrame () { return jFrame; }
+
+ // ========================================
+ public Controller (T t) {
+ createModel (t);
+ createAndShowFrame (createGUI (), createMenuBar ());
+ Plugins.hideSate ();
+ }
+
+ // ========================================
+ // XXX ATTENTION
+ // createModel est appelé avant la création des attribut pas le constructer de "super"
+ // les attrubuts ne doivent donc pas être initialisé durant leur déclaration
+ protected abstract void createModel (T t);
+ public abstract String getTitle ();
+ public abstract Image getIcon ();
+
+ public void updateBundle () {
+ SwingUtilities.invokeLater (new Runnable () {
+ public void run () {
+ jFrame.setTitle (getTitle ());
+ }
+ });
+ }
+
+ // ========================================
+ public void reborn () {
+ // XXX on pert les boites de dialog attachées à l'ancienne fenêtre
+ jFrame.dispose ();
+ jFrame.setJMenuBar (null);
+ jFrame.getContentPane ().remove (component);
+ createAndShowFrame (component, menuBar);
+ }
+
+ // ========================================
+ protected void createAndShowFrame (final Component component, final JMenuBar menuBar) {
+ final JFrame newJFrame = new JFrame (getTitle ());
+ newJFrame.setIconImage (getIcon ());
+ newJFrame.setJMenuBar (menuBar);
+ newJFrame.getContentPane ().add (component, BorderLayout.CENTER);
+ newJFrame.pack ();
+ newJFrame.addWindowListener (new WindowAdapter () {
+ public void windowClosing (WindowEvent e) {
+ Config.saveLocation ("Frame", jFrame);
+ if (tryClosingWindows ())
+ quit ();
+ else
+ reborn ();
+ }
+ });
+ if (jFrame == null) {
+ newJFrame.setLocationRelativeTo (null);
+ Config.loadLocation ("Frame", newJFrame, newJFrame.getLocation ());
+ } else
+ newJFrame.setLocation (jFrame.getLocation ());
+ jFrame = newJFrame;
+ this.component = component;
+ this.menuBar = menuBar;
+ jFrame.setVisible (true);
+ newJFrame ();
+ }
+
+ // ========================================
+ protected void newJFrame () { }
+
+ // ========================================
+ protected Component createGUI () {
+ Bundle.addBundleObserver (this);
+ return new JLabel ("Empty controller");
+ }
+
+ // ========================================
+ protected JMenuBar createMenuBar () {
+ return null;
+ }
+
+ // ========================================
+ public void quit () {
+ System.exit (0);
+ }
+
+ // ========================================
+ public void actionQuit () {
+ Config.saveLocation ("Frame", jFrame);
+ if (tryClosingWindows ())
+ quit ();
+ }
+
+ // ========================================
+ protected boolean tryClosingWindows () {
+ switch (JOptionPane.showConfirmDialog (jFrame, "Do you want to quit ?", "Quit",
+ JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE)) {
+ case JOptionPane.YES_OPTION:
+ return true;
+ case JOptionPane.NO_OPTION:
+ case JOptionPane.CLOSED_OPTION:
+ return false;
+ }
+ return true;
+ }
+
+ // ========================================
+ public void addMenuItem (JMenu... jMenu) {
+ Util.addMenuItem (actionsNames, this, jMenu[0]);
+ }
+
+ // ========================================
+ public void addIconButtons (Container... containers) {
+ Util.addIconButton (actionsNames, this, containers[0]);
+ }
+
+ // ========================================
+ public void addActiveButtons (Hashtable buttons) {
+ }
+
+ // ========================================
+ static public void main (String[] args) {
+ Config.load ("Misc");
+ Bundle.load ("Help");
+ Bundle.load ("Controller");
+
+ @SuppressWarnings ("serial")
+ class JControllerTestMenu extends JMenuBar {
+ public JControllerTestMenu (ApplicationManager controllerManager, ApplicationManager helpManager) {
+ setLayout (new BoxLayout (this, BoxLayout.X_AXIS));
+ JMenu fileMenu = Util.addJMenu (this, "File");
+ add (Box.createHorizontalGlue ());
+ JMenu helpMenu = Util.addJMenu (this, "Help");
+ controllerManager.addMenuItem (fileMenu);
+ helpManager.addMenuItem (helpMenu);
+ Hashtable buttons = new Hashtable ();
+ Util.collectButtons (buttons, fileMenu);
+ Util.collectButtons (buttons, helpMenu);
+ controllerManager.addActiveButtons (buttons);
+ helpManager.addActiveButtons (buttons);
+ }
+ };
+
+ class ControllerTest extends Controller {
+ public ControllerTest () { super (""); }
+ protected void createModel (String s) {}
+ public String getTitle () { return null; }
+ public Image getIcon () {
+ return Util.loadImageIcon (Config.getString ("MiscIcon",
+ Config.imagesJarDir+"misc"+Config.imagesExt)).getImage ();
+ }
+ protected JMenuBar createMenuBar () {
+ return new JControllerTestMenu (this, new HelpManager (this, "Misc"));
+ }
+ protected Component createGUI () {
+ return new JLabel ("Affichage de la licence.");
+ }
+ protected boolean tryClosingWindows () {
+ Config.save ("Misc");
+ return true;
+ }
+ };
+ SwingUtilities.invokeLater (new Runnable () {
+ public void run () {
+ new ControllerTest ();
+ }
+ });
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/DatePanel.java b/src/java/misc/DatePanel.java
new file mode 100644
index 0000000..f824abc
--- /dev/null
+++ b/src/java/misc/DatePanel.java
@@ -0,0 +1,242 @@
+// ================================================================================
+// Copyright (c) Francois Merciol 2002
+// Project : Classe
+// Name : DatePanel.java
+// Language : Java
+// Type : Source file for DatePanel class
+// Author : Francois Merciol
+// Creation : 02/09/2002
+// ================================================================================
+// History
+// --------------------------------------------------------------------------------
+// Author :
+// Date :
+// Reason :
+// ================================================================================
+// To be improved :
+// ================================================================================
+package misc;
+
+import java.awt.Dimension;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import javax.swing.JTextField;
+
+/**
+ Champ de saisie d'une date au format dd/MM/yyyy.
+ Autres fonctions :
+ (espace) : éfface le champs
+ '+' ou (fleche haut) : incrémente d'un jour
+ '-' ou (fleche bas) : décrémente d'un jour
+ (retoure chariot) ou (perte de "focus") : transforme une date sur deux chiffres en relatif à la date actuelle.
+
+*/
+@SuppressWarnings ("serial") public class DatePanel extends JTextField implements KeyListener, FocusListener {
+
+ // ========================================
+ /** Format d'une date en francais. */
+ static public final SimpleDateFormat dateFormat = new SimpleDateFormat ("dd/MM/yyyy");
+ /** Ensemble des caractères ayant une action sur ce champs.
+ Il faudrais ajouter le retoure chariot et le caractère d'effacement. */
+ static public final String acceptChar = "0123456789/+- "+KeyEvent.VK_UP+KeyEvent.VK_DOWN;
+
+ // ========================================
+ /**
+ Création d'une date en reservant une taille maximal puis mis à la date actuelle.
+ */
+ public DatePanel () {
+ super ("31/12/9999");
+ addKeyListener (this);
+ addFocusListener (this);
+ set (new Date ());
+ }
+
+ // ========================================
+ // api
+ // ========================================
+ /**
+ Interprétation d'une année sur 2 chiffres.
+ */
+ public void enter () {
+ tune2ky ();
+ }
+
+ // ========================================
+ /**
+ Fixe une date.
+ @param date la nouvelle valeur.
+ */
+ public void set (Date date) {
+ setText (dateFormat.format (date));
+ }
+
+ // ========================================
+ // Listener
+ // ========================================
+ /** Interface KeyListener. */
+ public void keyPressed (KeyEvent e) {
+ }
+
+ // ========================================
+ /** Interface KeyListener. */
+ public void keyReleased (KeyEvent e) {
+ int c = e.getKeyCode ();
+ switch (c) {
+ case KeyEvent.VK_UP:
+ incr (1);
+ e.consume ();
+ return;
+ case KeyEvent.VK_DOWN:
+ incr (-1);
+ e.consume ();
+ return;
+ }
+ }
+
+ // ========================================
+ /** Interface KeyListener. */
+ public void keyTyped (KeyEvent e) {
+ char c = e.getKeyChar ();
+
+ switch (c) {
+ case KeyEvent.VK_ENTER:
+ enter ();
+ return;
+ case ';':
+ // le ; sera s�parateur
+ e.consume ();
+ return;
+ case KeyEvent.VK_BACK_SPACE:
+ // on laisse java faire
+ return;
+ case KeyEvent.VK_SPACE:
+ setText ("");
+ e.consume ();
+ return;
+ case '+':
+ incr (1);
+ e.consume ();
+ return;
+ case '-':
+ incr (-1);
+ e.consume ();
+ return;
+ }
+
+ if (acceptChar.indexOf (c) < 0) {
+ e.consume ();
+ return;
+ }
+
+ if (getSelectedText () == null && getText ().length () >= 12) {
+ e.consume ();
+ return;
+ }
+ }
+
+ // ========================================
+ /** Interface FocusListener. */
+ public void focusGained (FocusEvent e) {
+ }
+
+ // ========================================
+ /** Interface FocusListener. */
+ public void focusLost (FocusEvent e) {
+ tune2ky ();
+ }
+
+ // ========================================
+ // Listener spécial
+ // ========================================
+ /**
+ Interprétation d'une année sur 2 chiffre.
+ */
+ public void tune2ky () {
+ try {
+ Date origDate = dateFormat.parse (getText ().trim ());
+ GregorianCalendar cal = new GregorianCalendar ();
+ cal.setTime (origDate);
+ int y = cal.get (Calendar.YEAR);
+ if (y < 100) {
+ cal.add (Calendar.YEAR, cur2ky);
+ if (y < min2ky)
+ cal.add (Calendar.YEAR, 100);
+ else if (y > max2ky)
+ cal.add (Calendar.YEAR, -100);
+ }
+ setText (dateFormat.format (cal.getTime ()));
+ getSize (tmpSize);
+ if (tmpSize.width != 0)
+ size = tmpSize;
+ } catch (Exception ex) {
+ }
+ }
+
+ // ========================================
+ /** Taille actuelle du champ. */
+ private Dimension tmpSize = new Dimension ();
+ /** Derniére taille maximum utilisée. */
+ private Dimension size;
+
+ // ========================================
+ /**
+ @return la taille maximum déjà utilisé.
+ */
+ public Dimension getPreferredSize () {
+ if (size != null)
+ return size;
+ return super.getPreferredSize ();
+ }
+
+ // ========================================
+ /**
+ @return la taille maximum déjà utilisé.
+ */
+ public Dimension getMinimumSize () {
+ if (size != null)
+ return size;
+ return super.getPreferredSize ();
+ }
+
+ // ========================================
+ /**
+ Change la date d'une certain nombre de jours.
+ @param incr le nombre de jour à avancer (diminuer si négatif).
+ */
+ public void incr (int incr) {
+ try {
+ tune2ky ();
+ Date origDate = dateFormat.parse (getText ().trim ());
+ GregorianCalendar cal = new GregorianCalendar ();
+ cal.setTime (origDate);
+ cal.add (Calendar.DATE, incr);
+ setText (dateFormat.format (cal.getTime ()));
+ } catch (Exception ex) {
+ }
+ }
+
+ // ========================================
+ // valeurs d'une année sur 2 chiffres
+ // ========================================
+ /** XXX commentaire sur l'optimisation d'une année sur 2 chiffre. */
+ static public int min2ky, max2ky, cur2ky;
+
+ /** Initialisation des champs. */
+ static {
+ GregorianCalendar cal = new GregorianCalendar ();
+ cal.setTime (new Date ());
+ int y = cal.get(Calendar.YEAR);
+ int yMod1ky = y % 100;
+ min2ky = yMod1ky - 50;
+ max2ky = yMod1ky + 50;
+ cur2ky = y - yMod1ky;
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/DimensionDouble.java b/src/java/misc/DimensionDouble.java
new file mode 100644
index 0000000..58379bf
--- /dev/null
+++ b/src/java/misc/DimensionDouble.java
@@ -0,0 +1,62 @@
+// ================================================================================
+// François MERCIOL 2015
+// Name : Dimension2D.java
+// Language : Java
+// Author : François Merciol
+// CopyLeft : Cecil B
+// Creation : 2015
+// Version : 0.1 (xx/xx/xx)
+// ================================================================================
+package misc;
+
+import java.awt.geom.Dimension2D;
+
+@SuppressWarnings ("overrides")
+public class DimensionDouble extends Dimension2D {
+
+ // ========================================
+ public double width, height;
+
+ public DimensionDouble () {
+ }
+
+ public DimensionDouble (double width, double height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ public boolean equals (Object obj) {
+ try {
+ DimensionDouble dim = (DimensionDouble) obj;
+ return width == dim.width && height == dim.height;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ // ========================================
+ public double getHeight () {
+ return height;
+ }
+
+ public double getWidth () {
+ return width;
+ }
+
+ public void setSize (Dimension2D d) {
+ width = d.getWidth ();
+ height = d.getHeight ();
+ }
+
+ public void setSize (double width, double height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ // ========================================
+ public String toString () {
+ return DimensionDouble.class.getSimpleName ()+"[width="+width+",height="+height+"]";
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/EasterEgg.java b/src/java/misc/EasterEgg.java
new file mode 100644
index 0000000..65aadb6
--- /dev/null
+++ b/src/java/misc/EasterEgg.java
@@ -0,0 +1,53 @@
+package misc;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+public class EasterEgg {
+ public static final SimpleDateFormat birthFormat = new SimpleDateFormat("MMdd");
+
+ String defaultValue;
+
+ class Periode {
+ String start;
+
+ String stop;
+
+ String value;
+
+ Periode(String start, String stop, String value) {
+ this.start = start;
+ this.stop = stop;
+ this.value = value;
+ }
+ }
+
+ ArrayList periodes = new ArrayList<>();
+
+ public EasterEgg(String defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public void addPeriode(String start, String stop, String value) {
+ this.periodes.add(new Periode(start, stop, value));
+ }
+
+ public String getValue() {
+ return get(new Date());
+ }
+
+ public String get(Date date) {
+ String day = birthFormat.format(date);
+ for (Periode periode : this.periodes) {
+ if (periode.start.compareTo(periode.stop) <= 0) {
+ if (day.compareTo(periode.start) >= 0 && day.compareTo(periode.stop) <= 0)
+ return periode.value;
+ continue;
+ }
+ if (day.compareTo(periode.start) <= 0 || day.compareTo(periode.stop) >= 0)
+ return periode.value;
+ }
+ return this.defaultValue;
+ }
+}
diff --git a/src/java/misc/Guide.java b/src/java/misc/Guide.java
new file mode 100644
index 0000000..70092ac
--- /dev/null
+++ b/src/java/misc/Guide.java
@@ -0,0 +1,208 @@
+package misc;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Frame;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLFrameHyperlinkEvent;
+
+@SuppressWarnings ("serial") public class Guide extends HtmlDialog {
+
+ // ========================================
+ static public final int H_SPACE = 5;
+ static public final int V_SPACE = 2;
+
+ // ========================================
+ Color standardBackground = Color.gray;
+ Color highlightColor = Color.orange;
+ Component [] component;
+ Color [] componentBackgroundColor;
+ int next = -1;
+ boolean [] done;
+
+ // ========================================
+ public Guide (Frame frame, String titleName, String fileName, Component [] component,
+ Color standardBackground, Color highlightColor) {
+ super (frame, titleName, fileName);
+ this.component = component;
+ this.standardBackground = standardBackground;
+ this.highlightColor = highlightColor;
+ done = new boolean [component.length];
+ componentBackgroundColor = new Color [component.length];
+ for (int i = 0; i < component.length; i++)
+ if (component [i] != null)
+ componentBackgroundColor [i] = component [i].getBackground ();
+ reset ();
+ editorPane.addHyperlinkListener (new Hyperactive ());
+ }
+
+ // ========================================
+ class Hyperactive implements HyperlinkListener {
+
+ public void hyperlinkUpdate (HyperlinkEvent e) {
+ if (e.getEventType () == HyperlinkEvent.EventType.ACTIVATED) {
+ String file = e.getURL ().getPath ();
+ String command = file.substring (file.lastIndexOf ("/")+1);
+ int idx = command.indexOf ("?");
+ if (idx >= 0)
+ command = command.substring (0, idx);
+ if ("Reset".equals (command)) {
+ reset ();
+ setNext ();
+ } else if (command.startsWith ("ActionG")) {
+ String [] bound = command.substring ("ActionG".length ()).split ("\\-");
+ flipGroup (Integer.parseInt (bound[0]), Integer.parseInt (bound[1]));
+ } else if (command.startsWith ("Action"))
+ flipStep (Integer.parseInt (command.substring ("Action".length ())));
+ else if (e instanceof HTMLFrameHyperlinkEvent) {
+ HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
+ HTMLDocument doc = (HTMLDocument) editorPane.getDocument ();
+ doc.processHTMLFrameHyperlinkEvent (evt);
+ } else {
+ try {
+ editorPane.setPage (e.getURL ());
+ } catch (Throwable t) {
+ Log.keepLastException ("Guide::hyperlinkUpdate", t);
+ }
+ }
+ }
+ }
+ }
+
+ // ========================================
+ public void setVisible (boolean visible) {
+ reset ();
+ super.setVisible (visible);
+ if (visible) {
+ setNext ();
+ editorPane.scrollToReference ("Top");
+ }
+ }
+
+ // ========================================
+ public void changeHtmlClassAction (String actionName, String className) {
+ String newPage = editorPane.getText ().
+ replaceAll ("]*name=\"Action("+actionName+")\"[^>]*>",
+ "
").
+ replaceAll ("
]*name=\"Action("+actionName+")\"[^>]*>",
+ "
");
+ editorPane.setText (newPage);
+ }
+
+ // ========================================
+ public void reset () {
+ next = -1;
+ if (done == null)
+ return;
+ for (int step = 0; step < done.length; step++) {
+ done [step] = false;
+ if (component [step] != null)
+ component [step].setBackground (componentBackgroundColor [step]);
+ }
+ // XXX pb d'affichage
+ editorPane.getText ();
+ try {
+ Thread.sleep (200);
+ } catch (InterruptedException e) {
+ }
+ changeHtmlClassAction ("(G[0-9]+-)?[0-9]+", "Unknown");
+ editorPane.scrollToReference ("Top");
+ }
+
+ // ========================================
+ public void unsetNext () {
+ if (next < 0)
+ return;
+ changeHtmlClassAction (""+next, "Unknown");
+ if (component [next] != null)
+ component [next].setBackground (componentBackgroundColor [next]);
+ next = -1;
+ }
+
+ // ========================================
+ public void setNext () {
+ if (next >= 0 && ! done [next])
+ return;
+ next = -1;
+ for (int step = 0; step < done.length; step++)
+ if (!done [step]) {
+ next = step;
+ changeHtmlClassAction (""+next, "Todo");
+ if (component [next] != null)
+ component [next].setBackground (highlightColor);
+ editorPane.scrollToReference ("Action"+next);
+ return;
+ }
+ }
+
+ // ========================================
+ private void stepIsDone (int step) {
+ done [step] = true;
+ changeHtmlClassAction (""+step, "Done");
+ if (component [step] != null)
+ component [step].setBackground (componentBackgroundColor [step]);
+ }
+
+ // ========================================
+ private void stepIsUnknown (int step) {
+ done [step] = false;
+ changeHtmlClassAction (""+step, "Unknown");
+ }
+
+ // ========================================
+ public void flipStep (int step) {
+ unsetNext ();
+ if (done [step])
+ stepIsUnknown (step);
+ else
+ stepIsDone (step);
+ checkGroup ();
+ setNext ();
+ }
+
+ // ========================================
+ public void flipGroup (int step1, int step2) {
+ unsetNext ();
+ boolean allDone = true;
+ for (int step = step1; step <= step2; step++)
+ if (!done [step]) {
+ allDone = false;
+ break;
+ }
+ if (allDone) {
+ for (int step = step1; step <= step2; step++)
+ stepIsUnknown (step);
+ changeHtmlClassAction ("G"+step1+"-"+step2, "Unknown");
+ } else {
+ for (int step = step1; step <= step2; step++)
+ stepIsDone (step);
+ changeHtmlClassAction ("G"+step1+"-"+step2, "Done");
+ }
+ checkGroup ();
+ setNext ();
+ }
+
+ // ========================================
+ public void checkGroup () {
+ String newPage = editorPane.getText ();
+ Pattern pattern = Pattern.compile ("
]*name=\"ActionG(([0-9]+)-([0-9]+))\"[^>]*>");
+ Matcher matcher = pattern.matcher (newPage);
+ while (matcher.find()) {
+ int step1 = Integer.parseInt (matcher.group (2));
+ int step2 = Integer.parseInt (matcher.group (3));
+ boolean allDone = true;
+ for (int step = step1; step <= step2; step++)
+ if (!done [step]) {
+ allDone = false;
+ break;
+ }
+ changeHtmlClassAction ("G"+step1+"-"+step2, allDone ? "Done" : "Unknown");
+ }
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/HelpManager.java b/src/java/misc/HelpManager.java
new file mode 100644
index 0000000..889b8d1
--- /dev/null
+++ b/src/java/misc/HelpManager.java
@@ -0,0 +1,197 @@
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Vector;
+import javax.swing.AbstractButton;
+import javax.swing.ImageIcon;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import misc.Bundle;
+import misc.Log;
+import misc.Util;
+
+/**
+ Les drapeaux peuvent être trouvé sur http://flags.blogpotato.de/
+*/
+@SuppressWarnings ("serial") public class HelpManager implements ApplicationManager, ActionListener {
+
+ // ========================================
+ private Frame frame;
+ private OwnFrame controller;
+ private String applicationName;
+ private JConsole jConsole;
+
+ // ========================================
+ static public final String
+ //actionPackBug = "PackBug",
+ actionForcePack = "ForcePack",
+ actionBugReport = "BugReport",
+ actionJConsole = "JConsole";
+
+ static public final List
actionsNames =
+ Arrays.asList ("About", "Licence", "Locale");
+ static public final List actionsBugNames =
+ Arrays.asList (/*actionPackBug, */actionForcePack, actionBugReport, actionJConsole);
+ @SuppressWarnings("unchecked")
+ static public final Hashtable actionsMethod =
+ Util.collectMethod (HelpManager.class, actionsNames, actionsBugNames);
+
+ public void actionPerformed (ActionEvent e) {
+ Util.actionPerformed (actionsMethod, e, this);
+ }
+
+ // ========================================
+ public HelpManager (OwnFrame controller, String applicationName) {
+ this.controller = controller;
+ this.applicationName = applicationName;
+ frame = new Frame ();
+ frame.setIconImage (controller.getIcon ());
+ aboutDialog = new HtmlDialog (frame, "About", Config.textsJarDir+"About"+applicationName+Config.htmlExt);
+ licenceDialog = new HtmlDialog (frame, "Licence", Config.textsJarDir+applicationName+"Licence"+Config.htmlExt);
+ jConsole = new JConsole (frame);
+ //Util.packBug = Config.getBoolean (actionPackBug+Config.checkedPostfix, false);
+ }
+
+ // ========================================
+ private HtmlDialog aboutDialog;
+ private HtmlDialog licenceDialog;
+
+ // ========================================
+ public void actionAbout () {
+ aboutDialog.restart ();
+ aboutDialog.setVisible (true);
+ }
+
+ // ========================================
+ public void actionLicence () {
+ licenceDialog.restart ();
+ licenceDialog.setVisible (true);
+ }
+
+ // ========================================
+ public void actionLocale () {
+ actionLocale (controller);
+ }
+
+ static public void actionLocale (OwnFrame controller) {
+ try {
+ Locale [] locales = Bundle.getApplicationsLocales ();
+ JComboBox localesList = Bundle.getJComboFlags (locales);
+ Locale currentLocale = Bundle.getLocale ();
+ int currentIndex = 0;
+ if (currentLocale != null)
+ for (int i = 0; i < locales.length; i++)
+ if (currentLocale.equals (locales[i])) {
+ currentIndex = i;
+ break;
+ }
+ localesList.setSelectedIndex (currentIndex);
+ JPanel jPanel = new JPanel (new BorderLayout ());
+ jPanel.add (new JLabel (Bundle.getMessage ("ChooseLocale")), BorderLayout.PAGE_START);
+ jPanel.add (localesList, BorderLayout.CENTER);
+
+ Frame frame = controller != null ? controller.getJFrame () : null;
+ Frame frmOpt = null;
+ if (frame == null) {
+ frmOpt = new JFrame ();
+ frmOpt.setVisible (true);
+ frmOpt.setLocationRelativeTo (null);
+ frmOpt.setAlwaysOnTop (true);
+ frame = frmOpt;
+ }
+ try {
+ if (JOptionPane.OK_OPTION !=
+ JOptionPane.showConfirmDialog (frame, jPanel, Bundle.getTitle ("ChangeLocale"),
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE))
+ return;
+ } finally {
+ if (frmOpt != null)
+ frmOpt.dispose();
+ }
+ Bundle.setLocale (locales[localesList.getSelectedIndex ()]);
+ Util.packWindow (frame);
+ } catch (Exception e) {
+ Log.keepLastException ("HelpManager::actionLocale", e);
+ }
+ }
+
+ // // ========================================
+ // public void actionPackBug () {
+ // Util.packBug = ! Util.packBug;
+ // Config.setBoolean (actionPackBug+Config.checkedPostfix, Util.packBug);
+ // ImageIcon icon = Util.loadActionIcon (actionPackBug+(Util.packBug ? "On" : "Off"));
+ // for (AbstractButton packBugCommand : packBugCommands) {
+ // packBugCommand<.setSelected (Util.packBug);
+ // // XXX bug Java
+ // packBugCommand.setIcon (icon);
+ // }
+ // }
+
+ // ========================================
+ public void actionForcePack () {
+ controller.reborn ();
+ }
+
+ // ========================================
+ public void actionBugReport () {
+ Log.dumpSaveDialog (controller.getJFrame ());
+ }
+
+ // ========================================
+ public void actionJConsole (boolean checked) {
+ jConsole.setVisible (checked);
+ Util.updateCheckBox (actionJConsole, checked);
+ }
+
+ // ========================================
+ // static private Vector packBugCommands = new Vector ();
+ // static public void addPackBugCommand (AbstractButton packBugCommand) {
+ // if (packBugCommand == null)
+ // return;
+ // packBugCommands.add (packBugCommand);
+ // packBugCommand.setSelected (Util.packBug);
+ // // XXX bug Java
+ // packBugCommand.setIcon (Util.loadActionIcon (actionPackBug+(Util.packBug ? "On" : "Off")));
+ // }
+ // static public void removePackBugCommand (AbstractButton packBugCommand) {
+ // packBugCommands.remove (packBugCommand);
+ // }
+
+ // ========================================
+ public void addMenuItem (JMenu... jMenu) {
+ Util.addMenuItem (actionsNames, this, jMenu[0]);
+ //Util.addCheckMenuItem (actionPackBug, this, Util.packBug, jMenu[0]);
+ Util.addMenuItem (actionForcePack, this, jMenu[0]);
+ Util.addMenuItem (actionBugReport, this, jMenu[0]);
+ Util.addCheckMenuItem (actionJConsole, this, jMenu[0]);
+ }
+
+ // ========================================
+ public void addIconButtons (Container... containers) {
+ Util.addIconButton (actionsNames, this, containers[0]);
+ //Util.addIconButton (actionPackBug, this, containers[0]);
+ Util.addIconButton (actionForcePack, this, containers[0]);
+ Util.addIconButton (actionBugReport, this, containers[0]);
+ }
+
+ // ========================================
+ public void addActiveButtons (Hashtable buttons) {
+ //addPackBugCommand (buttons.get (actionPackBug));
+ Log.addDumpCommand (buttons.get (actionBugReport));
+ }
+ // ========================================
+}
diff --git a/src/java/misc/HourPanel.java b/src/java/misc/HourPanel.java
new file mode 100644
index 0000000..8d37920
--- /dev/null
+++ b/src/java/misc/HourPanel.java
@@ -0,0 +1,253 @@
+// ================================================================================
+// Copyright (c) Francois Merciol 2002
+// Project : Perso
+// Name : HourPanel.java
+// Language : Java
+// Type : Source file for HourPanel class
+// Author : Francois Merciol
+// Creation : 02/09/2002
+// ================================================================================
+// History
+// --------------------------------------------------------------------------------
+// Author :
+// Date :
+// Reason :
+// ================================================================================
+// To be improved :
+// ================================================================================
+package misc;
+
+import java.awt.Dimension;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import javax.swing.JTextField;
+
+/**
+ Champ de saisie d'une heure au format HH:mm.
+ Autres fonctions :
+ (espace) : éfface le champs
+ (retoure chariot) ou (perte de "focus") : remet le champ au format.
+ Le premier caractère frappé éfface le champs. Des caractères peuvent être concervé si le prmier caractère
+ concerne un déplacement ou un éffacement.
+
+*/
+@SuppressWarnings ("serial") public class HourPanel extends JTextField implements KeyListener, FocusListener {
+
+ // ========================================
+ /** Format d'une heure. */
+ static public final SimpleDateFormat hourFormat = new SimpleDateFormat ("HH:mm");
+ /** Ensemble des caractères ayant une action sur ce champs.
+ Il faudrais ajouter le retoure chariot et le caractère d'effacement. */
+ static public final String acceptChar = "0123456789: ";
+
+ // ========================================
+ /** mémorise si le caractère frappé et le premier dans le champs. */
+ private boolean justFocus = false;
+
+ // ========================================
+ /**
+ Création d'une date en reservant une taille maximal puis mis à la date actuelle.
+ */
+ public HourPanel () {
+ super ("23:59");
+ addKeyListener (this);
+ addFocusListener (this);
+ set (new Date ());
+ }
+
+ // ========================================
+ // api
+ // ========================================
+ /**
+ Remet en forme le champs.
+ */
+ public void enter () {
+ tuneHour ();
+ }
+
+ // ========================================
+ /**
+ Fixe une heure.
+ @param date la nouvelle valeur.
+ */
+ public void set (Date date) {
+ setText (hourFormat.format (date));
+ }
+
+ // ========================================
+ // Listener
+ // ========================================
+ /** Dernière possition du curseur. */
+ int lastJTextPos = -1;
+
+ // ========================================
+ /** Interface KeyListener. */
+ public void keyPressed (KeyEvent e) {
+ lastJTextPos = getCaretPosition ();
+ }
+
+ // ========================================
+ /** Interface KeyListener. */
+ public void keyReleased (KeyEvent e) {
+ }
+
+ // ========================================
+ /** Interface KeyListener. */
+ public void keyTyped (KeyEvent e) {
+ char c = e.getKeyChar ();
+
+ switch (c) {
+ case KeyEvent.VK_ENTER:
+ enter ();
+ return;
+ case ';':
+ // le ; sera s�parateur
+ e.consume ();
+ return;
+ case KeyEvent.VK_BACK_SPACE:
+ // on laisse java faire
+ justFocus = false;
+ return;
+ case KeyEvent.VK_SPACE:
+ setText ("");
+ e.consume ();
+ return;
+ }
+
+ if (acceptChar.indexOf (c) < 0) {
+ e.consume ();
+ return;
+ }
+
+ if (getSelectedText () == null) {
+ if (justFocus)
+ setText ("");
+ if (c != ':' && getText ().length () >= 5) {
+ e.consume ();
+ return;
+ }
+ } else {
+ String text = getText ();
+ lastJTextPos = getSelectionStart ();
+ setText (text.substring (0, getSelectionStart ())+ text.substring (getSelectionEnd ()));
+ }
+ justFocus = false;
+ processHour (e);
+ }
+
+ // ========================================
+ /** Interface FocusListener. */
+ public void focusGained (FocusEvent e) {
+ justFocus = true;
+ }
+
+ // ========================================
+ /** Interface FocusListener. */
+ public void focusLost (FocusEvent e) {
+ justFocus = false;
+ tuneHour ();
+ }
+
+ // ========================================
+ // Listener spécial
+ // ========================================
+ /**
+ Traite l'insertion d'un caractère dur champ (chiffre ou ':').
+ @param e touche frappé au clavier.
+ */
+ public void processHour (KeyEvent e) {
+ char c = e.getKeyChar ();
+ String text = getText ();
+ int dpPos = text.indexOf (":");
+ if (dpPos >= 0) {
+ if (c == ':') {
+ if (lastJTextPos <= dpPos)
+ setText (((lastJTextPos == 0) ? "0" : text.substring (0, lastJTextPos))+":"+
+ text.substring (dpPos+1));
+ else
+ setText (text.substring (0, dpPos)+":"+text.substring (lastJTextPos));
+ setCaretPosition (text.indexOf (":")+1);
+ e.consume ();
+ return;
+ }
+ } else {
+ if (c == ':')
+ return;
+ // traiter l'apparition du :
+ if (text.length () < 1)
+ return;
+ if (text.charAt (0) > '2') {
+ // XXX pb si lastJTextPos = 0
+ setText (text.charAt (0)+":"+text.substring (1));
+ setCaretPosition (lastJTextPos+1);
+ return;
+ }
+ if (text.length () > 1) {
+ // XXX pb si lastJTextPos < 2
+ setText (text.substring (0, 2)+":"+text.substring (2));
+ setCaretPosition (lastJTextPos+1);
+ return;
+ }
+ }
+ }
+
+ // ========================================
+ /**
+ Remise en forme de l'heure.
+ */
+ public void tuneHour () {
+ try {
+ String text = getText ().trim ();
+ if (text.isEmpty ()) {
+ setText ("00:00");
+ return;
+ }
+ switch (text.indexOf (":")) {
+ case -1:
+ text += ":0";
+ break;
+ case 0:
+ text = "0"+text;
+ }
+ if (text.indexOf (":") == (text.length ()-1))
+ text += "0";
+ setText (hourFormat.format (hourFormat.parse (text)));
+ getSize (tmpSize);
+ if (tmpSize.width != 0)
+ size = tmpSize;
+ } catch (Exception ex) {
+ }
+ }
+
+ // ========================================
+ /** Taille actuelle du champ. */
+ private Dimension tmpSize = new Dimension ();
+ /** Derni�re taille maximum utilisée. */
+ private Dimension size;
+
+ // ========================================
+ /**
+ @return la taille maximum déjà utilisé.
+ */
+ public Dimension getPreferredSize () {
+ if (size != null)
+ return size;
+ return super.getPreferredSize ();
+ }
+
+ // ========================================
+ /**
+ @return la taille maximum déjà utilisé.
+ */
+ public Dimension getMinimumSize () {
+ if (size != null)
+ return size;
+ return super.getPreferredSize ();
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/HtmlDialog.java b/src/java/misc/HtmlDialog.java
new file mode 100644
index 0000000..f9fe778
--- /dev/null
+++ b/src/java/misc/HtmlDialog.java
@@ -0,0 +1,85 @@
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.io.IOException;
+import java.net.URL;
+import java.text.MessageFormat;
+import javax.swing.BorderFactory;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLFrameHyperlinkEvent;
+
+// XXX rechercher le fichier à afficher en fonction de la langue
+// XXX mise à jour dynamique en cas de changement de langue
+
+@SuppressWarnings ("serial") public class HtmlDialog extends TitledDialog {
+
+ // ========================================
+ public JEditorPane editorPane;
+
+ protected URL startedURL;
+
+ // ========================================
+ public HtmlDialog (Frame frame, String titleName, String fileName) {
+ super (frame, titleName);
+ editorPane = new JEditorPane ();
+ changeFileName (fileName);
+ editorPane.setBackground (getBackground ());
+ editorPane.setBorder (BorderFactory.createCompoundBorder (BorderFactory.createRaisedBevelBorder (),
+ BorderFactory.createEmptyBorder (2, 5, 2, 5)));
+ editorPane.setEditable (false);
+ editorPane.setCaretPosition (0);
+ editorPane.scrollToReference ("Top");
+ JScrollPane editorScrollPane = new JScrollPane (editorPane);
+ editorScrollPane.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ editorScrollPane.setPreferredSize (new Dimension (600, 300));
+ getContentPane ().add (editorScrollPane, BorderLayout.CENTER);
+ }
+
+ // ========================================
+ public void changeFileName (String fileName) {
+ try {
+ URL newURL = Config.getDataUrl (fileName);
+ if (newURL.equals (startedURL))
+ return;
+ startedURL = newURL;
+ restart ();
+ } catch (Exception e) {
+ }
+ }
+
+ // ========================================
+ HyperlinkListener hyperlinkListener = new HyperlinkListener () {
+ public void hyperlinkUpdate (HyperlinkEvent e) {
+ if (e.getEventType () == HyperlinkEvent.EventType.ACTIVATED) {
+ if (e instanceof HTMLFrameHyperlinkEvent) {
+ ((HTMLDocument) editorPane.getDocument ()).processHTMLFrameHyperlinkEvent ((HTMLFrameHyperlinkEvent) e);
+ } else {
+ try {
+ editorPane.setPage (e.getURL ());
+ } catch (Exception ioe) {
+ System.err.println ("IOE: " + ioe);
+ }
+ }
+ }
+ }
+ };
+
+ public void restart () {
+ try {
+ editorPane.setPage (startedURL);
+ editorPane.setDragEnabled (true);
+ editorPane.removeHyperlinkListener (hyperlinkListener);
+ editorPane.addHyperlinkListener (hyperlinkListener);
+ } catch (Exception e) {
+ }
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/ImagePreview.java b/src/java/misc/ImagePreview.java
new file mode 100644
index 0000000..0d06473
--- /dev/null
+++ b/src/java/misc/ImagePreview.java
@@ -0,0 +1,89 @@
+package misc;
+
+import javax.swing.*;
+import java.beans.*;
+import java.awt.*;
+import java.io.File;
+
+/* ImagePreview.java by FileChooserDemo2.java. */
+@SuppressWarnings("serial")
+public class ImagePreview extends JComponent
+ implements PropertyChangeListener {
+
+ static public int maxInSide = 90;
+ static public int border = 5;
+ static public int maxOutSide = maxInSide+2*border;
+
+ protected ImageIcon thumbnail = null;
+ protected File file = null;
+ protected long maxSize;
+
+ public ImagePreview (JFileChooser fc, long maxSize) {
+ this.maxSize = maxSize;
+ setPreferredSize (new Dimension (maxOutSide, maxOutSide));
+ fc.addPropertyChangeListener (this);
+ }
+
+ public void loadImage () {
+ if (file == null || (maxSize > 0 && file.length () > maxSize)) {
+ thumbnail = null;
+ return;
+ }
+ //Don't use createImageIcon (which is a wrapper for getResource)
+ //because the image we're trying to load is probably not one
+ //of this program's own resources.
+ ImageIcon tmpIcon = new ImageIcon (file.getPath ());
+ if (tmpIcon != null) {
+ thumbnail = tmpIcon;
+ if (tmpIcon.getIconWidth () > tmpIcon.getIconHeight ()) {
+ if (tmpIcon.getIconWidth () > maxInSide)
+ thumbnail =
+ new ImageIcon (tmpIcon.getImage ().getScaledInstance (maxInSide, -1, Image.SCALE_DEFAULT));
+ } else {
+ if (tmpIcon.getIconHeight () > maxInSide)
+ thumbnail =
+ new ImageIcon (tmpIcon.getImage ().getScaledInstance (-1, maxInSide, Image.SCALE_DEFAULT));
+
+ }
+ }
+ }
+
+ public void propertyChange (PropertyChangeEvent e) {
+ boolean update = false;
+ String prop = e.getPropertyName ();
+
+ //If the directory changed, don't show an image.
+ if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals (prop)) {
+ file = null;
+ update = true;
+
+ //If a file became selected, find out which one.
+ } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals (prop)) {
+ file = (File) e.getNewValue ();
+ update = true;
+ }
+
+ //Update the preview accordingly.
+ if (update) {
+ thumbnail = null;
+ if (isShowing ()) {
+ loadImage ();
+ repaint ();
+ }
+ }
+ }
+
+ protected void paintComponent (Graphics g) {
+ if (thumbnail == null)
+ loadImage ();
+ if (thumbnail != null) {
+ int x = getWidth ()/2 - thumbnail.getIconWidth ()/2;
+ int y = getHeight ()/2 - thumbnail.getIconHeight ()/2;
+ if (y < border)
+ y = border;
+ if (x < border)
+ x = border;
+ thumbnail.paintIcon (this, g, x, y);
+ }
+ }
+}
diff --git a/src/java/misc/JConsole.java b/src/java/misc/JConsole.java
new file mode 100644
index 0000000..006aa6e
--- /dev/null
+++ b/src/java/misc/JConsole.java
@@ -0,0 +1,77 @@
+package misc;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+@SuppressWarnings ("serial") public class JConsole extends TitledDialog {
+
+ // ========================================
+ private JTextArea textArea = new JTextArea (5, 20);
+ public static boolean copy = true;
+
+ // ========================================
+ public JConsole (Frame frame) {
+ super (frame, "JConsole");
+ textArea.setEditable (false);
+ setPreferredSize (new Dimension (550, 300));
+ getContentPane ().add (new JScrollPane (textArea), BorderLayout.CENTER);
+ getContentPane ().add (Util.newButton ("Clear", new ActionListener () {
+ public void actionPerformed (ActionEvent evt) {
+ synchronized (textArea) {
+ textArea.setText ("");
+ }
+ }
+ }), BorderLayout.SOUTH);
+ if (copy) {
+ copyOut (true);
+ copyOut (false);
+ }
+ pack ();
+ }
+
+
+ // ========================================
+ public void copyOut (boolean err) {
+ Thread thread = new Thread () {
+ public void run () {
+ for (;;) {
+ try {
+ PipedInputStream pin = new PipedInputStream ();
+ PrintStream out = new PrintStream (new PipedOutputStream (pin), true, "UTF-8");
+ if (err)
+ System.setErr (out);
+ else
+ System.setOut (out);
+ BufferedReader in = new BufferedReader (new InputStreamReader (pin));
+ for (;;) {
+ String line = in.readLine ();
+ synchronized (textArea) {
+ textArea.append (line+"\n");
+ }
+ }
+ } catch (Exception e) {
+ textArea.append (e.toString());
+ ByteArrayOutputStream buf = new ByteArrayOutputStream ();
+ e.printStackTrace (new PrintStream (buf));
+ textArea.append (buf.toString ());
+ try {
+ Thread.sleep (1000);
+ } catch (InterruptedException e2) {
+ }
+ }
+ }
+ }
+ };
+ thread.setDaemon (true);
+ thread.start ();
+ }
+
+ // ========================================
+ public static void main (String[] arg) {
+ new JConsole (null);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/JRemoteUpdate.java b/src/java/misc/JRemoteUpdate.java
new file mode 100644
index 0000000..bad2a8f
--- /dev/null
+++ b/src/java/misc/JRemoteUpdate.java
@@ -0,0 +1,237 @@
+package misc;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.TreeSet;
+import java.util.Vector;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.table.DefaultTableModel;
+
+import static misc.Util.GBC;
+import static misc.Util.GBCNL;
+
+import static misc.RemoteUpdate.CheckPeriod;
+import static misc.RemoteUpdate.FileDescriptor;
+import static misc.RemoteUpdate.FileInfo;
+import static misc.RemoteUpdate.TodoFile;
+
+public class JRemoteUpdate implements SwingConstants {
+
+ static public String
+ actionDetails = "Details",
+ labelFileName = "FileName", labelLocal= "Local", labelRemote = "Remote";
+
+
+ // ========================================
+ private OwnFrame controller;
+ RemoteUpdate remoteUpdate;
+ Runnable actionAfterDownLoad;
+
+ JPanel jPanel = Util.getGridBagPanel ();
+ ArrayList allMirrorInfo;
+ JFrame jFrame = new JFrame ();
+ JButton startAction;
+
+ // ========================================
+ public JRemoteUpdate (OwnFrame controller, RemoteUpdate remoteUpdate, Runnable actionAfterDownLoad) {
+ this.controller = controller;
+ this.remoteUpdate = remoteUpdate;
+ this.actionAfterDownLoad = actionAfterDownLoad;
+ jFrame.setIconImage (controller.getIcon ());
+ }
+
+ public class MirrorInfo {
+ RemoteUpdate.Mirror mirror;
+ StateNotifier notifier = new StateNotifier ();
+ public ProgressState progressState = new ProgressState (notifier, "Progress");
+ TodoFile transfertAction, cleanAction;
+ JCheckBox transfertBoutton, cleanBoutton;
+ JLabel info;
+ ProgressStatePanel progressStatePanel = new ProgressStatePanel (progressState);
+
+ MirrorInfo (RemoteUpdate.Mirror mirror, TodoFile transfertAction) {
+ this.mirror = mirror;
+ // XXX check transfertAction in Download|Upload
+ this.transfertAction = transfertAction;
+ cleanAction = transfertAction == TodoFile.Download ? TodoFile.LocalRemove : TodoFile.RemoteRemove;
+ transfertBoutton = Util.addCheckIcon (""+transfertAction, null,
+ Config.getBoolean (transfertAction+mirror.token+Config.checkedPostfix, false),
+ jPanel, GBC);
+ cleanBoutton = Util.addCheckIcon (""+cleanAction, null,
+ Config.getBoolean (cleanAction+mirror.token+Config.checkedPostfix, false),
+ jPanel, GBC);
+ notifier.addUpdateObserver (progressStatePanel, "Progress");
+ info = new JLabel (mirror.getInfo (mirror.check (transfertAction), transfertAction));
+ Util.addComponent (info, jPanel, GBC);
+ Util.addIconButton (actionDetails, new ActionListener () {
+ public void actionPerformed (ActionEvent e) {
+ JOptionPane.showMessageDialog (jFrame, getDetails (), Bundle.getTitle (""+actionDetails), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }, jPanel);
+ Util.unBoxButton (jPanel);
+ Util.addComponent (progressStatePanel, jPanel, GBCNL);
+ }
+ public void setConfig () {
+ Config.setBoolean (transfertAction+mirror.token+Config.checkedPostfix, transfertBoutton.isSelected ());
+ Config.setBoolean (cleanAction+mirror.token+Config.checkedPostfix, cleanBoutton.isSelected ());
+ }
+ public void update () {
+ (new Thread () {
+ public void run () {
+ mirror.update ();
+ info.setText (mirror.getInfo (mirror.check (transfertAction), transfertAction));
+ //Util.packWindow (jPanel);
+ }
+ }).start ();
+ }
+ public JScrollPane getDetails () {
+ @SuppressWarnings ("serial")
+ DefaultTableModel dataObjectModel = new DefaultTableModel () {
+ public Class> getColumnClass (int column) {
+ if (column != 1)
+ return String.class;
+ return javax.swing.ImageIcon.class;
+ }
+ };
+ JTable jTableObject = new JTable (dataObjectModel);
+ jTableObject.getTableHeader ().setReorderingAllowed (true);
+ jTableObject.setShowVerticalLines (false);
+ JScrollPane scrollPane = Util.getJScrollPane (jTableObject, true, false);
+ jTableObject.setFillsViewportHeight (true);
+ dataObjectModel.setColumnCount (6);
+ Util.setColumnLabels (jTableObject, new String[] {"FileName", null, "LocalDate", "LocalSize", "RemoteDate", "RemoteSize"});
+
+ for (TodoFile action : new TodoFile []{transfertAction, cleanAction})
+ for (String fileName : mirror.check (action)) {
+ FileDescriptor fd = mirror.getInfo (fileName);
+ FileInfo lfi = fd.local, rfi = fd.remote;
+ dataObjectModel.addRow (new Object [] {fileName, Util.loadActionIcon (""+fd.todo+Util.ON),
+ FileInfo.getDate (lfi), FileInfo.getSize (lfi),
+ FileInfo.getDate (rfi), FileInfo.getSize (rfi)});
+ }
+ scrollPane.setPreferredSize (new java.awt.Dimension (800, 400));
+ return scrollPane;
+ }
+ public void startAction () {
+ (new Thread () {
+ public void run () {
+ try {
+ String messagePrefix = transfertAction == TodoFile.Download ? "Download" : "Upload";
+ if (!(cleanBoutton.isSelected () || transfertBoutton.isSelected ()))
+ return;
+ mirror.update ();
+ TreeSet removed = new TreeSet ();
+ if (cleanBoutton.isSelected ())
+ removed = mirror.performe (cleanAction, null);
+ TreeSet transfered = new TreeSet ();
+ if (transfertBoutton.isSelected ()) {
+ transfered = mirror.performe (transfertAction, progressState);
+ mirror.update ();
+ info.setText (mirror.getInfo (mirror.check (transfertAction), transfertAction));
+ }
+ if (removed.size () == 0 && transfered.size () == 0)
+ return;
+ JPanel msgPanel = Util.getGridBagPanel ();
+ Util.addComponent (new JLabel (MessageFormat.format (Bundle.getMessage (messagePrefix+"Completed"),
+ transfered.size ())), msgPanel, GBCNL);
+ if (transfered.size () > 0) {
+ Util.addLabel (""+transfertAction, LEFT, msgPanel, GBCNL);
+ Util.addComponent (Util.getJScrollPane (new JList (new Vector (transfered))),
+ msgPanel, GBCNL);
+ }
+ if (removed.size () > 0) {
+ Util.addLabel ("Remove", LEFT, msgPanel, GBCNL);
+ Util.addComponent (Util.getJScrollPane (new JList (new Vector (removed))),
+ msgPanel, GBCNL);
+ }
+ JOptionPane.showMessageDialog (jFrame,
+ msgPanel,
+ Bundle.getTitle (""+transfertAction), JOptionPane.INFORMATION_MESSAGE);
+ } finally {
+ decrThreads ();
+ }
+ }
+ }).start ();
+ }
+ };
+ private int nbThreads;
+ private boolean isDownload;
+ private synchronized void resetThreads (int nbThreads, boolean isDownload) {
+ if (nbThreads < 1)
+ return;
+ while (this.nbThreads != 0)
+ try {
+ wait ();
+ } catch (Exception InterruptedException) {
+ }
+ this.isDownload = isDownload;
+ startAction.setEnabled (false);
+ this.nbThreads = nbThreads;
+ }
+ private synchronized void decrThreads () {
+ nbThreads--;
+ if (nbThreads != 0)
+ return;
+ notifyAll ();
+ startAction.setEnabled (true);
+ if (isDownload && actionAfterDownLoad != null)
+ actionAfterDownLoad.run ();
+ }
+
+ // ========================================
+ public void dialog (TodoFile action, boolean checkPeriod) {
+ jPanel.removeAll ();
+ allMirrorInfo = new ArrayList ();
+ for (RemoteUpdate.Mirror mirror : remoteUpdate.mirrors)
+ allMirrorInfo.add (new MirrorInfo (mirror, action));
+ for (MirrorInfo mirrorInfo : allMirrorInfo)
+ mirrorInfo.update ();
+ startAction = Util.addButton (""+action, null, jPanel, GBCNL);
+ startAction.addActionListener (new ActionListener () {
+ public void actionPerformed (ActionEvent e) {
+ (new Thread () {
+ public void run () {
+ resetThreads (allMirrorInfo.size (), action == TodoFile.Download);
+ for (MirrorInfo mirrorInfo : allMirrorInfo)
+ mirrorInfo.startAction ();
+ }
+ }).start ();
+ }
+ });
+ if (checkPeriod) {
+ JPanel line = Util.getGridBagPanel ();
+ Util.addLabel ("CheckingPeriod", LEFT, line, GBC);
+ JComboBox periodChooser = Util.addEnum (CheckPeriod.class, remoteUpdate.currentPeriod (), line, GBCNL);
+ Util.addComponent (line, jPanel, GBCNL);
+ if (JOptionPane.showConfirmDialog (jFrame, jPanel, Bundle.getTitle (""+action),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION)
+ Config.setString ("CheckPeriod", ""+CheckPeriod.values () [periodChooser.getSelectedIndex ()]);
+ } else
+ JOptionPane.showMessageDialog (jFrame, jPanel, Bundle.getTitle (""+action), JOptionPane. QUESTION_MESSAGE);
+ for (MirrorInfo mirrorInfo : allMirrorInfo)
+ mirrorInfo.progressState.abort ();
+ for (MirrorInfo mirrorInfo : allMirrorInfo)
+ mirrorInfo.setConfig ();
+ }
+ public void downloadDialog () {
+ dialog (TodoFile.Download, true);
+ }
+ public void uploadDialog () {
+ dialog (TodoFile.Upload, false);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/LocalizedUserLabel.java b/src/java/misc/LocalizedUserLabel.java
new file mode 100644
index 0000000..2ff802d
--- /dev/null
+++ b/src/java/misc/LocalizedUserLabel.java
@@ -0,0 +1,79 @@
+// ================================================================================
+// François MERCIOL 2015
+// Name : LocalizedUserLabel.java
+// Language : Java
+// Author : François Merciol
+// CopyLeft : Cecil B
+// Creation : 2015
+// Version : 0.1 (xx/xx/xx)
+// ================================================================================
+package misc;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Locale;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+
+import static misc.Util.GBC;
+import static misc.Util.GBCNL;
+
+public class LocalizedUserLabel {
+
+ // ========================================
+ protected boolean isCustomized;
+ protected String labelName;
+ protected String currentLabel;
+ protected String newLabel;
+ protected JLabel jLabel;
+
+ public String getLabel () { return labelName; }
+ public String getNewLabel () { return isCustomized ? newLabel : null; }
+ public String getCurrentLabel () { return currentLabel; }
+ public JLabel getJLabel () { return jLabel; }
+
+ // ========================================
+ public LocalizedUserLabel (String labelName, boolean isLocalized, boolean admin) {
+ isCustomized = isLocalized && admin;
+ this.labelName = labelName;
+ currentLabel = isLocalized ? Bundle.getUser (labelName) : labelName;
+ jLabel = new JLabel (currentLabel, SwingConstants.RIGHT);
+ if (!isCustomized)
+ return;
+ jLabel.addMouseListener (new MouseAdapter () {
+ public void mousePressed (MouseEvent e) {
+ LocalizedUserLabel.this.mousePressed (e);
+ }
+ });
+ }
+
+ // ========================================
+ public void mousePressed (MouseEvent e) {
+ if (!isCustomized || !SwingUtilities.isRightMouseButton (e))
+ return;
+ Locale locale = Bundle.getLocale ();
+ ImageIcon flag = Util.loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.flagsDirname,
+ locale.getCountry ().toLowerCase () + Config.iconsExt);
+ if (flag != null)
+ flag.setDescription (locale.toString ());
+ JLabel jLocal = new JLabel (locale.toString (), flag, SwingConstants.LEFT);
+ JTextField jValue = new JTextField (newLabel == null ? Bundle.getUser (labelName) : newLabel, 9);
+ JPanel content = Util.getGridBagPanel ();
+ Util.addComponent (new JLabel (), content, GBC);
+ Util.addComponent (jLocal, content, GBCNL);
+ Util.addComponent (new JLabel (labelName+" : ", SwingConstants.RIGHT), content, GBC);
+ Util.addComponent (jValue, content, GBCNL);
+ if (JOptionPane.showConfirmDialog (e.getComponent (), content, Bundle.getTitle ("Localized"),
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
+ return;
+ currentLabel = newLabel = jValue.getText ();
+ jLabel.setText (currentLabel);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/Log.java b/src/java/misc/Log.java
new file mode 100644
index 0000000..a29a17c
--- /dev/null
+++ b/src/java/misc/Log.java
@@ -0,0 +1,102 @@
+package misc;
+
+import java.awt.Component;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+import javax.swing.AbstractButton;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+public class Log {
+
+ // ========================================
+ static private final SimpleDateFormat dateFormat = new SimpleDateFormat ("[yyyy/MM/dd HH:mm:ss] ");
+ // static private final String separator = System.getProperty ("file.separator");
+ // static public final String dumpExtension = "log";
+ static public final boolean debug = true;
+
+ // ========================================
+ static public void writeLog (String serviceName, String message) {
+ try {
+ BufferedWriter out = new BufferedWriter
+ (new FileWriter (Config.getString ("logPath", Config.logSystemDir)+Config.FS+serviceName+Config.logExt, true));
+ out.write (dateFormat.format (new Date ())+message+"\n");
+ out.flush ();
+ out.close ();
+ } catch (IOException e) {
+ }
+ }
+
+ // ========================================
+ static public Hashtable lastExceptions = new Hashtable ();
+ static public boolean keepLastException;
+
+ // ========================================
+ static public void keepLastException (String where, Throwable t) {
+ try {
+ if (debug)
+ t.printStackTrace ();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream ();
+ PrintWriter printWriter = new PrintWriter (baos);
+ printWriter.println ("Exception:\nDate: "+dateFormat.format (new Date ())+"\n");
+ t.printStackTrace (printWriter);
+ printWriter.flush ();
+ printWriter.close ();
+ lastExceptions.put (where, baos.toString ("ISO-8859-1"));
+ System.err.println ("Exception "+t+" find in "+where+"\nSee log file.");
+ keepLastException = true;
+ for (AbstractButton dumpCommand : dumpCommands)
+ dumpCommand.setEnabled (keepLastException);
+ } catch (Exception e2) {
+ }
+ }
+
+ // ========================================
+ static public void dumpLastException (File file) {
+ PrintWriter printWriter = null;
+ try {
+ printWriter = new PrintWriter (new FileWriter (file));
+ for (String where : lastExceptions.keySet ())
+ printWriter.println ("\n\nContext: "+where+"\n"+lastExceptions.get (where));
+ printWriter.flush ();
+ } catch (Exception e) {
+ } finally {
+ try {
+ printWriter.close ();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ // ========================================
+ static public void dumpSaveDialog (Component component) {
+ JFileChooser dumpChooser =
+ new JFileChooser (Config.getString ("dumpDir", Config.logSystemDir));
+ dumpChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("DumpFilter"), Config.logExt));
+ dumpChooser.setDialogTitle (Bundle.getTitle ("Dump"));
+ if (dumpChooser.showSaveDialog (component) != JFileChooser.APPROVE_OPTION)
+ return;
+ dumpLastException (dumpChooser.getSelectedFile ());
+ }
+
+ // ========================================
+ static private Vector dumpCommands = new Vector ();
+ static public void addDumpCommand (AbstractButton dumpCommand) {
+ if (dumpCommand == null)
+ return;
+ dumpCommands.add (dumpCommand);
+ dumpCommand.setEnabled (keepLastException);
+ }
+ static public void removeDumpCommand (AbstractButton dumpCommand) {
+ dumpCommands.remove (dumpCommand);
+ }
+ // ========================================
+}
diff --git a/src/java/misc/MultiToolBarBorderLayout.java b/src/java/misc/MultiToolBarBorderLayout.java
new file mode 100644
index 0000000..1958fd9
--- /dev/null
+++ b/src/java/misc/MultiToolBarBorderLayout.java
@@ -0,0 +1,318 @@
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager2;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.TreeSet;
+import javax.swing.SwingConstants;
+
+public class MultiToolBarBorderLayout implements LayoutManager2, SwingConstants {
+ static public final Hashtable positionStringToInt;
+ static public final Hashtable positionIntToString;
+
+ static {
+ positionIntToString = new Hashtable ();
+ positionIntToString.put (CENTER, BorderLayout.CENTER);
+ positionIntToString.put (NORTH, BorderLayout.NORTH);
+ positionIntToString.put (EAST, BorderLayout.EAST);
+ positionIntToString.put (SOUTH, BorderLayout.SOUTH);
+ positionIntToString.put (WEST, BorderLayout.WEST);
+
+ positionStringToInt = new Hashtable ();
+ for (int key : positionIntToString.keySet ())
+ positionStringToInt.put (positionIntToString.get (key), key);
+ }
+
+ // ========================================
+ int hgap;
+ int vgap;
+ Container menu;
+ Hashtable positions = new Hashtable ();
+ Component center;
+
+ public MultiToolBarBorderLayout () {
+ this (0, 0);
+ }
+ public MultiToolBarBorderLayout (int hgap, int vgap) {
+ this.hgap = hgap;
+ this.vgap = vgap;
+ }
+ public int getHgap () {
+ return hgap;
+ }
+ public void setHgap (int hgap) {
+ this.hgap = hgap;
+ }
+ public int getVgap () {
+ return vgap;
+ }
+ public void setVgap (int vgap) {
+ this.vgap = vgap;
+ }
+ public void setMenu (Container menu) {
+ this.menu = menu;
+ }
+ private ArrayList orderedComponents = new ArrayList ();
+ public void setLayoutOrderedComponents (ArrayList orderedComponents) {
+ if (orderedComponents== null)
+ return;
+ this.orderedComponents = orderedComponents;
+ }
+ // ========================================
+ public void addLayoutComponent (Component comp, Object constraints) {
+ synchronized (comp.getTreeLock ()) {
+ if ((constraints == null) || (constraints instanceof String))
+ addLayoutComponent ((String)constraints, comp);
+ else
+ throw new IllegalArgumentException ("cannot add to layout: constraint must be a string (or null)");
+ }
+ }
+ @Deprecated
+ public void addLayoutComponent (String name, Component comp) {
+ synchronized (comp.getTreeLock ()) {
+ if (name == null)
+ name = BorderLayout.CENTER;
+ Integer position = positionStringToInt.get (name);
+ if (position == CENTER) {
+ if (center != null)
+ // XXX ou erreur
+ positions.remove (comp);
+ center = comp;
+ }
+ positions.put (comp, position);
+ }
+ }
+ public void removeLayoutComponent (Component comp) {
+ synchronized (comp.getTreeLock ()) {
+ positions.remove (comp);
+ if (center == comp)
+ center = null;
+ }
+ }
+ public Object getConstraints (Component comp) {
+ try {
+ return positionIntToString.get (positions.get (comp));
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ // ========================================
+ public Dimension minimumLayoutSize (Container target) {
+ return layoutSize (target, true);
+ }
+ public Dimension preferredLayoutSize (Container target) {
+ return layoutSize (target, false);
+ }
+ public Dimension maximumLayoutSize (Container target) {
+ return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+ Hashtable> getSortedComponents (Container target) {
+ ArrayList allComponents = new ArrayList (orderedComponents);
+ for (Component c : target.getComponents ())
+ if (!allComponents.contains (c))
+ allComponents.add (c);
+ Hashtable> sortedComponents = new Hashtable> ();
+ for (int pos : positionIntToString.keySet ())
+ sortedComponents.put (pos, new ArrayList ());
+ for (Component c : allComponents) {
+ Integer position = positions.get (c);
+ if (!c.isVisible () || position == null)
+ continue;
+ sortedComponents.get (position).add (c);
+ }
+ return sortedComponents;
+ }
+ int maxSize (ArrayList components, boolean isMinimum, boolean isHorizontal) {
+ int max = 0;
+ int componentCount = components.size ();
+ for (int i = 0; i < componentCount; i++) {
+ Component c = components.get (i);
+ Dimension d = isMinimum ? c.getMinimumSize () : c.getPreferredSize ();
+ max = isHorizontal ? Math.max (max, d.width) : Math.max (max, d.height);
+ }
+ return max;
+ }
+ TreeSet getIntermediate (ArrayList components, boolean isMinimum, boolean isHorizontal, int minSize) {
+ ArrayList sizes = new ArrayList ();
+ int componentCount = components.size ();
+ for (int i = 0; i < componentCount; i++) {
+ Component c = components.get (i);
+ Dimension d = isMinimum ? c.getMinimumSize () : c.getPreferredSize ();
+ sizes.add (isHorizontal ? d.width : d.height);
+ }
+ TreeSet result = new TreeSet ();
+ int maxComp = componentCount-1;
+ for (int i = 0; i < componentCount; i++) {
+ int size = 0;
+ for (int j = i; j < maxComp; j++) {
+ size += sizes.get (j);
+ if (size > minSize)
+ result.add (size);
+ }
+ maxComp = componentCount;
+ }
+ return result;
+ }
+ void swapAxes (Dimension d) {
+ int tmp = d.width;
+ d.width = d.height;
+ d.height = tmp;
+ }
+ Dimension fill (ArrayList components, boolean isMinimum, boolean isHorizontal, int maxWidth) {
+ int componentCount = components.size ();
+ int x = 0, y = 0, maxX = 0, rowHeight = 0;
+ for (int i = 0; i < componentCount; i++) {
+ Component c = components.get (i);
+ Dimension d = isMinimum ? c.getMinimumSize () : c.getPreferredSize ();
+ if (!isHorizontal)
+ swapAxes (d);
+ if (x == 0 || x + d.width <= maxWidth) {
+ if (x > 0)
+ x += isHorizontal ? hgap : vgap;
+ x += d.width;
+ rowHeight = Math.max (rowHeight, d.height);
+ continue;
+ }
+ maxX = Math.max (maxX, x);
+ x = d.width;
+ y += (isHorizontal ? vgap : hgap) + rowHeight;
+ rowHeight = d.height;
+ }
+ Dimension result = new Dimension (Math.max (maxX, x), y+rowHeight);
+ // !!! if !isHorizontal : width => main axes
+ return result;
+ }
+ Dimension getExtra (Hashtable> sortedComponents,
+ int northPos, int southPos, boolean isMinimum, boolean isHorizontal,
+ int menuWidth, int extraCenter) {
+ int minWidth = Util.max (maxSize (sortedComponents.get (CENTER), isMinimum, isHorizontal)+extraCenter,
+ menuWidth,
+ maxSize (sortedComponents.get (northPos), isMinimum, isHorizontal),
+ maxSize (sortedComponents.get (southPos), isMinimum, isHorizontal));
+ TreeSet sizes = new TreeSet ();
+ sizes.add (minWidth);
+ sizes.addAll (getIntermediate (sortedComponents.get (northPos), isMinimum, isHorizontal, minWidth));
+ sizes.addAll (getIntermediate (sortedComponents.get (southPos), isMinimum, isHorizontal, minWidth));
+ int minSurface = Integer.MAX_VALUE;
+ int extraHeight = 0;
+ for (int size : sizes) {
+ Dimension northDim = fill (sortedComponents.get (northPos), isMinimum, isHorizontal, size);
+ Dimension southDim = fill (sortedComponents.get (southPos), isMinimum, isHorizontal, size);
+ int width = Util.max (size, northDim.width, southDim.width);
+ int height = northDim.height+southDim.height;
+ int surface = height*width;
+ if (surface < minSurface) {
+ minSurface = surface;
+ minWidth = width;
+ extraHeight = height;
+ }
+ }
+ Dimension result = new Dimension (minWidth, extraHeight);
+ if (!isHorizontal)
+ swapAxes (result);
+ return result;
+ }
+ Dimension layoutSize (Container target, boolean isMinimum) {
+ synchronized (target.getTreeLock ()) {
+ Hashtable> sortedComponents = getSortedComponents (target);
+ Dimension extraSide = getExtra (sortedComponents, WEST, EAST, isMinimum, false, 0, 0);
+ int menuWidth = menu == null ? 0 : (isMinimum ? menu.getMinimumSize () : menu.getPreferredSize ()).width;
+ Dimension extra = getExtra (sortedComponents, NORTH, SOUTH, isMinimum, true, menuWidth, extraSide.width);
+ Insets insets = target.getInsets ();
+ return new Dimension (extra.width+insets.left+insets.right,
+ extraSide.height+extra.height+insets.top+insets.bottom);
+ }
+ }
+ public float getLayoutAlignmentX (Container parent) {
+ return 0.5f;
+ }
+ public float getLayoutAlignmentY (Container parent) {
+ return 0.5f;
+ }
+ // ========================================
+ public void invalidateLayout (Container target) {
+ }
+ public void layoutContainer (Container target) {
+ synchronized (target.getTreeLock ()) {
+ Hashtable> sortedComponents = getSortedComponents (target);
+ Insets insets = target.getInsets ();
+ int top = insets.top;
+ int bottom = target.getHeight () - insets.bottom;
+ int left = insets.left;
+ int right = target.getWidth () - insets.right;
+
+ int maxWidth = right-left;
+ top += setComponents (target, sortedComponents.get (NORTH), insets.top, insets.left, true, maxWidth);
+ bottom -= setComponents (target, sortedComponents.get (SOUTH), insets.top, insets.left, true, maxWidth);
+ moveComponents (sortedComponents.get (SOUTH), 0, bottom-insets.top);
+
+ int maxHeight = bottom-top;
+ left += setComponents (target, sortedComponents.get (WEST), top, insets.left, false, maxHeight);
+ right -= setComponents (target, sortedComponents.get (EAST), top, insets.left, false, maxHeight);
+ moveComponents (sortedComponents.get (EAST), right-insets.left, 0);
+
+ if (center != null && center.isVisible ())
+ center.setBounds (left, top, right - left, bottom - top);
+ target.repaint ();
+ }
+ }
+ private void moveComponents (ArrayList components, int dx, int dy) {
+ int componentCount = components.size ();
+ for (int i = 0; i < componentCount; i++) {
+ Component c = components.get (i);
+ c.setLocation (c.getX ()+dx, c.getY ()+dy);
+ }
+ }
+ private int setComponents (Container target, ArrayList components, int top, int left, boolean isHorizontal, int maxWidth) {
+ int x = 0, y = 0, rowHeight = 0, rowStart = 0;
+ int componentCount = components.size ();
+ for (int i = 0; i < componentCount; i++) {
+ Component c = components.get (i);
+ Dimension d = c.getPreferredSize ();
+ c.setSize (d.width, d.height);
+ if (!isHorizontal)
+ swapAxes (d);
+ if (x == 0 || x + d.width <= maxWidth) {
+ if (x > 0)
+ x += isHorizontal ? hgap : vgap;
+ x += d.width;
+ rowHeight = Math.max (rowHeight, d.height);
+ continue;
+ }
+ setComponents (target, left, top, components, rowStart, i, isHorizontal, y, rowHeight);
+ x = d.width;
+ y += (isHorizontal ? vgap : hgap) + rowHeight;
+ rowHeight = d.height;
+ rowStart = i;
+ }
+ setComponents (target, left, top, components, rowStart, componentCount, isHorizontal, y, rowHeight);
+ return y+rowHeight;
+ }
+ private void setComponents (Container target, int x, int y,
+ ArrayList components, int rowStart, int rowEnd,
+ boolean isHorizontal, int delta, int maxSize) {
+ for (int i = rowStart; i < rowEnd; i++) {
+ Component c = components.get (i);
+ if (isHorizontal) {
+ int cy = y + delta + (maxSize - c.getHeight ())/2;
+ c.setLocation (x, cy);
+ x += c.getWidth () + hgap;
+ } else {
+ int cx = x + delta + (maxSize - c.getWidth ())/2;
+ c.setLocation (cx, y);
+ y += c.getHeight () + vgap;
+ }
+ }
+ }
+ // ========================================
+ public String toString () {
+ return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]";
+ }
+}
diff --git a/src/java/misc/OwnFrame.java b/src/java/misc/OwnFrame.java
new file mode 100644
index 0000000..b07ae2b
--- /dev/null
+++ b/src/java/misc/OwnFrame.java
@@ -0,0 +1,11 @@
+package misc;
+
+import java.awt.Image;
+import javax.swing.JFrame;
+
+public interface OwnFrame {
+ public JFrame getJFrame ();
+ public String getTitle ();
+ public Image getIcon ();
+ public void reborn ();
+}
diff --git a/src/java/misc/Plugins.java b/src/java/misc/Plugins.java
new file mode 100644
index 0000000..09d1d93
--- /dev/null
+++ b/src/java/misc/Plugins.java
@@ -0,0 +1,165 @@
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Vector;
+import javax.swing.ImageIcon;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTable;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+
+public class Plugins {
+
+ // ========================================
+ static public URL getDataUrl (String name) {
+ try {
+ File file = (new File (name));
+ if (file.exists ()) {
+ URL result = file.toURI ().toURL ();
+ return result;
+ }
+ } catch (Exception e) {
+ }
+ try {
+ URL result = ClassLoader.getSystemResource (name);
+ return result;
+ } catch (Exception e) {
+ }
+ return null;
+ }
+ // ========================================
+ static public ImageIcon loadImageIcon (String name) {
+ URL url = getDataUrl ("data/images/button/"+name+".png");
+ return (url != null) ? new ImageIcon (url) : null;
+ }
+ // ========================================
+ // Change Util.version too !
+ static public final Long version = 20171101L;
+ static public final String[] stateLabel = {"not found", "old version", "updated"};
+ static public final ImageIcon[] stateIcon = { loadImageIcon ("Bad"), loadImageIcon ("Warning"), loadImageIcon ("Good")};
+
+ static public class PluginInfo {
+ public String name;
+ public String url;
+ public boolean mandatory, loaded, update;
+ public PluginInfo (String name, String url, boolean mandatory) {
+ this.name = name;
+ this.url = url;
+ this.mandatory = mandatory;
+ }
+ };
+
+ static ArrayList pluginsInfo = new ArrayList ();
+
+ // ========================================
+ @SuppressWarnings ("rawtypes")
+ static public void check (String name, String url, String className, boolean mandatory, Long dateNeed) {
+ PluginInfo pluginInfo = new PluginInfo (name, url, mandatory);
+ pluginsInfo.add (pluginInfo);
+ try {
+ Class plugin = ClassLoader.getSystemClassLoader ().loadClass (className);
+ pluginInfo.loaded = true;
+ pluginInfo.update =
+ dateNeed == null ||
+ dateNeed <= (Long) plugin.getDeclaredField ("version").get (null);
+ } catch (Exception e) {
+ }
+ }
+
+ // ========================================
+ @SuppressWarnings ("serial")
+ static public class ImageCellRenderer extends JLabel implements TableCellRenderer {
+ public Component getTableCellRendererComponent (JTable jTable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ if (value instanceof ImageIcon) {
+ setIcon ((ImageIcon) value);
+ setText (null);
+
+ } else {
+ setIcon (null);
+ setText ((String) value);
+ }
+ return this;
+ }
+ }
+
+ // ========================================
+ static public JDialog jDialog;
+ static public boolean warning = false;
+
+ static public void showSate () {
+ Vector> data = new Vector> ();
+ boolean ready = true;
+ for (PluginInfo pluginInfo : pluginsInfo) {
+ ready &= !pluginInfo.mandatory || pluginInfo.loaded;
+ int state = (pluginInfo.loaded ? (pluginInfo.update ? 2 : 1) : 0);
+ if (state != 2)
+ warning = true;
+ data.add
+ (new Vector
+ (Arrays.asList (pluginInfo.name, stateIcon[state], stateLabel[state], (pluginInfo.update ? "" : pluginInfo.url) )));
+ }
+ Vector columnNames = new Vector (Arrays.asList ("Plugin name", "", "State", "URL"));
+ @SuppressWarnings ("serial")
+ JTable table = new JTable (data, columnNames) {
+ public Component prepareRenderer (final TableCellRenderer renderer, final int row, final int column) {
+ final Component prepareRenderer = super.prepareRenderer (renderer, row, column);
+ final TableColumn tableColumn = getColumnModel ().getColumn (column);
+ int width = Math.max (prepareRenderer.getPreferredSize ().width, tableColumn.getPreferredWidth ());
+ tableColumn.setPreferredWidth (width);
+ return prepareRenderer;
+ }
+ };
+ table.setDefaultRenderer (Object.class, new ImageCellRenderer ());
+
+ final TableCellRenderer renderer = table.getTableHeader ().getDefaultRenderer ();
+ for (int i = 0; i < table.getColumnCount (); ++i) {
+ int width = renderer.getTableCellRendererComponent (table, table.getModel ().getColumnName (i), false, false, 0, i).getPreferredSize ().width;
+ TableColumn tableColumn = table.getColumnModel ().getColumn (i);
+ tableColumn.setPreferredWidth (width);
+ }
+
+ JPanel container = new JPanel ();
+ container.setLayout (new BorderLayout());
+ container.add (table.getTableHeader(), BorderLayout.PAGE_START);
+ container.add (table, BorderLayout.CENTER);
+
+ if (!ready) {
+ Dimension containerSize = container.getSize ();
+ containerSize.width = Math.max (containerSize.width, 600);
+ containerSize.height = Math.max (containerSize.height, 100);
+ container.setPreferredSize (containerSize);
+
+ container.add (new JLabel ("Would you like to continue?"), BorderLayout.PAGE_END);
+ if (JOptionPane.YES_OPTION !=
+ JOptionPane.showConfirmDialog (null, container, " Can't load plugins ", JOptionPane.YES_NO_OPTION))
+ System.exit (1);
+ return;
+ }
+ jDialog = new JDialog ((java.awt.Frame)null, " Plugins state ", false);
+ jDialog.getContentPane ().add (container, BorderLayout.CENTER);
+ jDialog.setVisible (true);
+ jDialog.pack ();
+ jDialog.setLocationRelativeTo (null);
+ jDialog.toFront ();
+ }
+
+ static public void hideSate () {
+ if (jDialog == null)
+ return;
+ jDialog.pack ();
+ //jDialog.toFront ();
+ if (!warning)
+ jDialog.setVisible (false);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/ProgressState.java b/src/java/misc/ProgressState.java
new file mode 100644
index 0000000..1680f5a
--- /dev/null
+++ b/src/java/misc/ProgressState.java
@@ -0,0 +1,67 @@
+package misc;
+
+import java.util.HashSet;
+
+public class ProgressState {
+
+ // ========================================
+ HashSet workingThreads = new HashSet ();
+ StateNotifier observable;
+ String valueName;
+
+ static public enum State {Init, Value, End};
+ public State state;
+ public String domain;
+ public int value;
+ public int maxValue;
+
+ // ========================================
+ public ProgressState (StateNotifier observable, String valueName) {
+ this.observable = observable;
+ this.valueName = valueName;
+ }
+ // ========================================
+ public synchronized void init (String domain, int maxValue) {
+ this.domain = domain;
+ this.value = 0;
+ this.maxValue = maxValue;
+ state = State.Init;
+ workingThreads = new HashSet ();
+ workingThreads.add (Thread.currentThread ());
+ observable.broadcastUpdate (valueName);
+ }
+ public synchronized void addThread (Thread thread) {
+ // XXX test ! State.end
+ workingThreads.add (thread);
+ }
+ // ========================================
+ public synchronized void abort () {
+ workingThreads.clear ();
+ }
+ // ========================================
+ public synchronized boolean isInterrupted () {
+ return !workingThreads.contains (Thread.currentThread ());
+ }
+ // ========================================
+ public synchronized boolean setValue (int value) {
+ this.value = value;
+ state = State.Value;
+ observable.broadcastUpdate (valueName);
+ return workingThreads.contains (Thread.currentThread ());
+ }
+ // ========================================
+ public synchronized boolean addValue (int delta) {
+ if (delta > 0) {
+ value += delta;
+ state = State.Value;
+ observable.broadcastUpdate (valueName);
+ }
+ return workingThreads.contains (Thread.currentThread ());
+ }
+ // ========================================
+ public synchronized void end () {
+ state = State.End;
+ observable.broadcastUpdate (valueName);
+ }
+ // ========================================
+}
diff --git a/src/java/misc/ProgressStatePanel.java b/src/java/misc/ProgressStatePanel.java
new file mode 100644
index 0000000..a6313ab
--- /dev/null
+++ b/src/java/misc/ProgressStatePanel.java
@@ -0,0 +1,78 @@
+// ================================================================================
+// Copyright (c) Francois Merciol 2002
+// Project : Classe
+// Name : DatePanel.java
+// Language : Java
+// Type : Source file for DatePanel class
+// Author : Francois Merciol
+// Creation : 02/09/2002
+// ================================================================================
+// History
+// --------------------------------------------------------------------------------
+// Author :
+// Date :
+// Reason :
+// ================================================================================
+// To be improved :
+// ================================================================================
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+
+@SuppressWarnings ("serial") public class ProgressStatePanel extends JPanel implements ActionListener {
+
+ // ========================================
+ JProgressBar jProgressBar = new JProgressBar ();
+ JButton stopButton = new JButton (Util.loadActionIcon ("Abort"));
+ ProgressState progressState;
+
+ // ========================================
+ public ProgressStatePanel (ProgressState progressState) {
+ this.progressState = progressState;
+ jProgressBar.setMaximum (1);
+ jProgressBar.setString ("");
+ jProgressBar.setStringPainted (true);
+ jProgressBar.setAlignmentX (Component.LEFT_ALIGNMENT);
+
+ setLayout (new BorderLayout ());
+ add (jProgressBar, BorderLayout.CENTER);
+ stopButton.setActionCommand ("Abort");
+ stopButton.addActionListener (this);
+ stopButton.setEnabled (false);
+ add (stopButton, BorderLayout.LINE_END);
+ }
+
+ public void actionPerformed (ActionEvent e) {
+ if (e.getSource () != stopButton)
+ return;
+ progressState.abort ();
+ }
+
+ // ========================================
+ public void updateProgress () {
+ switch (progressState.state) {
+ case Value:
+ jProgressBar.setValue (progressState.value);
+ break;
+ case Init:
+ jProgressBar.setString (progressState.domain);
+ jProgressBar.setValue (progressState.value);
+ jProgressBar.setMaximum (progressState.maxValue);
+ stopButton.setEnabled (true);
+ break;
+ case End:
+ jProgressBar.setString ("");
+ jProgressBar.setValue (0);
+ stopButton.setEnabled (false);
+ break;
+ }
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/ProxyManager.java b/src/java/misc/ProxyManager.java
new file mode 100644
index 0000000..09cb21e
--- /dev/null
+++ b/src/java/misc/ProxyManager.java
@@ -0,0 +1,110 @@
+package misc;
+
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import javax.swing.AbstractButton;
+import javax.swing.ButtonGroup;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import static misc.Util.GBCNL;
+
+@SuppressWarnings ("serial")
+public class ProxyManager implements ApplicationManager, ActionListener {
+ static public final String
+ actionSetProxy = "SetProxy",
+ actionNoProxy = "NoProxy",
+ actionSystemConfigProxy = "SystemConfigProxy",
+ actionManualConfigProxy = "ManualConfigProxy";
+
+ static public final List radioButtonNames = Arrays.asList (actionNoProxy, actionSystemConfigProxy, actionManualConfigProxy);
+ static public final List actionsNames = Arrays.asList (actionSetProxy);
+ @SuppressWarnings("unchecked")
+ static public final Hashtable actionsMethod =
+ Util.collectMethod (ProxyManager.class, actionsNames, radioButtonNames);
+ public void actionPerformed (ActionEvent e) {
+ Util.actionPerformed (actionsMethod, e, this);
+ }
+ // ========================================
+ public void addMenuItem (JMenu... jMenu) {
+ Util.addMenuItem (actionsNames, this, jMenu[0]);
+ }
+ public void addIconButtons (Container... containers) {
+ Util.addIconButton (actionsNames, this, containers[0]);
+ }
+ public void addActiveButtons (Hashtable buttons) {
+ // disable if no network ?
+ }
+ JPanel manualPanel;
+ private String getConfig () {
+ if ("true".equals (System.getProperty ("java.net.useSystemProxies")))
+ return actionSystemConfigProxy;
+ String host = System.getProperty ("http.proxyHost");
+ String port = System.getProperty ("http.proxyPort");
+ if (host == null || port == null || host.isEmpty () || port.isEmpty ())
+ return actionNoProxy;
+ return actionManualConfigProxy;
+ }
+ public void actionSetProxy () {
+ JFrame jFrame = new JFrame ();
+ jFrame.setIconImage (controller.getIcon ());
+ JPanel msgPanel = Util.getGridBagPanel ();
+ String proxyConfig = getConfig ();
+ ButtonGroup group = new ButtonGroup ();
+ Util.addRadioButton (actionNoProxy, this, group, proxyConfig, msgPanel, GBCNL);
+ Util.addRadioButton (actionSystemConfigProxy, this, group, proxyConfig, msgPanel, GBCNL);
+ Util.addRadioButton (actionManualConfigProxy, this, group, proxyConfig, msgPanel, GBCNL);
+ manualPanel = Util.getGridBagPanel ();
+ JTextField hostTF = new JTextField (Config.getString ("ProxyHostName", "squid"), 18);
+ JTextField portTF = new JTextField (Config.getString ("ProxyPort", "3128"), 6);
+ // System.setProperty("http.proxyUser", "user");
+ // System.setProperty("http.proxyPassword", "password");
+ Util.addLabelFields (manualPanel, "Host", hostTF);
+ Util.addLabelFields (manualPanel, "Port", portTF);
+ Util.addComponent (manualPanel, msgPanel, GBCNL);
+ Util.setEnabled (manualPanel, proxyConfig.equals (actionManualConfigProxy));
+ if (JOptionPane.showConfirmDialog (jFrame, msgPanel, misc.Bundle.getTitle ("Proxy"), JOptionPane.YES_NO_OPTION)
+ != JOptionPane.YES_OPTION)
+ return;
+ Config.setString ("ProxyHostName", hostTF.getText ());
+ Config.setString ("ProxyPort", portTF.getText ());
+ proxyConfig = group.getSelection ().getActionCommand ();
+ if (actionSystemConfigProxy.equals (proxyConfig)) {
+ System.setProperty ("java.net.useSystemProxies", "true");
+ System.setProperty ("http.proxyHost", "");
+ } else {
+ System.setProperty ("java.net.useSystemProxies", "false");
+ if (actionNoProxy.equals (proxyConfig))
+ System.setProperty ("http.proxyHost", "");
+ else if (actionManualConfigProxy.equals (proxyConfig)) {
+ System.setProperty ("http.proxyHost", hostTF.getText ());
+ System.setProperty ("http.proxyPort", portTF.getText ());
+ }
+ }
+ java.net.ProxySelector.setDefault (java.net.ProxySelector.getDefault ());
+ }
+ public void actionNoProxy () {
+ Util.setEnabled (manualPanel, false);
+ }
+ public void actionSystemConfigProxy () {
+ Util.setEnabled (manualPanel, false);
+ }
+ public void actionManualConfigProxy () {
+ Util.setEnabled (manualPanel, true);
+ }
+
+ // ========================================
+ private OwnFrame controller;
+ public ProxyManager (OwnFrame controller) {
+ this.controller = controller;
+ }
+ // ========================================
+}
diff --git a/src/java/misc/RealTime.java b/src/java/misc/RealTime.java
new file mode 100644
index 0000000..050b92c
--- /dev/null
+++ b/src/java/misc/RealTime.java
@@ -0,0 +1,73 @@
+package misc;
+
+@SuppressWarnings ("serial")
+class NewChalenger extends RuntimeException {
+ public NewChalenger () {
+ super ("NewChalenger");
+ }
+}
+
+public class RealTime {
+ // ========================================
+ private int nbChalengers;
+ private Thread leadership;
+
+ public void start (Runnable task) {
+ (new Thread () {
+ public void run () {
+ if (!getLeadership ())
+ return;
+ try {
+ task.run ();
+ } catch (NewChalenger e) {
+ } finally {
+ loseLeaderShip ();
+ }
+ }
+ }).start ();
+ }
+
+ // ========================================
+ public synchronized void waitTerminaison () {
+ if (leadership == Thread.currentThread ())
+ return;
+ while (leadership != null && nbChalengers > 0)
+ try {
+ wait ();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // ========================================
+ public synchronized boolean getLeadership () {
+ if (leadership != null) {
+ nbChalengers++;
+ try {
+ wait ();
+ } catch (InterruptedException e) {
+ }
+ nbChalengers--;
+ if (nbChalengers != 0) {
+ notifyAll ();
+ return false;
+ }
+ }
+ leadership = Thread.currentThread ();
+ return true;
+ }
+ public synchronized void loseLeaderShip () {
+ leadership = null;
+ notifyAll ();
+ }
+ public synchronized void checkChalengers () {
+ if (nbChalengers != 0)
+ throw new NewChalenger ();
+ }
+
+ // ========================================
+ static public void checkChalengers (RealTime realTime) {
+ if (realTime != null)
+ realTime.checkChalengers ();
+ }
+ // ========================================
+}
diff --git a/src/java/misc/RemoteUpdate.java b/src/java/misc/RemoteUpdate.java
new file mode 100644
index 0000000..3647309
--- /dev/null
+++ b/src/java/misc/RemoteUpdate.java
@@ -0,0 +1,748 @@
+package misc;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.CookiePolicy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+public class RemoteUpdate {
+
+ // ========================================
+ static long delay = 2000;
+ static CookieManager cookieManager = new CookieManager();
+ static {
+ try {
+ ((CookieManager) CookieHandler.getDefault ()).setCookiePolicy (CookiePolicy.ACCEPT_ALL);
+ } catch (Exception e) {
+ cookieManager.setCookiePolicy (CookiePolicy.ACCEPT_ALL);
+ CookieHandler.setDefault (cookieManager);
+ }
+ }
+
+ // ========================================
+ static public final String backExtention = "back";
+ static public final int bufSize = 1024*1024;
+ static public final SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyyMMdd");
+ static public final SimpleDateFormat timeFormat = new SimpleDateFormat ("yyyyMMddHHmmss");
+ static public final SimpleDateFormat displayFormat = new SimpleDateFormat ("dd/MM/yyyy HH:mm:ss");
+ static public final NumberFormat numberFormat = NumberFormat.getInstance ();
+
+ static public enum CheckPeriod { NoCheck, Day, Week, Month, Year; };
+ static public final List excludeFileName = Arrays.asList ("timestamp");
+
+ static public enum TodoFile {LocalRemove, Download, NoChange, Upload, RemoteRemove};
+ static public class FileInfo {
+ long date, size;
+ public FileInfo (long date, long size) { this.date = date; this.size = size; }
+ public String toString () { return "{"+displayFormat.format (new Date (date))+" "+size+"}"; }
+ static public String getDate (FileInfo fileInfo) { return fileInfo == null ? "" : displayFormat.format (fileInfo.date); }
+ static public String getSize (FileInfo fileInfo) { return fileInfo == null ? "" : ""+fileInfo.size; }
+ };
+
+ static public FilenameFilter mirrorFilter = new FilenameFilter () {
+ public boolean accept (File dir, String name) {
+ return ! (excludeFileName.contains (name) || name.endsWith ("."+backExtention) || name.endsWith (".new"));
+ }
+ };
+
+ // ========================================
+ static public class FileDescriptor {
+ // ----------------------------------------
+ public TodoFile todo = TodoFile.NoChange;
+ public FileInfo local, remote;
+ public String toString () { return ""+todo+" "+local+" "+remote; }
+ // ----------------------------------------
+ public void updateTodo (TodoFile action) {
+ todo = TodoFile.NoChange;
+ if (remote == null) {
+ switch (action) {
+ case LocalRemove:
+ case Upload:
+ todo = action;
+ case Download:
+ break;
+ case NoChange:
+ case RemoteRemove:
+ break;
+ }
+ return;
+ }
+ if (local == null) {
+ switch (action) {
+ case RemoteRemove:
+ case Download:
+ todo = action;
+ case LocalRemove:
+ break;
+ case NoChange:
+ case Upload:
+ break;
+ }
+ return;
+ }
+ if (local.size != remote.size) {
+ switch (action) {
+ case LocalRemove:
+ todo = TodoFile.Download;
+ break;
+ case RemoteRemove:
+ todo = TodoFile.Upload;
+ break;
+ default:
+ todo = action;
+ }
+ return;
+ }
+ if (local.date+delay < remote.date) {
+ if (action == TodoFile.Download || action == TodoFile.LocalRemove)
+ todo = TodoFile.Download;
+ return;
+ }
+ if (local.date > remote.date+delay) {
+ if (action == TodoFile.Upload || action == TodoFile.RemoteRemove)
+ todo = TodoFile.Upload;
+ //System.err.print (" "+local.date+" "+remote.date+" "+action);
+ return;
+ }
+ }
+ // ----------------------------------------
+ };
+
+ // ========================================
+ public class Mirror {
+ String token;
+ File localRepository;
+ FilenameFilter mirrorFilter = RemoteUpdate.mirrorFilter;
+ TreeSet excludeFiles;
+ TreeMap localFiles, remoteFiles;
+ TreeMap allFiles;
+
+ // ----------------------------------------
+ public Mirror (File root, String... params) {
+ token = params[0];
+ if (params.length > 1) {
+ localRepository = root;
+ for (int i = 1; i < params.length; i++)
+ localRepository = new File (localRepository, params[i]);
+ } else
+ localRepository = new File (root, token);
+ }
+ public String toString () { return token+": "+localFiles+" "+remoteFiles; }
+ public synchronized void update () {
+ updateRemoteFiles ();
+ updateLocalFiles ();
+ if (remoteFiles == null)
+ return;
+ TreeSet allFilesName = new TreeSet ();
+ allFilesName.addAll (localFiles.keySet ());
+ allFilesName.addAll (remoteFiles.keySet ());
+ allFiles = new TreeMap ();
+ for (String fileName : allFilesName)
+ allFiles.put (fileName, new FileDescriptor ());
+ for (String fileName : localFiles.keySet ())
+ allFiles.get (fileName).local = localFiles.get (fileName);
+ for (String fileName : remoteFiles.keySet ())
+ allFiles.get (fileName).remote = remoteFiles.get (fileName);
+ }
+ public void updateTodo (TodoFile action) {
+ if (allFiles == null)
+ return;
+ for (String fileName : allFiles.keySet ()) {
+ //System.err.print ("coucou : "+fileName+" ");
+ allFiles.get (fileName).updateTodo (action);
+ //System.err.println ();
+ }
+ }
+ public long getSize (TreeSet filesName, TodoFile action) {
+ long result = 0;
+ if (allFiles == null || action == TodoFile.NoChange)
+ return result;
+ boolean remote = false;
+ switch (action) {
+ case LocalRemove:
+ case Download:
+ remote = true;
+ case NoChange:
+ break;
+ case RemoteRemove:
+ case Upload:
+ break;
+ }
+ for (String fileName : filesName) {
+ FileDescriptor file = allFiles.get (fileName);
+ if (file == null)
+ continue;
+ try {
+ if (file.todo == action)
+ result += remote ? file.remote.size : file.local.size;
+ } catch (Exception e) {
+ }
+ }
+ return result;
+ }
+ public TreeSet getFileAction (TodoFile action) {
+ TreeSet result = new TreeSet ();
+ if (allFiles == null)
+ return result;
+ for (String fileName : allFiles.keySet ())
+ if (allFiles.get (fileName).todo == action)
+ result.add (fileName);
+ return result;
+ }
+ public synchronized boolean hasNewVersion () {
+ update ();
+ return check (TodoFile.Download).size () > 0;
+ }
+ public synchronized TreeSet check (TodoFile action) {
+ updateTodo (action);
+ return getFileAction (action);
+ }
+ public TreeSet performe (TodoFile action, ProgressState progressState) {
+ try {
+ TreeSet files = check (action);
+ if (progressState != null)
+ progressState.init (Bundle.getMessage (""+action), (int) getSize (files, action));
+ switch (action) {
+ case LocalRemove:
+ return localRemove (this, files, progressState);
+ case RemoteRemove:
+ return remoteRemove (this, files, progressState);
+ case Download:
+ return getRemoteFiles (this, files, progressState);
+ case Upload:
+ return putRemoteFiles (this, files, progressState);
+ case NoChange:
+ break;
+ }
+ } finally {
+ if (progressState != null)
+ progressState.end ();
+ }
+ return new TreeSet ();
+ }
+ public String getInfo (TreeSet files, TodoFile action) {
+ return MessageFormat.format (Bundle.getMessage ("DownloadInfo"),
+ Bundle.getLabel (Util.toCapital (token)),
+ allFiles == null ? 0 : 1, files.size (), Util.toNumIn2Units (getSize (files, action)));
+ }
+ public FileDescriptor getInfo (String fileName) {
+ return allFiles.get (fileName);
+ }
+
+ // ----------------------------------------
+ private void updateLocalFiles () {
+ excludeFiles = new TreeSet ();
+ localFiles = new TreeMap ();
+ updateLocalFiles (localRepository, token);
+ }
+ private void updateLocalFiles (File localRepository, String name) {
+ if (localRepository.isFile ()) {
+ if (excludeFileName.contains (name) || name.endsWith ("."+backExtention)) {
+ excludeFiles.add (name);
+ return;
+ }
+ localFiles.put (name, new FileInfo (localRepository.lastModified (), localRepository.length ()));
+ return;
+ }
+ if (!localRepository.isDirectory ())
+ return;
+ for (String child : localRepository.list ()) {
+ updateLocalFiles (new File (localRepository, child), name+"/"+child);
+ }
+ }
+ private void getExcludeFiles (File localRepository, String name) {
+ if (localRepository.isFile ()) {
+ localFiles.put (name, new FileInfo (localRepository.lastModified (), localRepository.length ()));
+ return;
+ }
+ if (!localRepository.isDirectory ())
+ return;
+ for (String child : localRepository.list (mirrorFilter)) {
+ if (excludeFileName.contains (child))
+ continue;
+ updateLocalFiles (new File (localRepository, child), name+"/"+child);
+ }
+ }
+ // ----------------------------------------
+ private void updateRemoteFiles () {
+ try {
+ allFiles = null;
+ remoteFiles = null;
+ URLConnection urlConnection = getUrlConnection ("zipList", token);
+ urlConnection.connect ();
+ remoteFiles = new TreeMap ();
+ receiveZip (urlConnection, new ZipLineReader () {
+ public void readLine (String line) {
+ ParsePosition pos = new ParsePosition (0);
+ try {
+ long date = timeFormat.parse (line, pos).getTime ();
+ pos.setIndex (pos.getIndex ()+1);
+ long size = numberFormat.parse (line, pos).longValue ();
+ String fileName = line.substring (pos.getIndex ()+1);
+ remoteFiles.put (fileName, new FileInfo (date, size));
+ } catch (Exception e) {
+ }
+ }}, token);
+ } catch (Exception e) {
+ System.err.println (e);
+ //e.printStackTrace ();
+ }
+ }
+ // ----------------------------------------
+ };
+
+ // ========================================
+ public String protocol;
+ public String serverName;
+ public String versionName;
+ public String requestModel;
+ public Mirror[] mirrors;
+ public RemoteUpdate (String protocol, String serverName, String versionName, String requestModel, String []... mirrorsParams) {
+ this.protocol = protocol;
+ this.serverName = serverName;
+ this.versionName = versionName;
+ this.requestModel = requestModel;
+ File root = Config.getPWD ().getParentFile ();
+ this.mirrors = new Mirror[mirrorsParams.length];
+ int idx = 0;
+ for (String [] params : mirrorsParams)
+ mirrors[idx++] = new Mirror (root, params);
+ }
+ public CheckPeriod currentPeriod () {
+ return CheckPeriod.valueOf (CheckPeriod.class, Config.getString ("CheckPeriod", ""+CheckPeriod.Month));
+ }
+ public boolean hasNewVersion () {
+ CheckPeriod period = currentPeriod ();
+ Date lastCheck = new Date ();
+ try {
+ lastCheck = dateFormat.parse (Config.getString ("LastCheck", "20150401"));
+ } catch (Exception e) {
+ }
+ Date today = new Date ();
+ long age = (today.getTime ()-lastCheck.getTime ())/(24*60*60*1000);
+ switch (period) {
+ case NoCheck:
+ return false;
+ case Day:
+ if (age < 1)
+ return false;
+ break;
+ case Week:
+ if (age < 7)
+ return false;
+ break;
+ case Month:
+ if (age < 31)
+ return false;
+ break;
+ case Year:
+ if (age < 366)
+ return false;
+ break;
+ }
+ Config.setString ("LastCheck", dateFormat.format (today));
+ for (Mirror mirror : mirrors)
+ if (mirror.hasNewVersion ())
+ return true;
+ return false;
+ }
+
+ // ========================================
+ private URLConnection getUrlConnection (String cmd, String arg)
+ throws IOException {
+ return getUrlConnection (MessageFormat.format (requestModel, versionName, cmd, arg));
+ }
+ private URLConnection getUrlConnection (String uri)
+ throws IOException {
+ URL url = new URL (protocol+"://"+serverName+uri);
+ URLConnection urlConnection = url.openConnection ();
+ urlConnection.setRequestProperty ("User-Agent", "Adecwatt Agent");
+ urlConnection.setUseCaches (true);
+ return urlConnection;
+ }
+
+ static private Random random = new Random ();
+ static private final String charset = "UTF-8";
+ static private final String LINE_FEED = "\r\n";
+ static public String getBoundary () {
+ // XXX we must check not apears in message :-(
+ return "=-="+Long.toString (random.nextLong (), 36).toUpperCase ()+"=-=";
+ }
+
+ // ========================================
+ public abstract class ZipBuilder {
+ public abstract void writeEntry (String token, ZipOutputStream zipOut) throws IOException;
+ };
+ public class TextZipBuilder extends ZipBuilder {
+ private TreeSet filesName;
+ public TextZipBuilder (TreeSet filesName) { this.filesName = filesName; }
+ public void writeEntry (String token, ZipOutputStream zipOut) throws IOException {
+ ZipEntry zipOutEntry = new ZipEntry (token);
+ zipOut.putNextEntry (zipOutEntry);
+ PrintWriter entryWriter = new PrintWriter (new OutputStreamWriter (zipOut));
+ for (String fileName : filesName)
+ entryWriter.print (fileName+"\n");
+ entryWriter.flush ();
+ zipOut.closeEntry ();
+ }
+ };
+ public abstract class ZipFileReader {
+ public abstract boolean readEntry (ZipInputStream zipIn, String entryName, String token) throws IOException;
+ };
+ public abstract class ZipLineReader extends ZipFileReader {
+ public boolean readEntry (ZipInputStream zipIn, String entryName, String token) throws IOException {
+ if (! entryName.equals (token))
+ return true;
+ BufferedReader in = new BufferedReader (new InputStreamReader (zipIn));
+ for (;;) {
+ String line = in.readLine ();
+ if (line == null)
+ break;
+ if ("".equals (line))
+ continue;
+ readLine (line);
+ }
+ return false;
+ }
+
+ public abstract void readLine (String line);
+ };
+
+ // ========================================
+ public void receiveZip (URLConnection urlConnection, ZipFileReader zipFileReader, String token) {
+ try {
+ String contentType = urlConnection.getContentType ();
+ if (contentType == null || !contentType.startsWith ("application/zip"))
+ return;
+ ZipInputStream zipIn = new ZipInputStream (urlConnection.getInputStream ());
+ for (;;) {
+ ZipEntry zipInEntry = zipIn.getNextEntry ();
+ if (zipInEntry == null)
+ break;
+ String entryName = zipInEntry.getName ();
+ if (!entryName.startsWith (token))
+ continue;
+ if (!zipFileReader.readEntry (zipIn, entryName, token))
+ break;
+ }
+ } catch (Exception e) {
+ e.printStackTrace ();
+ }
+ }
+
+ // ========================================
+ public URLConnection sendZip (String cmd, String token, ZipBuilder zipBuilder) {
+ try {
+ URLConnection urlConnection = getUrlConnection (cmd, token);
+ String boundary = getBoundary ();
+ urlConnection.setRequestProperty ("Content-Type", "multipart/form-data; boundary="+boundary);
+ urlConnection.setDoOutput (true);
+ urlConnection.setDoInput (true);
+ OutputStream httpStream = urlConnection.getOutputStream ();
+ PrintWriter httpWriter = new PrintWriter (new OutputStreamWriter (httpStream, charset), true);
+ httpWriter.append ("--"+boundary).append (LINE_FEED);
+ httpWriter.append ("Content-Disposition: form-data; name=\""+cmd+"\"; filename=\""+cmd+"\"").append (LINE_FEED);
+ httpWriter.append ("Content-Type: application/zip").append (LINE_FEED);
+ httpWriter.append ("Content-Transfer-Encoding: binary").append (LINE_FEED);
+ httpWriter.append (LINE_FEED).flush ();
+ ByteArrayOutputStream memStream = new ByteArrayOutputStream ();
+ ZipOutputStream zipOut = new ZipOutputStream (memStream);
+
+ zipBuilder.writeEntry (token, zipOut);
+
+ zipOut.flush ();
+ zipOut.close ();
+ httpWriter.flush ();
+ httpStream.write (memStream.toByteArray ());
+ httpWriter.append (LINE_FEED).flush ();
+ httpWriter.append ("--"+boundary+"--").append(LINE_FEED);
+ httpWriter.close ();
+
+ urlConnection.connect ();
+ return urlConnection;
+ } catch (Exception e) {
+ e.printStackTrace ();
+ }
+ return null;
+ }
+
+ // ========================================
+ public TreeSet localRemove (Mirror mirror, TreeSet filesName, ProgressState progressState) {
+ if (filesName == null)
+ filesName = new TreeSet ();
+ if (mirror.excludeFiles != null)
+ filesName.addAll (mirror.excludeFiles);
+ TreeSet removed = new TreeSet ();
+ for (String fileName : filesName) {
+ if (! fileName.startsWith (mirror.token))
+ continue;
+ fileName = fileName.substring (mirror.token.length ());
+ File oldFile = new File (mirror.localRepository.getAbsolutePath ()+fileName);
+ if (!oldFile.delete ())
+ System.err.println ("coucou pb delete: "+oldFile);
+ removed.add (fileName);
+ }
+ return removed;
+ }
+
+ // ========================================
+ public TreeSet remoteRemove (Mirror mirror, TreeSet filesName, ProgressState progressState) {
+ if (filesName == null)
+ filesName = new TreeSet ();
+ if (mirror.excludeFiles != null)
+ filesName.addAll (mirror.excludeFiles);
+ TreeSet removed = new TreeSet ();
+ if (filesName.size () < 1)
+ return removed;
+ URLConnection urlConnection = sendZip ("zipRemove", mirror.token, new TextZipBuilder (filesName));
+ receiveZip (urlConnection, new ZipLineReader () {
+ public void readLine (String line) {
+ removed.add (line);
+ }}, mirror.token);
+ return removed;
+ }
+
+ // ========================================
+ public TreeSet getRemoteFiles (Mirror mirror, TreeSet filesName, ProgressState progressState) {
+ TreeSet downloaded = new TreeSet ();
+ try {
+ if (filesName.size () < 1)
+ return downloaded;
+ URLConnection urlConnection = sendZip ("zipGets", mirror.token, new TextZipBuilder (filesName));
+ byte[] tmp = new byte[bufSize];
+ receiveZip (urlConnection, new ZipFileReader () {
+ public boolean readEntry (ZipInputStream zipIn, String entryName, String token) throws IOException {
+ File newFile = mirror.localRepository;
+ for (String item : entryName.substring (mirror.token.length ()).split ("/")) {
+ if (item == null || item.isEmpty ())
+ continue;
+ newFile = new File (newFile, item);
+ }
+ File dirFile = newFile.getParentFile ();
+ dirFile.mkdirs ();
+ File tmpFile = File.createTempFile ("download", "tmp", dirFile);
+ tmpFile.deleteOnExit ();
+ Util.copy (zipIn, new FileOutputStream (tmpFile), tmp, progressState, false, true);
+ // XXX tmpFile.setLastModified (zipInEntry.getLastModifiedTime ().toMillis ());
+ tmpFile.setLastModified (mirror.allFiles.get (entryName).remote.date);
+ if (progressState != null && progressState.isInterrupted ())
+ return false;
+ Util.backup (newFile, Util.getExtention (newFile), backExtention);
+ try {
+ Files.move (tmpFile.toPath (), newFile.toPath (), StandardCopyOption.REPLACE_EXISTING);
+ } catch (Exception e) {
+ }
+ if (tmpFile.exists ()) {
+ System.err.println ("can't change open file!");
+ tmpFile.renameTo (new File (""+newFile+".new"));
+ }
+ downloaded.add (entryName);
+ return true;
+ }}, mirror.token);
+ } catch (Exception e) {
+ e.printStackTrace ();
+ }
+ return downloaded;
+ }
+
+ // ========================================
+ public static boolean newFileExists (File file) {
+ if (file.isFile () && file.exists () && "new".equals (Util.getExtention (file)))
+ return true;
+ if (!file.isDirectory ())
+ return false;
+ for (File subFile : file.listFiles (new FileFilter () {
+ public boolean accept (File file2) {
+ return file2.isDirectory () || (file2.isFile () && "new".equals (Util.getExtention (file2)));
+ }
+ }))
+ if (newFileExists (subFile))
+ return true;
+ return false;
+ }
+ public static void renameNewFile (File file) {
+ if (file.isFile () && file.exists () && "new".equals (Util.getExtention (file))) {
+ try {
+ File newFile = new File (file.getParentFile (), Util.getBase (file));
+ Files.move (file.toPath (), newFile.toPath (), StandardCopyOption.REPLACE_EXISTING);
+ } catch (Exception e) {
+ }
+ }
+ if (!file.isDirectory ())
+ return;
+ for (File subFile : file.listFiles (new FileFilter () {
+ public boolean accept (File file2) {
+ return file2.isDirectory () || (file2.isFile () && "new".equals (Util.getExtention (file2)));
+ }
+ }))
+ renameNewFile (subFile);
+ }
+
+ // ========================================
+ public static void launch (File jarFile) {
+ try {
+ Runtime.getRuntime ().exec ("java -jar "+jarFile.getName (), null, jarFile.getParentFile ());
+ System.exit (0);
+ } catch (Exception e) {
+ e.printStackTrace ();
+ }
+ }
+
+ // ========================================
+ public TreeSet putRemoteFiles (Mirror mirror, TreeSet filesName, ProgressState progressState) {
+ TreeSet uploaded = new TreeSet ();
+ if (filesName == null || filesName.size () < 1)
+ return uploaded;
+ try {
+ byte[] tmp = new byte[bufSize];
+ TimeZone timeZone = TimeZone.getDefault ();
+ URLConnection urlConnection = sendZip ("zipPuts", mirror.token, new ZipBuilder () {
+ public void writeEntry (String token, ZipOutputStream zipOut) throws IOException {
+ for (String fileName : filesName) {
+ if (! fileName.startsWith (token))
+ continue;
+ ZipEntry zipOutEntry = new ZipEntry (fileName);
+ File file = new File (mirror.localRepository, fileName.substring (token.length ()));
+ long dateMs = file.lastModified ();
+ dateMs -= timeZone.getOffset (dateMs);
+ zipOutEntry.setTime (dateMs);
+ zipOut.putNextEntry (zipOutEntry);
+ PrintWriter entryWriter = new PrintWriter (new OutputStreamWriter (zipOut));
+ Util.copy (new FileInputStream (file), zipOut, tmp, progressState, true, false);
+ entryWriter.flush ();
+ zipOut.closeEntry ();
+ }
+ }});
+ receiveZip (urlConnection, new ZipLineReader () {
+ public void readLine (String line) {
+ uploaded.add (line);
+ }}, mirror.token);
+ } catch (Exception e) {
+ e.printStackTrace ();
+ }
+ return uploaded;
+ }
+
+ // ========================================
+ public String getRoles (String login) {
+ try {
+ URLConnection urlConnection = getUrlConnection ("getRoles", login);
+ urlConnection.connect ();
+ BufferedReader br = new BufferedReader (new InputStreamReader (urlConnection.getInputStream ()));
+ String roles = br.readLine ();
+ for (;;) {
+ String line = br.readLine ();
+ if (line == null)
+ break;
+ }
+ if (roles.indexOf ("|") < 0)
+ return null;
+ return roles;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ public void logoutDokuwiki () {
+ try {
+ URLConnection urlConnection = getUrlConnection ("?do=logout");
+ urlConnection.connect ();
+ forceOpenConnection (urlConnection);
+ } catch (Exception e) {
+ }
+ }
+ public void loginDokuwiki (String login, String password) {
+ try {
+ // page de connexion
+ URLConnection urlConnection = getUrlConnection ("?do=login");
+ urlConnection.connect ();
+ String sectok = null;
+ BufferedReader br = new BufferedReader (new InputStreamReader (urlConnection.getInputStream ()));
+ for (;;) {
+ String line = br.readLine ();
+ if (line == null)
+ break;
+ if (line.indexOf ("name=\"sectok\"") < 0)
+ continue;
+ Pattern p = Pattern.compile (".*<([^<]*name=\"sectok\"[^>]*)>.*");
+ Matcher m = p.matcher (line);
+ if (!m.matches ())
+ break;
+ line = m.group (1);
+ p = Pattern.compile (".*value=\"([^\"]*)\".*");
+ m = p.matcher (line);
+ if (!m.matches ())
+ break;
+ sectok = m.group (1);
+ break;
+ }
+ if (sectok == null)
+ return;
+ // envoie de mot de passe
+ urlConnection = getUrlConnection ("?do=login");
+ urlConnection.setDoOutput (true);
+ urlConnection.setDoInput (true);
+ urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded");
+ String post =
+ "sectok="+sectok+"&"+
+ "id=debut&"+
+ "do=login&"+
+ "u="+URLEncoder.encode (login, charset)+"&"+
+ "p="+URLEncoder.encode (password, charset);
+ urlConnection.setRequestProperty ("Content-Length", ""+post.getBytes ().length);
+ OutputStream httpStream = urlConnection.getOutputStream ();
+ PrintWriter httpWriter = new PrintWriter (new OutputStreamWriter (httpStream, charset), true);
+ httpWriter.append (post).append (LINE_FEED).flush ();
+ urlConnection.connect ();
+ forceOpenConnection (urlConnection);
+ } catch (Exception e) {
+ e.printStackTrace ();
+ }
+ }
+
+ // ========================================
+ static public void forceOpenConnection (URLConnection urlConnection) {
+ try {
+ BufferedReader br = new BufferedReader (new InputStreamReader (urlConnection.getInputStream ()));
+ for (;;) {
+ String line = br.readLine ();
+ if (line == null)
+ break;
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/RemoteUpdateManager.java b/src/java/misc/RemoteUpdateManager.java
new file mode 100644
index 0000000..28b4cac
--- /dev/null
+++ b/src/java/misc/RemoteUpdateManager.java
@@ -0,0 +1,74 @@
+package misc;
+
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import javax.swing.AbstractButton;
+import javax.swing.JMenu;
+
+@SuppressWarnings ("serial")
+public class RemoteUpdateManager implements ApplicationManager, ActionListener {
+
+ // ========================================
+ static public final String
+ actionUpdate = "Update",
+ actionOnline = "Online";
+ static public final List actionsNames = Arrays.asList (actionUpdate, actionOnline);
+ @SuppressWarnings("unchecked")
+ static public final Hashtable actionsMethod =
+ Util.collectMethod (RemoteUpdateManager.class, actionsNames);
+ public void actionPerformed (ActionEvent e) {
+ Util.actionPerformed (actionsMethod, e, this);
+ }
+
+ // ========================================
+ public void addMenuItem (JMenu... jMenu) {
+ Util.addMenuItem (actionsNames, this, jMenu[0]);
+ }
+ public void addIconButtons (Container... containers) {
+ Util.addIconButton (actionsNames, this, containers[0]);
+ }
+ private ArrayList enabledConnectedButtons = new ArrayList ();
+ public void addActiveButtons (Hashtable buttons) {
+ enabledConnectedButtons.add (buttons.get (actionOnline));
+ updateActiveButtons ();
+ }
+ public void updateActiveButtons () {
+ for (AbstractButton button : enabledConnectedButtons)
+ button.setEnabled (connected);
+ }
+ public void actionUpdate () {
+ jRemoteUpdate.downloadDialog ();
+ }
+ public void actionOnline () {
+ jRemoteUpdate.uploadDialog ();
+ }
+
+ // ========================================
+ private boolean connected = false;
+ private RemoteUpdate remoteUpdate;
+ private JRemoteUpdate jRemoteUpdate;
+
+ public void setConnected (boolean connected) { this.connected = connected; updateActiveButtons (); }
+ public RemoteUpdate getRemoteUpdate () { return remoteUpdate; }
+ public JRemoteUpdate getJRemoteUpdate () { return jRemoteUpdate; }
+
+ public RemoteUpdateManager (OwnFrame controller, RemoteUpdate remoteUpdate, Runnable actionAfterUpdate) {
+ this.remoteUpdate = remoteUpdate;
+ jRemoteUpdate = new JRemoteUpdate (controller, remoteUpdate, actionAfterUpdate);
+ }
+
+ public void check () {
+ (new Thread () { public void run () {
+ if (remoteUpdate.hasNewVersion ())
+ jRemoteUpdate.downloadDialog ();
+ } }).start ();
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/ScaledImage.java b/src/java/misc/ScaledImage.java
new file mode 100644
index 0000000..eedd252
--- /dev/null
+++ b/src/java/misc/ScaledImage.java
@@ -0,0 +1,238 @@
+// ================================================================================
+// François MERCIOL 2015
+// Name : ScaledImage.java
+// Language : Java
+// Author : François Merciol
+// CopyLeft : Cecil B
+// Creation : 2015
+// Version : 0.1 (xx/xx/xx)
+// ================================================================================
+package misc;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Point2D;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.util.Hashtable;
+import javax.swing.ImageIcon;
+
+public class ScaledImage {
+
+ static public class ImageInfo {
+ public AffineTransform at;
+ public double [] bounds;
+ public double x, y;
+ Hashtable tiles = new Hashtable ();
+ public ImageInfo (AffineTransform at, double [] bounds, double x, double y) {
+ this.at = at;
+ this.bounds = bounds;
+ this.x = x;
+ this.y = y;
+ }
+ }
+ // ========================================
+ static public final RenderingHints renderingHints;
+ static {
+ renderingHints = new RenderingHints (RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ // renderingHints.put (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ // renderingHints.put (RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+ // renderingHints.put (RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
+ // renderingHints.put (RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ }
+
+ static public final int defaultAdjust = 8;
+ public BufferedImage reference;
+ public boolean horizontalSpin, verticalSpin;
+
+ Hashtable> scalesRotations = new Hashtable> ();
+
+ public ScaledImage (BufferedImage image) {
+ reference = image;
+ }
+ public ScaledImage (BufferedImage image, boolean horizontalSpin, boolean verticalSpin) {
+ reference = image;
+ this.horizontalSpin = horizontalSpin;
+ this.verticalSpin = verticalSpin;
+ }
+
+ public ScaledImage getNewSpin (boolean horizontalSpin, boolean verticalSpin) {
+ if (this.horizontalSpin == horizontalSpin && this.verticalSpin == verticalSpin)
+ return this;
+ return new ScaledImage (reference, this.horizontalSpin ^ horizontalSpin, this.verticalSpin ^ verticalSpin);
+ }
+
+ public void changeReference (BufferedImage image) {
+ reference = image;
+ clearCache ();
+ }
+
+ public void clearCache () {
+ scalesRotations.clear ();
+ }
+
+ // ========================================
+ public AffineTransform getAffineTransform (Dimension2D size, double theta) {
+ int width = reference.getWidth ();
+ int height = reference.getHeight ();
+ double scaleX = size.getWidth () / width;
+ double scaleY = size.getHeight () / height;
+ if (scaleX == 0 || scaleY == 0)
+ return null;
+ if (horizontalSpin)
+ scaleX = -scaleX;
+ if (verticalSpin)
+ scaleY = -scaleY;
+ AffineTransform at = AffineTransform.getRotateInstance (Math.toRadians ((int) Math.toDegrees (theta)));
+ at.scale (scaleX, scaleY);
+ at.translate (-width/2., -height/2.);
+ return at;
+ }
+
+ static public final Point2D ORIGINE = new Point2D.Double (0, 0);
+ static public final Dimension ONE_TILE = new Dimension (1, 1);
+ public ImageIcon get (Dimension size, double theta) {
+ return get (size, theta, ONE_TILE);
+ }
+ public ImageIcon get (Dimension size, double theta, Dimension tile) {
+ if (tile.width <= 0 || tile.height <= 0)
+ return null;
+ ImageInfo imageInfo = getInfo (size, theta);
+ if (imageInfo == null)
+ return null;
+ ImageIcon imageIcon = imageInfo.tiles.get (tile);
+ if (imageIcon != null)
+ return imageIcon;
+ AffineTransformOp op = new AffineTransformOp (imageInfo.at, renderingHints);
+ BufferedImage image = op.createCompatibleDestImage (reference, null);
+ Graphics2D printGraphics = (Graphics2D) image.getGraphics ();
+ printGraphics.setRenderingHint (RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ print (printGraphics, null, imageInfo, tile);
+ imageIcon = new ImageIcon (image);
+ imageInfo.tiles.put (tile, imageIcon);
+ return imageIcon;
+ }
+ public void print (Graphics2D printGraphics, Point2D pos, ImageInfo imageInfo, Dimension tile) {
+ if (pos != null)
+ printGraphics.translate (pos.getX ()+imageInfo.x, pos.getY ()+imageInfo.y);
+ if (ONE_TILE.equals (tile))
+ printGraphics.drawImage (reference, imageInfo.at, null);
+ else {
+ double width = reference.getWidth (), height = reference.getHeight ();
+ double scaleX = 1.0/tile.width, scaleY = 1.0/tile.height;
+ double stepX = width/tile.width, stepY = height/tile.height;
+ for (int i = 0; i < tile.width; i++)
+ for (int j = 0; j < tile.height; j++) {
+ AffineTransform at = new AffineTransform (imageInfo.at);
+ at.translate (i*stepX, j*stepY);
+ at.scale (scaleX, scaleY);
+ printGraphics.drawImage (reference, at, null);
+ }
+ }
+ if (pos != null)
+ printGraphics.translate (-pos.getX ()-imageInfo.x, -pos.getY ()-imageInfo.y);
+ }
+ public void print (Graphics2D printGraphics, Point2D pos, DimensionDouble size, double theta, Dimension tile) {
+ print (printGraphics, pos, newInfo (size, theta), tile);
+ }
+
+ public double[] getBounds (Dimension size, double theta) {
+ ImageInfo imageInfo = getInfo (size, theta);
+ if (imageInfo == null)
+ return null;
+ return imageInfo.bounds;
+ }
+ public ImageInfo getInfo (Dimension size, double theta) {
+ int angle = (int) Math.toDegrees (theta);
+ Hashtable rotated = scalesRotations.get (angle);
+ if (rotated == null) {
+ rotated = new Hashtable ();
+ scalesRotations.put (angle, rotated);
+ }
+ ImageInfo imageInfo = rotated.get (size);
+ if (imageInfo != null)
+ return imageInfo;
+ imageInfo = newInfo (new DimensionDouble (size.width, size.height), theta);
+ if (imageInfo == null)
+ return null;
+ rotated.put (size, imageInfo);
+ return imageInfo;
+ }
+ public ImageInfo newInfo (DimensionDouble size, double theta) {
+ int width = reference.getWidth ();
+ int height = reference.getHeight ();
+ double scaleX = size.getWidth () / width;
+ double scaleY = size.getHeight () / height;
+ if (scaleX == 0 || scaleY == 0)
+ return null;
+ if (horizontalSpin)
+ scaleX = -scaleX;
+ if (verticalSpin)
+ scaleY = -scaleY;
+ AffineTransform at = getAffineTransform (size, theta);
+ double [] bounds = new double [] {0, 0, 0, height, width, height, width, 0};
+ at.transform (bounds, 0, bounds, 0, 4);
+ double dx = bounds[0];
+ double dy = bounds[1];
+ for (int i = 1; i < 4; i++) {
+ dx = Math.min (dx, bounds [i*2]);
+ dy = Math.min (dy, bounds [i*2+1]);
+ }
+ at.preConcatenate (AffineTransform.getTranslateInstance (-dx, -dy));
+ return new ImageInfo (at, bounds, dx, dy);
+ }
+
+ public ImageInfo newInfo2 (DimensionDouble size, double theta) {
+ int width = reference.getWidth ();
+ int height = reference.getHeight ();
+ double scaleX = size.getWidth () / width;
+ double scaleY = size.getHeight () / height;
+ if (scaleX == 0 || scaleY == 0)
+ return null;
+ if (horizontalSpin)
+ scaleX = -scaleX;
+ if (verticalSpin)
+ scaleY = -scaleY;
+ AffineTransform at = AffineTransform.getRotateInstance (theta);
+ at.scale (scaleX, scaleY);
+ at.translate (-width/2., -height/2.);
+ double [] bounds = new double [] {0, 0, 0, height, width, height, width, 0};
+ at.transform (bounds, 0, bounds, 0, 4);
+ double dx = bounds[0];
+ double dy = bounds[1];
+ for (int i = 1; i < 4; i++) {
+ dx = Math.min (dx, bounds [i*2]);
+ dy = Math.min (dy, bounds [i*2+1]);
+ }
+ at.preConcatenate (AffineTransform.getTranslateInstance (-dx, -dy));
+ return new ImageInfo (at, bounds, dx, dy);
+ }
+
+ public ImageIcon getSide (int max) {
+ int width = reference.getWidth ();
+ int height = reference.getHeight ();
+ return get (width>height ? new Dimension (max, (height*max)/width) : new Dimension ((width*max)/height, max), 0);
+ }
+
+ public ImageIcon getInsideFit (int maxWidth, int maxHeight, int adjust) {
+ return getInside (Math.min (reference.getWidth (), (maxWidth/adjust)*adjust),
+ Math.min (reference.getHeight (), (maxHeight/adjust)*adjust));
+ }
+
+ public ImageIcon getInside (int maxWidth, int maxHeight) {
+ int width = reference.getWidth ();
+ int height = reference.getHeight ();
+ return get ((width*maxHeight)/height > maxWidth ?
+ new Dimension (maxWidth, (height*maxWidth)/width) :
+ new Dimension ((width*maxHeight)/height, maxHeight), 0);
+ }
+
+ public ImageIcon get (DimensionDouble real, double scale, double theta) {
+ return get (new Dimension ((int)(real.getWidth ()*scale), (int)(real.getHeight ()*scale)), 0);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/SpinnerSlider.java b/src/java/misc/SpinnerSlider.java
new file mode 100644
index 0000000..013129d
--- /dev/null
+++ b/src/java/misc/SpinnerSlider.java
@@ -0,0 +1,125 @@
+package misc;
+
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ChangeListener;
+
+import misc.Util;
+import static misc.Util.GBC;
+import static misc.Util.GBCNL;
+
+/**
+ Spinner and Slider
+*/
+@SuppressWarnings ("serial")
+public class SpinnerSlider extends JPanel implements ChangeListener {
+
+ static public int MaxPrecision = 10000;
+ static public NumberFormat numberFormat;
+ static {
+ numberFormat = NumberFormat.getInstance (Locale.FRENCH);
+ //numberFormat = new DecimalFormat ("#,##0.###,#");
+ numberFormat.setGroupingUsed (true);
+ numberFormat.setMinimumFractionDigits (0);
+ numberFormat.setMaximumFractionDigits (12);
+ }
+
+ // ========================================
+ public interface Accessor {
+ /** current */
+ public void set (double value);
+ /** minValue, maxValue, current */
+ public double [] get ();
+ };
+ Accessor accessor;
+
+ // ========================================
+ public double minValue, maxValue;
+ public SpinnerNumberModel snm = new SpinnerNumberModel (0., 0., 0., 1.) {
+ public Object getPreviousValue () {
+ Number value = (Number) super.getPreviousValue ();
+ return SpinnerSlider.this.getPreviousValue (value);
+ }
+ public Object getNextValue () {
+ Number value = (Number) super.getNextValue ();
+ return SpinnerSlider.this.getNextValue (value);
+ }
+ };
+ public JSpinner spinner = new JSpinner (snm);
+ public JLabel label = new JLabel ("/0");
+ private JSlider slider = new JSlider (0, MaxPrecision, 1);
+
+ // ========================================
+ public SpinnerSlider (Accessor accessor, int textLength, float slideWidthCoef) {
+ super (null);
+ this.accessor = accessor;
+
+ snm.addChangeListener (this);
+ slider.addChangeListener (this);
+ ((JSpinner.DefaultEditor) spinner.getEditor ()).getTextField ().setColumns (textLength);
+
+ JSpinner.NumberEditor editor = (JSpinner.NumberEditor) spinner.getEditor ();
+ DecimalFormat format = editor.getFormat ();
+ format.setDecimalSeparatorAlwaysShown (true);
+ format.setMinimumFractionDigits (0);
+ format.setMaximumFractionDigits (12);
+
+ setLayout (new GridBagLayout ());
+ Util.addComponent (spinner, this, GBC);
+ Util.addComponent (label, this, GBC);
+ Util.addComponent (slider, this, GBCNL);
+
+ Dimension d = slider.getPreferredSize ();
+ d.width = (int)(slideWidthCoef*d.width);
+ slider.setPreferredSize (d);
+ slider.setMinimumSize (d);
+ }
+
+ // ========================================
+ public void stateChanged (ChangeEvent e) {
+ try {
+ if (e.getSource () == slider)
+ accessor.set (((double)slider.getValue ()/MaxPrecision)*(maxValue - minValue)+minValue);
+ else if (e.getSource () == snm)
+ accessor.set (((Number)snm.getValue ()).doubleValue ());
+ } catch (Exception e2) {
+ e2.printStackTrace ();
+ }
+ }
+
+ // ========================================
+ public void update () {
+ double [] doubleValues = accessor.get ();
+ minValue = doubleValues [0];
+ maxValue = doubleValues [1];
+ slider.removeChangeListener (this);
+ snm.removeChangeListener (this);
+ snm.setMinimum (doubleValues [0]);
+ snm.setMaximum (doubleValues [1]); // XXX ?
+ snm.setValue (doubleValues [2]);
+ //snm.setStepSize ((maxValue-minValue)/MaxPrecision);
+ slider.setValue ((int)((doubleValues [2]-minValue)/(maxValue-minValue)*MaxPrecision));
+ label.setText ("/"+numberFormat.format ((float)doubleValues [1]));
+ snm.addChangeListener (this);
+ slider.addChangeListener (this);
+ }
+
+ // ========================================
+ public Number getPreviousValue (Number value) {
+ return value;
+ }
+ public Number getNextValue (Number value) {
+ return value;
+ }
+ // ========================================
+}
diff --git a/src/java/misc/StateNotifier.java b/src/java/misc/StateNotifier.java
new file mode 100644
index 0000000..665d879
--- /dev/null
+++ b/src/java/misc/StateNotifier.java
@@ -0,0 +1,109 @@
+// ================================================================================
+// François MERCIOL 2013
+// Name : StateNotifier.java
+// Language : Java
+// Author : François Merciol
+// CopyLeft : Cecil B
+// Creation : 2012
+// Version : 0.1 (xx/xx/xx)
+// ================================================================================
+
+package misc;
+
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.TreeSet;
+
+public class StateNotifier {
+
+ // ========================================
+ private Hashtable> observers = new Hashtable> ();
+ private Hashtable> observableNames= new Hashtable> ();
+
+ // ========================================
+ private void broadcast (String observable) {
+ Hashtable objectMethod = observableNames.get (observable);
+ if (objectMethod == null)
+ return;
+ try {
+ for (Object object : objectMethod.keySet ())
+ objectMethod.get (object).invoke (object);
+ } catch (Exception e) {
+ Log.keepLastException ("ModelInfoSender::broadcast <"+observable+">", e);
+ }
+ }
+
+ // ========================================
+ private void broadcast (String observable, Object... args) {
+ Hashtable objectMethod = observableNames.get (observable);
+ if (objectMethod == null)
+ return;
+ try {
+ for (Object object : objectMethod.keySet ())
+ objectMethod.get (object).invoke (object, new Object[]{args});
+ } catch (Exception e) {
+ Log.keepLastException ("ModelInfoSender::broadcast <"+observable+">", e);
+ }
+ }
+
+ // ========================================
+ public void broadcastUpdate (String observable) {
+ broadcast ("update"+observable);
+ }
+ public void broadcastDisplay (String observable, Object... args) {
+ broadcast ("display"+observable, args);
+ }
+
+ // ========================================
+ private void addObserver (Object object, boolean arg, String... observable) {
+ TreeSet newNames = new TreeSet ();
+ for (String obs : observable) {
+ String name = (arg ? "display" : "update")+obs;
+ try {
+ Method method = arg ?
+ object.getClass ().getMethod (name, Object[].class):
+ object.getClass ().getMethod (name);
+ Hashtable objectMethod = observableNames.get (name);
+ if (objectMethod == null)
+ observableNames.put (name, objectMethod = new Hashtable ());
+ objectMethod.put (object, method);
+ newNames.add (name);
+ } catch (NoSuchMethodException e) {
+ Log.keepLastException ("StateNotifier::addObserver no method <"+name+"> in class <"+object.getClass ()+">", e);
+ }
+ }
+ if (newNames.size () == 0)
+ return;
+ try {
+ TreeSet oldNames = observers.get (object);
+ oldNames.addAll (newNames);
+ } catch (Exception e) {
+ observers.put (object, newNames);
+ }
+ }
+
+ // ========================================
+ public void addUpdateObserver (Object object, String... observable) {
+ addObserver (object, false, observable);
+ }
+ public void addMsgObserver (Object object, String... observable) {
+ addObserver (object, true, observable);
+ }
+
+ // ========================================
+ public void removeObserver (Object object) {
+ TreeSet names = observers.get (object);
+ if (names == null)
+ return;
+ for (String name : names) {
+ Hashtable objectMethod = observableNames.get (name);
+ objectMethod.remove (object);
+ if (objectMethod.size () == 0)
+ observableNames.remove (name);
+ }
+ observers.remove (object);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/Story.java b/src/java/misc/Story.java
new file mode 100644
index 0000000..13e920e
--- /dev/null
+++ b/src/java/misc/Story.java
@@ -0,0 +1,156 @@
+package misc;
+
+import java.util.ArrayList;
+import java.util.Stack;
+import java.util.Vector;
+
+public class Story {
+
+ // ========================================
+ static public final String
+ BroadcastStory = "Story";
+
+ public abstract class Command {
+ public final String name;
+ public Command (String name) { this.name = name; }
+ public abstract void exec ();
+ public abstract void undo ();
+ public void displayExec () { display (); }
+ public void displayUndo () { display (); }
+ public void display () {}
+ }
+
+ public abstract class Commands extends Command {
+ ArrayList commands = new ArrayList ();
+ public Commands (String name) { super (name); }
+ public Story getStory () { return Story.this; }
+ public int size () { return commands.size (); }
+ public void add (Command command) {
+ commands.add (command);
+ }
+ public void exec () {
+ // XXX si erreur undo jusqu'a l'etape
+ for (Command command : commands) {
+ command.exec ();
+ command.displayExec ();
+ }
+ }
+ public void undo () {
+ for (int i = commands.size ()-1; i >= 0; i--) {
+ Command command = commands.get (i);
+ command.undo ();
+ command.displayUndo ();
+ }
+ }
+ public String toString () {
+ String result = "";
+ for (Command command : commands)
+ result += " "+command.name;
+ return result;
+ }
+ }
+
+ // ========================================
+ StateNotifier observable;
+ Stack undo = new Stack ();
+ Stack redo = new Stack ();
+
+ public Vector getUndoCmd () {
+ return getCmd (undo);
+ }
+ public Vector getRedoCmd () {
+ return getCmd (redo);
+ }
+ public Vector getCmd (Stack commands) {
+ Vector result = new Vector (commands.size ());
+ for (int i = commands.size () - 1; i >= 0; i--)
+ result.add (commands.get (i).name);
+ return result;
+ }
+
+ public Story (StateNotifier observable) {
+ this.observable = observable;
+ }
+ public void addUpdateObserver (Object object) {
+ observable.addUpdateObserver (object, BroadcastStory);
+ }
+ public void removeObserver (Object object) {
+ observable.removeObserver (object);
+ }
+
+ public void add (Command command) {
+ try {
+ if (command instanceof Commands && ((Commands) command).commands.size () < 1)
+ return;
+ command.exec ();
+ command.displayExec ();
+ undo.push (command);
+ } finally {
+ redo.clear ();
+ observable.broadcastUpdate (BroadcastStory);
+ }
+ };
+
+ // ========================================
+ Command lastSaved;
+ Command lastCommand () {
+ return undo.empty () ? null : undo.peek ();
+ }
+
+ public void markNotSaved () {
+ lastSaved = new Command ("") { public void exec () {} public void undo () {} };
+ observable.broadcastUpdate (BroadcastStory);
+ }
+ public void markSaved () {
+ lastSaved = lastCommand ();
+ observable.broadcastUpdate (BroadcastStory);
+ }
+ public boolean isModified () {
+ return lastSaved != lastCommand ();
+ }
+
+ // ========================================
+ public boolean undoAvailable () {
+ return !undo.empty ();
+ }
+ public boolean redoAvailable () {
+ return !redo.empty ();
+ }
+ public ArrayList getUndoCommande () { return getString (undo); }
+ public ArrayList getRedoCommande () { return getString (redo); }
+ ArrayList getString (Stack stack) {
+ ArrayList result = new ArrayList ();
+ for (Command command : stack)
+ result.add (command.name);
+ return result;
+ }
+
+ // ========================================
+ public void undo (int level) {
+ try {
+ for (int i = 0; i < level; i++) {
+ Command command = undo.pop ();
+ command.undo ();
+ command.displayUndo ();
+ redo.push (command);
+ }
+ } catch (Exception e) {
+ }
+ observable.broadcastUpdate (BroadcastStory);
+ }
+
+ public void redo (int level) {
+ try {
+ for (int i = 0; i < level; i++) {
+ Command command = redo.pop ();
+ command.exec ();
+ command.displayExec ();
+ undo.push (command);
+ }
+ } catch (Exception e) {
+ }
+ observable.broadcastUpdate (BroadcastStory);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/StoryManager.java b/src/java/misc/StoryManager.java
new file mode 100644
index 0000000..61391d1
--- /dev/null
+++ b/src/java/misc/StoryManager.java
@@ -0,0 +1,142 @@
+package misc;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+import javax.swing.AbstractButton;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+
+public class StoryManager implements ApplicationManager, ActionListener {
+
+ // ========================================
+ static public final String
+ actionUndo = "Undo",
+ actionRedo = "Redo";
+ static public final List
+ actionsNames = Arrays.asList (actionUndo, actionRedo);
+ @SuppressWarnings("unchecked")
+ static public final Hashtable actionsMethod =
+ Util.collectMethod (StoryManager.class, actionsNames);
+ public void actionPerformed (ActionEvent e) {
+ Util.actionPerformed (actionsMethod, e, this);
+ }
+ private ArrayList enabledUndoButtons = new ArrayList ();
+ private ArrayList enabledRedoButtons = new ArrayList ();
+
+ // ========================================
+ public void addMenuItem (JMenu... jMenu) {
+ Util.addMenuItem (actionsNames, this, jMenu[0]);
+ }
+ public void addIconButtons (Container... containers) {
+ addListButton (Util.addIconButton (actionUndo, this, containers[0]), true);
+ addListButton (Util.addIconButton (actionRedo, this, containers[0]), false);
+ }
+ public void addListButton (JButton button, boolean undo) {
+ Dimension currentSize = button.getPreferredSize ();
+ button.setLayout (new BorderLayout ());
+ JLabel develop = new JLabel (Util.loadActionIcon ("develop"));
+ Dimension addedSize = develop.getPreferredSize ();
+ button.add (develop, BorderLayout.EAST);
+ currentSize.width += addedSize.width;
+ button.setPreferredSize (currentSize);
+
+ develop.addMouseListener (new MouseAdapter () {
+ public void mousePressed (MouseEvent e) {
+ button.setSelected (false);
+ if (!button.isEnabled () || story == null)
+ return;
+ new JStoryPopup (button, undo, SwingUtilities.convertMouseEvent (develop, e, button).getPoint ());
+ }
+ });
+ }
+
+ @SuppressWarnings ("serial")
+ class JStoryPopup extends JPopupMenu {
+ public JStoryPopup (JButton button, boolean undo, Point pos) {
+ Vector cmds = undo ? story.getUndoCmd () : story.getRedoCmd ();
+ for (int i = 0; i < cmds.size (); i++) {
+ if (i >= 10) {
+ add (new JLabel ("..."));
+ break;
+ }
+ JMenuItem jMenu = new JMenuItem (Bundle.getStory (cmds.get (i)));
+ final int count = i+1;
+ jMenu.addActionListener (new ActionListener () {
+ public void actionPerformed (ActionEvent e) {
+ if (undo)
+ story.undo (count);
+ else
+ story.redo (count);
+ }
+ });
+ add (jMenu);
+ }
+ show (button, pos.x, pos.y);
+ }
+ }
+
+ public void addActiveButtons (Hashtable buttons) {
+ enabledUndoButtons.add (buttons.get (actionUndo));
+ enabledRedoButtons.add (buttons.get (actionRedo));
+ updateActiveButtons ();
+ }
+ public void updateActiveButtons () {
+ updateStory ();
+ }
+
+ public void updateStory () {
+ boolean undo = false, redo = false;
+ if (story != null) {
+ undo = story.undoAvailable ();
+ redo = story.redoAvailable ();
+ }
+ for (AbstractButton button : enabledUndoButtons)
+ button.setEnabled (undo);
+ for (AbstractButton button : enabledRedoButtons)
+ button.setEnabled (redo);
+ }
+
+ public void actionUndo () {
+ if (story == null)
+ return;
+ story.undo (1);
+ }
+
+ public void actionRedo () {
+ if (story == null)
+ return;
+ story.redo (1);
+ }
+
+ // ========================================
+ Story story;
+ public void setStory (Story story) {
+ if (this.story != null)
+ this.story.removeObserver (this);
+ this.story = story;
+ if (story != null)
+ story.addUpdateObserver (this);
+ updateStory ();
+ }
+
+ // public StoryManager () {
+ // }
+
+ // ========================================
+}
diff --git a/src/java/misc/Timer.java b/src/java/misc/Timer.java
new file mode 100644
index 0000000..36654d4
--- /dev/null
+++ b/src/java/misc/Timer.java
@@ -0,0 +1,58 @@
+package misc;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.TimeZone;
+
+public class Timer {
+ // ========================================
+ static public SimpleDateFormat sdf = new SimpleDateFormat ("H:mm:ss.S");
+ static {
+ sdf.setTimeZone (TimeZone.getTimeZone ("GMT"));
+ }
+ class Milestone {
+ String name;
+ long end;
+ long last;
+ Milestone (String name, long end, long last) {
+ this.name = name;
+ this.end = end;
+ this.last = last;
+ }
+ }
+ // ========================================
+ long start = System.currentTimeMillis ();
+ long lastEnd = start;
+
+ ArrayList milestones = new ArrayList ();
+
+ public String getLap (String milestoneName) {
+ long now = System.currentTimeMillis ();
+ long end = now-start;
+ long last = now - lastEnd;
+ lastEnd = now;
+ milestones.add (new Milestone (milestoneName, end, last));
+ return milestoneName+": "+sdf.format (end)+" ("+end+")"+": "+sdf.format (last)+" ("+last+")";
+ }
+
+ public String getNames () {
+ String result = "";
+ for (Milestone milestone : milestones)
+ result += ":"+milestone.name;
+ return result;
+ }
+ public String getEnds () {
+ String result = "";
+ for (Milestone milestone : milestones)
+ result += ":"+sdf.format (milestone.end)+" ("+milestone.end+")";
+ return result;
+ }
+ public String getLasts () {
+ String result = "";
+ for (Milestone milestone : milestones)
+ result += ":"+sdf.format (milestone.last)+" ("+milestone.last+")";
+ return result;
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/Timestamp.java b/src/java/misc/Timestamp.java
new file mode 100644
index 0000000..2afd164
--- /dev/null
+++ b/src/java/misc/Timestamp.java
@@ -0,0 +1,34 @@
+package misc;
+
+public class Timestamp {
+ // ========================================
+ private long changeTimestamp, updateTimestamp;
+ public long[] getValues () { return new long[]{changeTimestamp, updateTimestamp}; }
+
+ // ========================================
+ public void reset () {
+ changeTimestamp = updateTimestamp = System.currentTimeMillis ();
+ }
+
+ // ========================================
+ public void change () {
+ changeTimestamp = System.currentTimeMillis ();
+ }
+
+ // ========================================
+ public void update () {
+ updateTimestamp = System.currentTimeMillis ();
+ }
+
+ // ========================================
+ public boolean isUpdated (Timestamp... others) {
+ if (changeTimestamp > updateTimestamp)
+ return false;
+ for (Timestamp other : others)
+ if (other.updateTimestamp > updateTimestamp)
+ return false;
+ return true;
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/TitledDialog.java b/src/java/misc/TitledDialog.java
new file mode 100644
index 0000000..277ae63
--- /dev/null
+++ b/src/java/misc/TitledDialog.java
@@ -0,0 +1,57 @@
+package misc;
+
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.SwingConstants;
+
+@SuppressWarnings ("serial") public class TitledDialog extends JDialog implements SwingConstants {
+ // ========================================
+ protected String titleId;
+
+ // ========================================
+ public TitledDialog (Frame frame, final String titleId) {
+ super (frame, Bundle.getTitle (titleId), false);
+ this.titleId = titleId;
+ Bundle.addLocalizedDialog (this, titleId);
+ addWindowListener (new WindowAdapter () {
+ public void windowClosing (WindowEvent e) {
+ Util.updateCheckBox (titleId, false);
+ }
+ });
+ boolean visible = Config.getBoolean (titleId+Config.checkedPostfix, false);
+ setVisible (visible);
+ //Util.updateCheckBox (titleId, visible);
+ }
+
+ // ========================================
+ public void setVisible (boolean visible) {
+ // if (visible == isVisible ())
+ // return;
+ super.setVisible (visible);
+ Util.updateCheckBox (titleId, visible);
+ if (visible) {
+ pack ();
+ setLocationRelativeTo (null);
+ Config.loadLocation (titleId, this, getLocation ());
+ toFront ();
+ } else {
+ saveLocation ();
+ }
+ }
+
+ // ========================================
+ public void setJFrame (JFrame jFrame) {
+ setIconImage (jFrame.getIconImage ());
+ }
+
+ // ========================================
+ public void saveLocation () {
+ Config.saveLocation (titleId, this);
+ }
+
+ // ========================================
+}
diff --git a/src/java/misc/ToolBarManager.java b/src/java/misc/ToolBarManager.java
new file mode 100644
index 0000000..39e7dd6
--- /dev/null
+++ b/src/java/misc/ToolBarManager.java
@@ -0,0 +1,462 @@
+package misc;
+
+import java.util.Comparator;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.Vector;
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTable;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+import javax.swing.plaf.basic.BasicButtonUI;
+import javax.swing.table.AbstractTableModel;
+
+import misc.TitledDialog;
+import static misc.Util.GBCNL;
+
+/**
+ ...
+*/
+
+public class ToolBarManager implements ApplicationManager, ActionListener, ContainerListener, SwingConstants {
+
+ // ========================================
+ static public BasicButtonUI buttonUI = new BasicButtonUI ();
+ static public Border buttonBorder = BorderFactory.createEmptyBorder (2, 2, 2, 2);
+
+ static public final String
+ actionUp = "Up",
+ actionDown = "Down",
+ actionToolBarProfil = "ToolBarProfil";
+ static public final List actionsToolBar =
+ Arrays.asList (actionToolBarProfil);
+ @SuppressWarnings("unchecked")
+ static public final Hashtable actionsMethod =
+ Util.collectMethod (ToolBarManager.class, actionsToolBar);
+ public void actionPerformed (ActionEvent e) {
+ try {
+ AbstractButton button = ((AbstractButton) e.getSource ());
+ Component component = toolBarComponent.get (button.getActionCommand ());
+ if (component != null) {
+ if (button.isSelected ())
+ show (component);
+ else
+ hide (component);
+ return;
+ }
+ } catch (Exception e2) {
+ Log.keepLastException ("ToolBarManager::actionPerformed", e2);
+ }
+ Util.actionPerformed (actionsMethod, e, this);
+ }
+ public void addMenuItem (JMenu... jMenu) {
+ Util.addMenuItem (actionsToolBar, this, jMenu[0]);
+ ((MultiToolBarBorderLayout) container.getLayout ()).setMenu (jMenu[0].getParent ());
+ }
+ public void addIconButtons (Container... containers) {
+ Util.addIconButton (actionsToolBar, this, containers[0]);
+ }
+ public void addActiveButtons (Hashtable buttons) {
+ // disable if no toolbar to manage (orderedComponents.size () < 1 => container listener)
+ }
+ // ========================================
+ @SuppressWarnings ("serial") public class TableObjectModel extends AbstractTableModel {
+ public int getColumnCount () { return 2; }
+ public int getRowCount () { return orderedComponents.size (); }
+ public Object getValueAt (int row, int column) {
+ if (row >= orderedComponents.size ())
+ return null;
+ return column == 0 ?
+ orderedComponents.get (row).getParent () != null :
+ Bundle.getTitle (toolBarName.get (orderedComponents.get (row)));
+ }
+ public String getColumnName (int column) {
+ return column == 0 ? Bundle.getLabel ("ToolBarShowed") : Bundle.getLabel ("ToolBarNamed");
+ }
+ public Class> getColumnClass (int column) {
+ return column == 0 ? Boolean.class : String.class;
+ }
+ public boolean isCellEditable (int row, int column) {
+ return column == 0;
+ }
+ public void setValueAt (Object aValue, int row, int column) {
+ if (column > 0 || row >= orderedComponents.size ())
+ return;
+ Component component = orderedComponents.get (row);
+ if ((Boolean) aValue)
+ show (component);
+ else
+ hide (component);
+ }
+ public void move (int delta) {
+ int idx = table.getSelectedRow ();
+ if (idx < 0)
+ return;
+ int mod = orderedComponents.size ();
+ Component old = orderedComponents.remove (idx);
+ idx = (idx+delta+mod) % mod;
+ if (idx == orderedComponents.size ())
+ orderedComponents.add (old);
+ else
+ orderedComponents.add (idx, old);
+ table.revalidate ();
+ table.getSelectionModel ().setLeadSelectionIndex (idx);
+ container.getLayout ().layoutContainer (container);
+ }
+ };
+ TableObjectModel dataObjectModel = new TableObjectModel ();
+ JTable table = new JTable (dataObjectModel);
+ public void actionToolBarProfil () {
+ JPanel panel = new JPanel (new BorderLayout ());
+ panel.add (Util.getJScrollPane (table), BorderLayout.CENTER);
+ JPanel leftPropCmdPanel = new JPanel ();
+ panel.add (leftPropCmdPanel, BorderLayout.SOUTH);
+ leftPropCmdPanel.add (Util.newIconButton (actionUp, new ActionListener () {
+ public void actionPerformed (ActionEvent e) { dataObjectModel.move (-1); }
+ }));
+ leftPropCmdPanel.add (Util.newIconButton (actionDown, new ActionListener () {
+ public void actionPerformed (ActionEvent e) { dataObjectModel.move (+1); }
+ }));
+ Hashtable buttons = Util.collectButtons (null, leftPropCmdPanel);
+ Util.collectButtons (buttons, leftPropCmdPanel);
+ for (AbstractButton button : buttons.values ()) {
+ button.setUI (buttonUI);
+ button.setBorder (buttonBorder);
+ }
+ //table.getTableHeader ().setReorderingAllowed (true);
+ table.setShowHorizontalLines (false);
+ table.setShowVerticalLines (false);
+ table.setRowSelectionAllowed (true);
+ table.setColumnSelectionAllowed (false);
+ table.setSelectionMode (0);
+ Dimension preferredSize = new Dimension (table.getPreferredSize ());
+ preferredSize.height += 40;
+ table.getParent ().getParent ().setPreferredSize (preferredSize);
+ for (int row = 0; row < table.getRowCount (); row++)
+ // check bundle before grab dialog
+ table.getValueAt (row, 1);
+ JOptionPane.showMessageDialog (frame, panel);
+ int i = 0;
+ for (Component component : orderedComponents)
+ Config.setInt (toolBarName.get (component)+"Order", i++);
+ }
+
+ // ========================================
+ /** Les points cardinaux sur lesquels l'orientation des boîtes doit être horizontal. */
+ static final List horizontalCardinal = Arrays.asList (NORTH, SOUTH);
+
+ // ========================================
+ /** receptacle qui accueille les boîtes (doit avoir une mise en forme de type bordure "BorderLayout"). */
+ private Container container;
+ /**
+ * Nom donné à chaque boîte. Ce nom est utilisé comme racine pour trouver des valeur dans la configuration ou l'internationnalisation.
+ * Exemple si le nom est "Horloge" on trouvera dans la configuration :
+ * "HorlogeChecked" (true indiquant que la boîte est visible) et
+ * "HorlogePlace" (East indiquant que la boîte s'attachera à droite)
+ * On trouvera dans le fichier des
+ * "ActionHorloge" associant le texte à la case à cocher ("Montre l'horloge" pour le texte en français)
+ * Enfin un évenement de type "Horloge" pourra être traité par "actionPerformed".
+ */
+ private Hashtable