commit 17dd1fedd2f7feb26cbeec67dbd0c50fe2dd8df3 Author: AdecWatt Date: Mon Jun 18 14:56:04 2018 +0200 First git version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9b03b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +build +distrib +data/cache +data/export +data/local +data/log +data/server/ +!data/server/furniture/000-0052.lpt +texts/help-* +ws/ +!ws/launch-adecWatt.sh +*~ +#* +soft/UpdatedAdecWatt.jar +soft/AdecWatt.jar diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ce78a9 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +AdecWatt +======= + +## Install + +git clone git@framagit.org:adecwatt/adecWatt.git +ant -f ant/build.xml + +## data server + +[adecwatt.parlenet.org](http://adecwatt.parlenet.org/) + +## Organization + +[ADEC 56](http://adec56.org/spip/index.php) + + +## Short MD documentation + +Two spaces at the end of a line +produces a line break. + +Text attributes _italic_, +**bold**, `monospace`. + +Horizontal rule: + +--- + +Bullet list: + + * apples + * oranges + * pears + +Numbered list: + + 1. wash + 2. rinse + 3. repeat + +A [link](http://example.com). + +![Image](Image_icon.png) + +> Markdown uses email-style > characters for blockquoting. + +Inline HTML is supported. diff --git a/ant/build.xml b/ant/build.xml new file mode 100644 index 0000000..9aaa37c --- /dev/null +++ b/ant/build.xml @@ -0,0 +1,335 @@ + + + + + + + + + + + + + Logiciel de plan de feu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AdecWatt source files]]> + http://adecwatt.parlenet.org/]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/config/AdecWatt.xml b/data/config/AdecWatt.xml new file mode 100644 index 0000000..d4eb3ff --- /dev/null +++ b/data/config/AdecWatt.xml @@ -0,0 +1,76 @@ + + + +This file is automaticaly generated by AdecWatt application at 6:18 PM on Jun 17, 2018. + +Day +North + +5 +0 + +4 +true +20180617 +1 +false +true + +false + +North + +true +[x=0,y=31] +North + +[x=0,y=31] + + +true +3 +data/log/ +[x=0,y=31] + + + +true +false +data/images/adecWatt.png + +true +false +/home/felix/perso/adecWatt56/data/export/CendresLampionsChapelleBleue.lpz +North +false + +false + + +false + +2 + + +false +true + +false + + + +true + +true + +North +[x=0,y=31] +North +true + + +true +false + +3128 + diff --git a/data/config/AdecWattUser_br_FR_breton.properties b/data/config/AdecWattUser_br_FR_breton.properties new file mode 100644 index 0000000..5447beb --- /dev/null +++ b/data/config/AdecWattUser_br_FR_breton.properties @@ -0,0 +1,102 @@ +#Produit automatiquement par BundleManager +#Mon Dec 14 15:11:27 CET 2015 +User_fluorescentTube3rgb=FR Tube fluorescent 3 RVB +User_public=FR Public +User_rightDoor=FR Porte droite +User_electrical=Tredan +User_fluorescentTube=FR Tube fluorescent +User_blueprintPos=FR Place du plan +User_pc=PC +User_insee=Kod-INSEE +User_length=Hirder +User_pcSpotFresnelLed=PC Fresnel \u00E0 Led +User_stroboscope=FR Stroboscope +User_par=PAR +User_doubleDoor=FR Porte double +User_performance=Abadenn +User_connectedTo=FR Branch\u00E9 \u00E0 +User_city=FR Commune +User_spot=FR Projecteur +User_powerSupply=FR Alimentation \u00E9lectrique +User_id=Anv implijer +User_building=Savadur +User_height=Sav +User_tubeFluorescent3rgb=FR Tuble fluorescent 3 RVB +User_comment=Displegadenn +User_oval=Ovalek +User_blueprint=Plan +User_dimmer=FR Gradateur +User_photo=Foto +User_rectangle=Reizhkogneg +User_image=Skeudenn +User_filter=FR Filtre +User_powerSocket=FR Prise de courant +User_blueprintVisibility=FR Voir le plan +User_width=Ledander +User_pcMartele=PC Martele +User_note=Notenn +User_accessory=Reizh +User_latitude=Ledenn +User_fogMachine=FR Machine fumig\u00E8ne +User_information=Titour +User_outside=FR Ext\u00E9rieur +User_btSpot=FR Basse tension +User_colorGel=Gelaenn Liv +User_blueprintSize=FR Taille du plan +User_leftDoor=FR Porte gauche +User_catwalk=FR Passerelle +User_powerPlug=FR Fiche \u00E9lectrique +User_lightplot=Plan goulo\u00F9 +User_line=FR Ligne +User_preview=FRAper\u00E7u +User_blueprintCut=Plan a-droc'h +User_pcFresnel=PC Fresnel +User_pcSpotMartele=PC Martele +User_weight=Pouez +User_hmiSpot=HMI +User_inside=FR Int\u00E9rieur +User_longitude=Hedenn +User_tubeFluorescent=FR Tube fluorescent +User_followSpot=FR Poursuite +User_decor=Dekor +User_parSpot=PAR +User_ledSpot=FR Projecteur \u00E0 LED +User_profileSpotS=FR D\u00E9coupe courte +User_simpleSocketPower=Lugell +User_pcSpotFresnel=PC Fresnel +User_pcLed=PC LED +User_profileSpotM=FR D\u00E9coupe moyenne +User_labelProp=Titour a-wel +User_profileSpotL=FR D\u00E9coupe longue +User_size=Stek +User_doublePowerSocket=FR Prise double +User_furniture=Pourviziono\u00F9 +User_color=Liv +User_horiziodeSpot=FR Horiziode +User_rot=Rotadur +User_geopos=Lec'hiadur +User_lowIcon=FR Au sol +User_simplePowerSocket=Lugell +User_shape=FR Forme +User_powerSocketFrame=FR Prise de courant +User_pos=Lec'hiadur +User_pcSpot=PC +User_door=Dor +User_ceilDoubleSocketPower=Lugell e-krec'h +User_type=Seurt +User_perch=Perchenn +User_regie=FR R\u00E9gie +User_scene=FR Sc\u00E8ne +User_address=Chomlec'h +User_profileSpot=FR D\u00E9coupe +User_video=FR Vid\u00E9o +User_poster=Skritell +User_support=Doug +User_ceilSimpleSocketPower=Lugell e-krec'h +User_name=Anv +User_zipCode=Kod-post +User_watt=Watt +User_connectedOn=FR Sur la prise +User_gelat=Gelaenn +User_horiziode=FR Horiziode +User_labelColor=Liv titour diff --git a/data/config/AdecWattUser_br_FR_gallo.properties b/data/config/AdecWattUser_br_FR_gallo.properties new file mode 100644 index 0000000..b00f8aa --- /dev/null +++ b/data/config/AdecWattUser_br_FR_gallo.properties @@ -0,0 +1,102 @@ +#Produit automatiquement par BundleManager +#Mon Dec 14 15:11:27 CET 2015 +User_fluorescentTube3rgb=FR Tube fluorescent 3 RVB +User_public=FR Public +User_rightDoor=FR Porte droite +User_electrical=Electriqe +User_fluorescentTube=FR Tube fluorescent +User_blueprintPos=FR Place du plan +User_pc=PC +User_insee=Code INSEE +User_length=Longhe\u00FBr +User_pcSpotFresnelLed=PC Fresnel \u00E0 Led +User_stroboscope=FR Stroboscope +User_par=PAR +User_doubleDoor=FR Porte double +User_performance=Perzent\u00E9zon +User_connectedTo=FR Branch\u00E9 \u00E0 +User_city=FR Commune +User_spot=Chandelle +User_powerSupply=FR Alimentation \u00E9lectrique +User_id=Identifiant +User_building=B\u00E2timents +User_height=Haote\u00FBr +User_tubeFluorescent3rgb=FR Tuble fluorescent 3 RVB +User_comment=Depllet +User_oval=Fao-rond +User_blueprint=Pllan +User_dimmer=FR Gradateur +User_photo=Foto +User_rectangle=Rectangl +User_image=imaije +User_filter=FR Filtre +User_powerSocket=FR Prise de courant +User_blueprintVisibility=FR Voir le plan +User_width=larje\u00FBr +User_pcMartele=PC Martele +User_note=Note +User_accessory=Afutiaos +User_latitude=Latitude +User_fogMachine=FR Machine fumig\u00E8ne +User_information=Ghiment +User_outside=FR Ext\u00E9rieur +User_btSpot=FR Basse tension +User_colorGel=Jelatine Coulour +User_blueprintSize=FR Taille du plan +User_leftDoor=FR Porte gauche +User_catwalk=FR Passerelle +User_powerPlug=FR Fiche \u00E9lectrique +User_lightplot=Gr\u00E9ment des chandelles +User_line=FR Ligne +User_preview=FR Aper\u00E7u +User_blueprintCut=Pllan de co\u00FBpe +User_pcFresnel=PC Fresnel +User_pcSpotMartele=PC Martele +User_weight=Pou\u00E9z +User_hmiSpot=HMI +User_inside=FR Int\u00E9rieur +User_longitude=longhe\u00FBr +User_tubeFluorescent=FR Tube fluorescent +User_followSpot=FR Poursuite +User_decor=Enterjiets +User_parSpot=PAR +User_ledSpot=FR Projecteur \u00E0 LED +User_profileSpotS=FR D\u00E9coupe courte +User_simpleSocketPower=Prinze de courant +User_pcSpotFresnel=PC Fresnel +User_pcLed=PC LED +User_profileSpotM=FR D\u00E9coupe moyenne +User_labelProp=Ghiment amontr\u00EB +User_profileSpotL=FR D\u00E9coupe longue +User_size=FR Taille +User_doublePowerSocket=FR Prise double +User_furniture=Fourniment +User_color=Coulour +User_horiziodeSpot=FR Horiziode +User_rot=Virement +User_geopos=J\u00E9yo pozition +User_lowIcon=FR Au sol +User_simplePowerSocket=Prinze de courant +User_shape=FR Forme +User_powerSocketFrame=FR Prise de courant +User_pos=Empllacement +User_pcSpot=PC +User_ceilDoubleSocketPower=Prinze de courant dan le doubl +User_door=Porte +User_type=Tipe +User_perch=Percho +User_regie=FR R\u00E9gie +User_scene=FR Sc\u00E8ne +User_address=Aderse +User_profileSpot=FR D\u00E9coupe +User_video=FR Vid\u00E9o +User_support=FR Support +User_poster=Pllacard +User_ceilSimpleSocketPower=Prinze de courant dan le doubl +User_name=Nomer +User_zipCode=Code de la post +User_watt=Watt +User_connectedOn=FR Sur la prise +User_gelat=Jelatine +User_labelColor=Coulour du ghiment +User_horiziode=FR Horiziode diff --git a/data/config/AdecWattUser_en_US.properties b/data/config/AdecWattUser_en_US.properties new file mode 100644 index 0000000..187c14f --- /dev/null +++ b/data/config/AdecWattUser_en_US.properties @@ -0,0 +1,53 @@ +#Produit automatiquement par BundleManager +#Mon Dec 14 15:11:27 CET 2015 +User_accessory=Accessory +User_address=Address +User_blueprint=Blueprint +User_blueprintCut=Blueprint cut +User_building=Building +User_catwalk=Catwalk +User_city=City +User_color=Color +User_colorGel= +User_comment=Comment +User_connectedOn=On +User_connectedTo=To +User_decor=Decor +User_dimmer=Dimmer +User_door=Door +User_doubleDoor= +User_electrical=Electrical +User_furniture=Furniture +User_gelat= +User_geopos=GeoPos +User_height=Height +User_image=Image +User_information=Information +User_insee=INSEE code +User_labelColor=Information color +User_labelProp=Showed information +User_latitude=Latitude +User_length=Length +User_lightplot=Lightplot +User_line=Line +User_longitude=Longitude +User_note=Note +User_oval=Oval +User_perch=Perche +User_performance=Performance +User_photo=Photo +User_pos=Position +User_poster=Poster +User_preview=Preview +User_rectangle=Rectangle +User_rot=Rotation +User_size=Size +User_slot=Slot +User_spot=Projector +User_support=Support +User_tubeFluorescent= +User_type=Type +User_watt=Watt +User_weight=Weight +User_width=Width +User_zipCode=Zip code diff --git a/data/config/AdecWattUser_es_ES.properties b/data/config/AdecWattUser_es_ES.properties new file mode 100644 index 0000000..4092cb7 --- /dev/null +++ b/data/config/AdecWattUser_es_ES.properties @@ -0,0 +1,122 @@ +#Produit automatiquement par BundleManager +#Sun Feb 04 17:02:12 CET 2018 +User_fluorescentTube3rgb=Tubo fluorescente 3 RVB +User_public=P\u00FAblico +User_rightDoor=Puerta a derecha +User_CendresLampionsCity=Cendres et Lampions City +User_electrical=el\u00E9ctrico +User_fluorescentTube=Tubo fluorescente +User_blueprintPos=Localizaci\u00F3n del plano +User_pc=PC +User_insee=C\u00F3digo INSEE +User_length=Largo +User_pcSpotFresnelLed=PC Fresnel LED +User_nezDeScene=Borde del escenario +User_stroboscope=Estroboscopio +User_par=PAR +User_tileSize=Escalabilidad +User_doubleDoor=Puerta dobla +User_accesQuai=Acceso al and\u00E9n +User_performance=Representaci\u00F3n +User_connectedTo=Enchufada +User_city=Municipio +User_spot=Proyector +User_powerSupply=Alimentaci\u00F3n el\u00C3\u00A9ctrica +User_id=Identificador +User_building=Inmobiliario +User_height=Altura +User_tubeFluorescent3rgb=Tubo fluorescente 3 RVB +User_comment=Comentario +User_oval=\u00D3valo +User_blueprint=Plano +User_dimmer=Graduator +User_photo=Foto +User_rectangle=Rect\u00E1ngulo +User_generalPowerSupply=Alimentaci\u00F3n general +User_image=Imagen +User_wall=Pared +User_filter=Filtro +User_powerSocket=Enchufe +User_quai=And\u00E9n +User_blueprintVisibility=Ver el plano +User_slot=Slot +User_width=Anchura +User_pcMartele=PC lentilla martelada +User_marker=Marca +User_note=Nota +User_accessory=Accesorio +User_latitude=Latitud +User_fogMachine=M\u00E1quina fum\u00EDgena +User_information=Informaci\u00F3n +User_outside=Exterior +User_milieuScene=Medio de la escenario +User_btSpot=Baja tensi\u00F3n +User_colorGel=Filtro +User_blueprintSize=Tama\u00F1o del plano +User_leftDoor=Puerta a izquierda +User_powerPlug=Enchufe +User_pendrillon=Cortina +User_catwalk=Pasarela +User_lightplot=Plano de luces +User_preview=Vistazo +User_line=L\u00EDnea +User_blueprintCut=Plano transversal +User_shower=Duchas +User_pcSpotMartele=PC lentilla martelada +User_pcFresnel=PC Fresnel +User_toilet=Ba\u00F1os +User_weight=Peso +User_hmiSpot=HMI +User_inside=Interior +User_longitude=Longitud +User_tubeFluorescent=Tubo fluorescente +User_followSpot=Foco +User_decor=Decoraci\u00F3n +User_parSpot=PAR +User_ledSpot=Proyector LED +User_profileSpotS=Foco corto +User_simpleSocketPower=Enchufe simple +User_pcSpotFresnel=PC Fresnel +User_profileSpotM=Foco medio +User_armchair=Butaca +User_pcLed=PC LED +User_profileSpotL=Foco largo +User_labelProp=Informaci\u00F3n fijada +User_size=Tama\u00F1o +User_step=Escal\u00F3n +User_doublePowerSocket=Enchufe doblo +User_furniture=Mobiliario +User_rot=Rotaci\u00F3n +User_people=Figurante +User_color=Color +User_horiziodeSpot=Horiziode +User_geopos=Geo-posici\u00F3n +User_accesLoges=Acceso a los camerinos +User_lowIcon=Al suelo +User_simplePowerSocket=Enchufe simple +User_shape=Forma +User_powerSocketFrame=Enchufe +User_pos=Posici\u00F3n +User_pcSpot=PC +User_loges=Camerinos +User_ceilDoubleSocketPower=Enchufe simple en el techo +User_door=Puerta +User_type=Tipo +User_perch=P\u00E9rtiga +User_regie=Sala de control +User_scene=Escenario +User_address=Direcci\u00F3n +User_profileSpot=Foco +User_video=Video +User_support=Soporte +User_poster=Cartel +User_ceilSimpleSocketPower=Enchufe simple en el techo +User_alluminiumBridge=Puente aluminio +User_name=Nombre +User_profileSpotXS=Mini Foco +User_zipCode=C\u00F3digo de \u00E1rea +User_watt=Watt +User_connectedOn=en el enchufe +User_gelat=Filtro +User_labelColor=Color del informaci\u00F3n +User_horiziode=horiziode diff --git a/data/config/AdecWattUser_fr_FR.properties b/data/config/AdecWattUser_fr_FR.properties new file mode 100644 index 0000000..a36d1cb --- /dev/null +++ b/data/config/AdecWattUser_fr_FR.properties @@ -0,0 +1,134 @@ +#Produit automatiquement par Bundle +#Tue Feb 13 16:40:00 CET 2018 +User_fluorescentTube3rgb=Tube fluorescent 3 RVB +User_style=Style +User_public=Public +User_rightDoor=Porte droite +User_CendresLampionsCity=Cendres et Lampions City +User_electrical=Electrique +User_fluorescentTube=Tube fluorescent +User_blueprintPos=Place du plan +User_pc=PC +User_mark=Marqueur +User_insee=Code INSEE +User_length=Longueur +User_pcSpotFresnelLed=PC Fresnel \u00E0 Led +User_nezDeScene=Nez de sc\u00E8ne +User_stroboscope=Stroboscope +User_par=PAR +User_tileSize=Tuillage +User_doubleDoor=Porte double +User_accesQuai=Acc\u00E8s quai +User_performance=Repr\u00E9sentation +User_connectedTo=Branch\u00E9 \u00E0 +User_city=Commune +User_spot=Projecteur +User_building=Immobilier +User_id=Identifiant +User_powerSupply=Alimentation \u00E9lectrique +User_height=Hauteur +User_tubeFluorescent3rgb=Tuble fluorescent 3 RVB +User_oval=Ovale +User_comment=Commentaire +User_blueprint=Plan +User_dimmer=Gradateur +User_photo=Photo +User_limite=Limite +User_rectangle=Rectangle +User_generalPowerSupply=Alimentation g\u00E9n\u00E9rale +User_image=Image +User_filter=Filtre +User_wall=Mur +User_powerSocket=Prise de courant +User_quai=Quai +User_blueprintVisibility=Voir le plan +User_width=Largeur +User_labelSize=Taille de police +User_default=Defaut +User_pcMartele=PC Martele +User_marker=Marqueur +User_note=Note +User_accessory=Accessoire +User_latitude=Latitude +User_fogMachine=Machine fumig\u00E8ne +User_information=Information +User_end=Fin +User_outside=Ext\u00E9rieur +User_milieuScene=Milieu sc\u00E8ne +User_colorGel=G\u00E9latine +User_btSpot=Basse tension +User_blueprintSize=Taille du plan +User_leftDoor=Porte gauche +User_powerPlug=Fiche \u00E9lectrique +User_catwalk=Passerelle +User_pendrillon=Pendrillon +User_lightplot=Plan de Feu +User_preview=Aper\u00E7u +User_line=Ligne +User_blueprintCut=Plan de coupe +User_shower=Douche +User_pcFresnel=PC Fresnel +User_pcSpotMartele=PC Martele +User_dimension=Cote +User_toilet=Toillet +User_weight=Poids +User_hmiSpot=HMI +User_inside=Int\u00E9rieur +User_longitude=Longitude +User_tubeFluorescent=Tube fluorescent +User_followSpot=Poursuite +User_decor=D\u00E9cor +User_parSpot=PAR +User_translation=Translation +User_ledSpot=Projecteur \u00E0 LED +User_profileSpotS=D\u00E9coupe courte +User_pcSpotFresnel=PC Fresnel +User_simpleSocketPower=Prise simple +User_angleDistance=Angle Distance +User_armchair=Fauteuil +User_pcLed=PC LED +User_profileSpotM=D\u00E9coupe moyenne +User_labelProp=Info affich\u00E9e +User_profileSpotL=D\u00E9coupe longue +User_size=Taille +User_step=Marche +User_doublePowerSocket=Prise double +User_furniture=Mobilier +User_people=Figurant +User_horiziodeSpot=Horiziode +User_color=Couleur +User_rot=Rotation +User_geopos=G\u00E9oPosition +User_accesLoges=Acc\u00E8s loges +User_lowIcon=Au sol +User_simplePowerSocket=Prise simple +User_shape=Forme +User_powerSocketFrame=Prise de courant +User_angle=Angle +User_pos=Position +User_loges=Loges +User_pcSpot=PC +User_begin=D\u00E9but +User_ceilDoubleSocketPower=Prise simple au plafond +User_door=Porte +User_type=Type +User_distance=Distance +User_perch=Perche +User_regie=R\u00E9gie +User_scene=Sc\u00E8ne +User_address=Adresse +User_profileSpot=D\u00E9coupe +User_video=Vid\u00E9o +User_support=Support +User_poster=Affiche +User_ceilSimpleSocketPower=Prise simple au plafond +User_alluminiumBridge=Pont aluminium +User_name=Nom +User_profileSpotXS=Mini D\u00E9coupe +User_zipCode=Code postal +User_watt=Watt +User_connectedOn=Sur la prise +User_arrow=Fl\u00E8che +User_gelat=Gelatine +User_labelColor=Couleur de l'info +User_horiziode=Horiziode diff --git a/data/config/AdecWatt_br_FR_breton.properties b/data/config/AdecWatt_br_FR_breton.properties new file mode 100644 index 0000000..055ce8d --- /dev/null +++ b/data/config/AdecWatt_br_FR_breton.properties @@ -0,0 +1,187 @@ +#Produit automatiquement par BundleManager +#Tue Jan 30 16:35:11 CET 2018 +LabelHelp-br_fr_breton=FR Aide en Breton +ActionTag=FR Etiquette +ActionFurnitureManager=FR Concepteur de mobilier +ActionCut=Troc\u2019ha\u00F1 +LabelHelp-br_fr_gallo=FR Aide en Gallo +LabelData=Dataenno\u00F9 +StoryAddSpinProp=Lakaat un adsked ouzhpenn +EditTitle=\ Edita\u00F1 +ActionShowItem=FR Montre +ActionRemove=Dilemel +StoryChangeBuilding=Che\u00F1ch savadur +ActionRemoveItem=Dilemel +ActionNewUnit=Nevez +EnumPropTypeEnumBuilding=Savadur +ActionSelectAll=Choaz holl +ActionCopyUnit=Duplika\u00F1 +ActionStageManager=FR R\u00E9gisseur +LabelWatt=Watt +EnumPropTypeEnumSquare=Gorread +LabelProperty=Perzh +ActionChangeRole=FR Changer de r\u00F4le... +ActionHorizontalRight=Steuda\u00F1 a-zehou +ActionVerticalDistrib=Ingali\u00F1 (a-serzh) +StoryRemoveLabels=FR Supprime \u00E9tiquette +MessageQuitJAdecWatt=Dilezel ar c\u2019hemmo\u00F9 ? +ActionLinguist=FR Linguiste +ChangeRoleTitle=\ Ra vo an Nerzh ganit \! +EnumPropTypeEnumGeo=Lec\u2019hia\u00F1 +ActionDataManager=FR Gardien du serveur +LabelLine=FR Ligne +YodaTitle=\ Yoda +MessageGiveSpace=FR Distance (homog\u00E8ne par d\u00E9faut) +ActionCircuit=FR Affiche les circuits +ActionExportPDF=FR Exporte en PDF +ActionPatch=FR "Patch" Ligne/Circuit +ActionMandatory=Ranket +MessageConnectionSucceeded=FR Connexion r\u00E9ussie +StoryPasteItem=Pega\u00F1 elfenn +LabelHelp-fr_fr=FR Aide en fran\u00E7ais +LabelSoft=Poellad +ActionHorizontalLeft=Steuda\u00F1 a-gleiz +LabelCircuit=FR Circuit +MessageChangeRole=Dont da merer +LabelDST=Editor +ActionYoda=Yoda +ActionVerticalBottom=Steuda\u00F1 an trao\u00F1 +ManualTitle=\ Ar dornlevr AdecWatt +ActionExport=FR Exporter... +StoryResizeComp=FR Dimensionne composant +LabelIcons=FR Icons +ActionTransformItem=Troi\u00F1 +LabelPassword=FR Mot de passe +StoryTransform=Treuzfurmadur +ActionAddPatch=FR Ajoute le "Patch" Ligne/Circuit +ActionModifyAcc=Kemma\u00F1 +StoryChangeLabels=Che\u00F1ch tikedenn +ActionPaste=Pega\u00F1 +ActionHidden=Kuzhet +StoryRemoveAcc=FR Supprime acc\u00E9ssoire +ActionErase=Disfasa\u00F1 +EnumPropTypeEnumIcon=Ikon +ActionRemoveUnit=Dilemel +ActionNoFilter=Ignore +ActionSetEnum=Fiksa\u00F1 ar choazio\u00F9 +ActionRemoveAcc=Dilemel +TransformTitle=\ Treuzfurmadur +LabelId=FR Identifiant +ActionFilter=Filtre +ActionImport=Emporzhia\u00F1... +EnumPropTypeEnumEnum=Choazio\u00F9 +LabelShortcut=FR Court-circuit +MessageWelcome=Degemer mat \!\nBremanaat ar poellad. +LabelHelp-en_us=FR Aide en anglais +EnumPropTypeEnumNumber=Niver +ActionAdd=Lakaat ouzhpenn +ActionLandscape=FR Paysage +ActionCopy=Kopia\u00F1 +ActionConnection=FR Connexion +LabelCircuitless=FR Sans circuit +ActionDataStructuresManager=FR Concepteur de donn\u00E9es +LabelTest=FR Test +StoryMoveItem=Diblasamant +StoryRemoveProp=Dilemel tikedenn +ActionWizard=FR Tu ne veux pas savoir \! +ActionClose=Serri\u00F1 +ActionModifyItem=Kemma\u00F1 +ActionPageSetup=Reolia\u00F1 ar moullerez... +ActionLock=Morailh +ActionDisplayItem=Diskouez +StoryLinkItem=FR Lie composant +StoryConnectAcc=FR Connecte acc\u00E9ssoire +SelectImageTitle=\ Choaz ur skeudenn +LabelLogin=FR Nom de connexion +SliderTitle=\ FR Echelle & Fondu +ActionPrint=FR Imprimer... +ActionLocalized=Etrebroadel +ActionServerName=FR Nom du server +StoryAddAcc=FR Ajoute acc\u00E9ssoire +ActionCrossfades=FR Fondu +StoryAddProp=Ajout propri\u00E9t\u00E9 +ActionTurnLeft=FR Tourne \u00E0 gauche +EnumPropTypeEnumCity=FR Commune +EnumPropTypeEnumArticle=FR Article +LabelType=Seurt +LabelImages=FR Images +LayoutTitle=FR Mise en page +ActionRemoveZone=FR Supprime la zone +LabelExportFilter=Document (.lpz) +StoryOrderedProp=FR R\u00E9organisation +ActionTransformUnit=Troi\u00F1 +ActionRemoveImage=Dilemel +ActionAddZone=FR ajoute une zone +StoryChangeSpin=Che\u00F1ch adsked +StoryLinkAcc=FR Lie acc\u00E9ssoire +StorySelectItem=FR Selectionne composant +ActionAddPoster=FR Ajoute l\u2019affiche +StoryChangeParent=FR Change de mod\u00E8le +StoryChangeEnum=Che\u00F1ch niveridigezh +ActionValidate=FR Pr\u00E9pare au t\u00E9l\u00E9verssement +StoryRemoveEnum=FR Supprime \u00E9num\u00E9ration +MessageConnectionFailed=FR Echecs de connexion +ActionRenameUnit=FR Renomer +ActionRestart=Adkregi\u00F1 +ActionNomouse=FR Modification sans souris +ActionHorizontalCenter=Steuda\u00F1 e kreiz +ActionCloseAll=Serri\u00F1 holl +ActionSearch=FR Recherche +ActionScale=FR Echelle +ActionManual=Dornlevr implij... +StoryChangeType=Che\u00F1ch seurt +EnumPropTypeEnumImage=Skeudenn +ActionTurnRight=FR Tourne \u00E0 droite +LabelHelp-images=FR Images d\u2019aide +PlacementTitle=\ Arenkamant +LabelSRC=FR Mod\u00E8le +ActionTestedServer=FR version de test +StoryClearProp=Dilemel perzh +ActionCopyItem=Duplika\u00F1 +ActionUnchange=FR Pas de changement +StoryRemoveItem=FR Supprime composant +EnumPropTypeEnumPreview=FR Aper\u00E7u +ActionArchitect=FR Architecte +ActionVisitor=FR Visiteur +LabelHelp-es_es=FR Aide en espagnol +StoryLinkEmb=FR Lie composant/acc\u00E9ssoire +StoryRotItem=Troi\u00F1 +ActionModifyUnit=Kemma\u00F1 +ActionRemoveWorkspace=Dilemel +MessagePromoteConfirmation=FR Voulez-vous pr\u00E9parer le t\u00E9l\u00E9versement de l\u2019\u00E9l\u00E9ment \: {0} ({1}) ? +ActionVerticalTop=Steuda\u00F1 e-krec\u2019h +ActionAddProp=Lakaat ur perzh ouzhpenn +ActionVerticalCenter=Steuda\u00F1 e kreiz +ActionDisplayUnit=Diskouez +LabelHelpOSM=FR D\u00E9placement \: click droit | Zoom \: double click gauche ou molette +LabelUnplug=FR Non connect\u00E9 +StoryCloneItem=FR Clone composant +StoryAddItem=Lakaat ur komponant ouzhpenn +ActionTransformAcc=Troi\u00F1 +MessageMixName=FR plusieurs noms +ActionHorizontalSpace=Lakaat spas (a-led) +StoryChangeModifiers=Che\u00F1ch perzhegezh +LabelUnits=FR Composants +ActionPortrait=FR Portrait +ActionDisplayAcc=Diskouez +ActionHttpServer=FR Protocole HTTP +ActionLocalServer=FR Server web local +AdecWattStillRunningTitle=\ Kemmo\u00F9 nann-enrollet +StoryChangeName=Che\u00F1ch anv +AdecWattTitle=\ AdecWatt (Stalier \: {0} / Orjalenn \: {1}) +MessageMixId=FR plusieurs ref\u00E9rences +SearchTitle=\ FR Recherche +ActionHorizontalDistrib=Ingali\u00F1 (a-led) +StoryChangeValue=Disfasa\u00F1 ar talvoud +ActionHorizontalSpin=Eilpenn horizontalek +ActionChangeImage=Kemm +ActionVerticalSpace=Lakaat spas (a-serzh) +StoryEdit=Che\u00F1ch +MessageRemoveConfirmation=Dilemel an elfenn \: {0} ({1}) ? +MessageGiveName=Anv nevez \: +LabelImageFilter=Skeudenn (.gif .jpg .jpeg .png .tif .tiff .bmp) +ActionPromoteUnit=FR Pr\u00EAt au t\u00E9l\u00E9versement +EnumPropTypeEnumCube=Volum +ActionPlotCity=FR Place le centre ville +EnumPropTypeEnumText=FR Texte +ActionHideItem=FR Cache diff --git a/data/config/AdecWatt_br_FR_gallo.properties b/data/config/AdecWatt_br_FR_gallo.properties new file mode 100644 index 0000000..388ffbe --- /dev/null +++ b/data/config/AdecWatt_br_FR_gallo.properties @@ -0,0 +1,190 @@ +#Produit automatiquement par BundleManager +#Tue Jan 30 16:35:11 CET 2018 +LabelHelp-br_fr_breton=FR Aide en Breton +ActionTag=FR Etiquette +ActionFurnitureManager=FR Concepteur de mobilier +ActionCut=Cae\u00FBper +LabelHelp-br_fr_gallo=FR Aide en Gallo +LabelData=Don\u00E9es +StoryAddSpinProp=Revoure +EditTitle=\ Bani +ActionShowItem=FR Montre +ActionRemove=Aboli +StoryChangeBuilding=Chanjerie b\u00E2timents +ActionRemoveItem=Aboli +ActionNewUnit=Nouviao +EnumPropTypeEnumBuilding=B\u00E2timents +ActionSelectAll=Tout prendr +ActionCopyUnit=Fere des aotants +ActionStageManager=FR R\u00E9gisseur +LabelWatt=Watt +EnumPropTypeEnumSquare=Grandou +LabelProperty=Merche +ActionChangeRole=FR Changer de r\u00F4le... +ActionHorizontalRight=Enligner de la drete +ActionVerticalDistrib=D\u00E9roler +StoryRemoveLabels=Tirer l\u2019etiqhette +MessageQuitJAdecWatt=Voul\u2019ous mettr a bas tous les chanjements +ActionLinguist=FR Linguiste +ChangeRoleTitle=\ Qe la force seije qant\u00EB tai +EnumPropTypeEnumGeo=Empllacement +ActionDataManager=FR Gardien du serveur +LabelLine=FR Ligne +LabelHelp-gallo=FR Aide en Gallo +YodaTitle=\ Yoda +MessageGiveSpace=FR Distance (homog\u00E8ne par d\u00E9faut) +ActionCircuit=FR Affiche les circuits +ActionExportPDF=FR Exporte en PDF +ActionPatch=FR "Patch" Ligne/Circuit +ActionMandatory=Oblij\u00EB +MessageConnectionSucceeded=FR Connexion r\u00E9ussie +StoryPasteItem=Paisse amare +LabelSoft=Lojici\u00EB +ActionHorizontalLeft=Enligner de la gaoche +LabelCircuit=FR Circuit +MessageChangeRole=Deveni menou +LabelDST=Banissou +ActionYoda=Yoda +ActionVerticalBottom=Enligner d\u2019abas +ManualTitle=\ Ghide du gr\u00E9ment des chandelles +ActionExport=FR Exporter... +StoryResizeComp=FR Dimensionne composant +LabelIcons=FR Icons +ActionTransformItem=Amorfozer +LabelPassword=FR Mot de passe +StoryTransform=Amorfoze +ActionAddPatch=FR Ajoute le "Patch" Ligne/Circuit +ActionModifyAcc=Chanjer +StoryChangeLabels=Chanjerie etiqhette +ActionPaste=Paisser +ActionHidden=Qhut\u00EB +StoryRemoveAcc=FR Supprime acc\u00E9ssoire +LabelCircuiless= +ActionErase=Aboli +EnumPropTypeEnumIcon=Icon +ActionRemoveUnit=Aboli +ActionNoFilter=Ignore +ActionSetEnum=Fet les chou\u00E8z +ActionRemoveAcc=Aboli +TransformTitle=\ Amorfoze +LabelId=FR Identifiant +ActionFilter=Filtre +ActionImport=Mettr a veni +EnumPropTypeEnumEnum=Chou\u00E8z +LabelShortcut=FR Court-circuit +MessageWelcome=Bonevenue Cmencer par abuter le lojici\u00EB\n +EnumPropTypeEnumNumber=Nombr +ActionAdd=Met ao bout +ActionLandscape=FR Paysage +ActionCopy=Fere un doubl +ActionConnection=FR Connexion +LabelCircuitless=FR Sans circuit +ActionDataStructuresManager=FR Concepteur de donn\u00E9es +LabelTest=FR Test +StoryMoveItem=Depllacer +StoryRemoveProp=Tirer une merche +ActionWizard=FR Tu ne veux pas savoir \! +ActionClose=Cllore +ActionModifyItem=Chanjer +ActionPageSetup=Param\u00E8trer la moulou\u00E8re +ActionLock=Crouille +LabelHelp-fr=FR Aide en fran\u00E7ais +ActionDisplayItem=Amontr\u00EB +StoryLinkItem=FR Lie composant +StoryConnectAcc=FR Connecte acc\u00E9ssoire +SelectImageTitle=\ Elouter une imaije +LabelLogin=FR Nom de connexion +SliderTitle=\ FR Echelle & Fondu +ActionPrint=FR Imprimer... +ActionLocalized=Langaije +ActionServerName=FR Nom du server +StoryAddAcc=FR Ajouter accessoire +ActionCrossfades=FR Fondu +StoryAddProp=Ajouter une merche +ActionTurnLeft=FR Tourne \u00E0 gauche +EnumPropTypeEnumCity=FR Commune +EnumPropTypeEnumArticle=FR Article +LabelType=Tipe +LabelImages=FR Images +LayoutTitle=FR Mise en page +ActionRemoveZone=FR Supprime la zone +LabelExportFilter=FR Document (.lpz) +StoryOrderedProp=FR R\u00E9organisation +LabelHelp-en= +ActionTransformUnit=Amorfozer +ActionRemoveImage=Aboli +ActionAddZone=FR ajoute une zone +StoryChangeSpin=Chanjerie revoure +StoryLinkAcc=FR Lie acc\u00E9ssoire +StorySelectItem=FR Selectionne composant +ActionAddPoster=FR Ajoute l\u2019affiche +StoryChangeParent=FR Change de mod\u00E8le +StoryChangeEnum=Chanjerie d\u00E9bornement +ActionValidate=FR Pr\u00E9pare au t\u00E9l\u00E9verssement +StoryRemoveEnum=FR Supprime \u00E9num\u00E9ration +MessageConnectionFailed=FR Echecs de connexion +ActionRenameUnit=FR Renomer +ActionRestart=Erpaisser tout +ActionNomouse=FR Modification sans souris +ActionHorizontalCenter=Enligner du mitan +ActionCloseAll=Cllore tout +ActionSearch=FR Recherche +ActionScale=FR Echelle +ActionManual=Ghide d\u2019uzaije... +StoryChangeType=Chanje de tipe +EnumPropTypeEnumImage=Imaije +ActionTurnRight=FR Tourne \u00E0 droite +LabelHelp-images=FR Images d\u2019aide +PlacementTitle=\ Pllacement +LabelSRC=FR Mod\u00E8le +ActionTestedServer=FR version de test +StoryClearProp=Aboli une merche +ActionCopyItem=Fere des aotants +ActionUnchange=FR Pas de changement +StoryRemoveItem=FR Supprime composant +EnumPropTypeEnumPreview=FR Aper\u00E7u +ActionVisitor=FR Visiteur +ActionArchitect=FR Architecte +LabelHelp-es_es=FR Aide en espagnol +StoryLinkEmb=FR Lie composant/acc\u00E9ssoire +StoryRotItem=Vire +ActionModifyUnit=Chanjer +ActionRemoveWorkspace=Aboli +MessagePromoteConfirmation=FR Voulez-vous pr\u00E9parer le t\u00E9l\u00E9versement de l\u2019\u00E9l\u00E9ment \: {0} ({1}) ? +ActionVerticalTop=Enligner du haot +ActionAddProp=Mettr en pus une merche +ActionVerticalCenter=Enligner du mitan +ActionDisplayUnit=Amontr\u00EB +LabelHelpOSM=Depllacement \: clic de drete par de\u00FBz fais |\u00A0Zoum\u00A0\: (double) clic\u00A0ou ben rouellette +LabelUnplug=FR Non connect\u00E9 +StoryCloneItem=FR Clone composant +StoryAddItem=Ajouter un morc\u00E8 +ActionTransformAcc=Amorfozer +MessageMixName=FR plusieurs noms +ActionHorizontalSpace=Eg\u00E2iller +StoryChangeModifiers=Chanjerie qalification +LabelUnits=FR Composants +ActionPortrait=FR Portrait +ActionDisplayAcc=Amontr\u00EB +ActionHttpServer=FR Protocole HTTP +ActionLocalServer=FR Server web local +AdecWattStillRunningTitle=\ Chanjements pas encrouill\u00EBs +StoryChangeName=Chanjerie de nom +AdecWattTitle=Gr\u00E9ment des chandelles (Atelier \: {0} / Fil \: {1}) +MessageMixId=FR plusieurs ref\u00E9rences +SearchTitle=\ FR Recherche +ActionHorizontalDistrib=D\u00E9roler +StoryChangeValue=Change de valeur +ActionHorizontalSpin=D\u00E9tourner orizonta +ActionChangeImage=Chanjer +ActionVerticalSpace=Eg\u00E2iller +StoryEdit=Chanjements +MessageRemoveConfirmation=Voul\u2019ous mettr a bas l\u2019element \: {0} ({1}) ? +MessageGiveName=Ernomer \: +LabelImageFilter=Imaije (.gif .jpg .jpeg .png .tif .tiff .bmp) +ActionPromoteUnit=FR Pr\u00EAt au t\u00E9l\u00E9versement +LabelHelp-breton= +EnumPropTypeEnumCube=Qhubaije +ActionPlotCity=FR Place le centre ville +EnumPropTypeEnumText=FR Texte +ActionHideItem=FR Cache diff --git a/data/config/AdecWatt_en_US.properties b/data/config/AdecWatt_en_US.properties new file mode 100644 index 0000000..e7114ca --- /dev/null +++ b/data/config/AdecWatt_en_US.properties @@ -0,0 +1,197 @@ +#Produit automatiquement par BundleManager +#Tue Jan 30 16:35:11 CET 2018 +LabelHelp-br_fr_breton=Breton Help +ActionTag=Tag +ActionFurnitureManager=Funiture manager +ActionCut=Cut +LabelHelp-br_fr_gallo=Gallo Help +LabelData=Data +StoryAddSpinProp=Add spin +EditTitle=\ Edit +ActionShowItem=Show +ActionRemove=Remove +StoryChangeBuilding=Change building +ActionRemoveItem=Remove +ActionNewUnit=New +EnumPropTypeEnumBuilding=Building +ActionSelectAll=Select all +ActionCopyUnit=Duplicated +ActionStageManager=Stage manager +LabelWatt=Watt +EnumPropTypeEnumSquare=Square +LabelProperty=Property +ActionChangeRole=Change role... +ActionHorizontalRight=Right align +ActionVerticalDistrib=Distribute (vertical) +StoryRemoveLabels=Remove label +MessageQuitJAdecWatt=Forget all changes? +ActionLinguist=Linguist +ChangeRoleTitle=\ The force will be with you\! +EnumPropTypeEnumGeo=Localization +ActionDataManager=Data manager +LabelLine=Line +YodaTitle=\ Yoda +MessageGiveSpace=Distance (default homogeneous) +ActionCircuit=Show the circuits +ActionExportPDF=PDF Export +ActionPatch=Patch Line/Circuit +ActionMandatory=Mandatory +MessageConnectionSucceeded=Connection succeeded +StoryPasteItem=Paste componant +LabelHelp-fr_fr=French Help +LabelSoft=Software +ActionHorizontalLeft=Left align +LabelCircuit=Circuit +MessageChangeRole="Power comes with responsability."\n\nAre-you ready? +LabelDST=Editor +ActionYoda=Yoda +ActionVerticalBottom=Bottom align +ManualTitle=\ The AdecWatt manual +ActionExport=Export... +StoryResizeComp=Resize composant +LabelIcons=Icons +ActionTransformItem=Transform +LabelPassword=Password +StoryTransform=Transform +ActionAddPatch=Add patch +ActionModifyAcc=Modify +StoryChangeLabels=Change label +ActionPaste=Paste +ActionHidden=Hidden +StoryRemoveAcc=Remove accessory +ActionErase=Erase +EnumPropTypeEnumIcon=Icon +ActionRemoveUnit=Remove +ActionNoFilter=Ignore +ActionSetEnum=Set choice +ActionRemoveAcc=Remove +TransformTitle=\ Transforme +LabelId=Identifier +ActionFilter=Filter +ActionImport=Import... +EnumPropTypeEnumEnum=Choice +LabelShortcut=Shortcut +MessageWelcome=Welcome\!\nStart with software update procedure\n +LabelHelp-en_us=Help +EnumPropTypeEnumNumber=Number +ActionAdd=Add +ActionLandscape=Landscape +ActionCopy=Copy +ActionConnection=Connection +LabelCircuitless=Ciruitless +ActionDataStructuresManager=Data structures manager +LabelTest=Test +StoryMoveItem=Move componant +StoryRemoveProp=Remove property +ActionWizard=You do want to not know\! +ActionClose=Close +ActionModifyItem=Modify +ActionPageSetup=Page setup... +ActionLock=Lock +ActionDisplayItem=Display +StoryLinkItem=Link componant +StoryConnectAcc=Connect accessory +SelectImageTitle=\ Select an image +LabelLogin=Login +SliderTitle=\ Scale & Crossfades +ActionPrint=Print... +ActionLocalized=Localization +ActionServerName=Server name +StoryAddAcc=Add accessory +ActionCrossfades=Crossfades +StoryAddProp=Add propri\u00E9t\u00E9 +ActionTurnLeft=Turn left +EnumPropTypeEnumCity=City +EnumPropTypeEnumArticle=Article +LabelType=Type +LabelImages=Images +LayoutTitle=Layout +ActionRemoveZone=Remove zone +LabelExportFilter=Document (.lpz) +StoryOrderedProp=Ordered +ActionTransformUnit=Transform +ActionRemoveImage=Remove +ActionAddZone=Add zone +StoryChangeSpin=Change spin +StoryLinkAcc=Link accessory +StorySelectItem=Select composant +ActionAddPoster=Add poster +StoryChangeParent=change parent +StoryChangeEnum=Change enum +ActionValidate=Ready to upload +StoryRemoveEnum=Remove enum +MessageConnectionFailed=Connection failed +ActionRenameUnit=Rename +ActionRestart=Restart all +ActionNomouse=Change without mouse +ActionHorizontalCenter=Center align +ActionCloseAll=Close all +ActionSearch=Search +ActionScale=Scale +ActionManual=User guide... +StoryChangeType=CHange type +EnumPropTypeEnumImage=Image +ActionTurnRight=Turn right +LabelHelp-images=Help Images +PlacementTitle=\ Placement +LabelSRC=Template +ActionTestedServer=tested version +StoryClearProp=Clear value +ActionCopyItem=Duplicated +ActionUnchange=No modification +StoryRemoveItem=Remove componant +EnumPropTypeEnumPreview=Preview +ActionArchitect=Architect +ActionVisitor=Visitor +LabelHelp-es_es=Spain Help +StoryLinkEmb=Link componant/accessory +StoryRotItem=Rotation +ActionModifyUnit=Modify +ActionRemoveWorkspace=Remove +MessagePromoteConfirmation=Do-you want to prepared uploading of element\: {0} (in {1})? +ActionVerticalTop=Top align +ActionAddProp=Add property +ActionVerticalCenter=Middle align +ActionDisplayUnit=Display +LabelHelpOSM=Move\: right mouse button | Zoom\: left double click or mouse wheel +LabelUnplug=Unplug +StoryCloneItem=Clone componant +StoryAddItem=Add componant +ActionTransformAcc=Transform +MessageMixName=mix name +ActionHorizontalSpace=Space (horizontal) +StoryChangeModifiers=Change modifier +LabelUnits=Components +ActionPortrait=Portrait +ActionDisplayAcc=Display +ActionHttpServer=Http protocol +ActionLocalServer=Local web server +AdecWattStillRunningTitle=\ Unrecorded changes +StoryChangeName=Change name +AdecWattTitle=\ AdecWatt (Workspace \: {0} / Thread \: {1}) +MessageMixId=mix id +SearchTitle=\ Search +ActionHorizontalDistrib=Distribute (horizontal) +StoryChangeValue=Change value +ActionHorizontalSpin=Horizontal spin +ActionChangeImage=Change +ActionVerticalSpace=Space (vertical) +StoryEdit=Edit +MessageRemoveConfirmation=Do-you want to remove the element\: {0} (in {1})? +MessageGiveName=New name\: +LabelImageFilter=Image (.gif .jpg .jpeg .png .tif .tiff .bmp) +ActionPromoteUnit=Ready for upload +EnumPropTypeEnumCube=Volume +ActionPlotCity=Move to city +EnumPropTypeEnumText=Text +ActionHideItem=Hide +ActionBoundGlue=Bounding glue +ActionGridGlue=Grid glue +ActionHandleGlue=Handler glue +ActionMagnetPolicies=Magnet Policies... +LabelBoundGlue=Bounding glue +LabelGridGlue=Grid glue +LabelHandleGlue=Handler glue +MagnetPoliciesTitle=\ Magnet Policies +LabelInSegmentGlue=Only border (no lines) +ActionInSegmentGlue=Only border (no lines) diff --git a/data/config/AdecWatt_es_ES.properties b/data/config/AdecWatt_es_ES.properties new file mode 100644 index 0000000..d4f3b10 --- /dev/null +++ b/data/config/AdecWatt_es_ES.properties @@ -0,0 +1,255 @@ +#Produit automatiquement par BundleManager +#Sun Feb 04 16:52:03 CET 2018 +AboutTitle=A prop\u00F3sito de +ActionAbout=A prop\u00F3sito de +ActionAdd=A\u00F1ade +ActionAddPatch=A\u00F1ade el "Patch" L\u00EDn\u00E9a/circuito +ActionAddPoster=A\u00F1ade el cartel +ActionAddProp=A\u00F1ade una propiedad +ActionAddZone=A\u00F1ade una \u00E1rea +ActionArchitect=Arquitecto +ActionBugReport=Depuraci\u00F3n +ActionChangeImage=Cambiar +ActionChangeRole=Cambiar de funci\u00F3n +ActionCircuit=Muestra los circuitos +ActionClear=Borrar +ActionClose=Cerrar +ActionCloseAll=Cerrar todos +ActionConnection=Conexi\u00F3n +ActionCopy=Copiar +ActionCopyItem=Duplicar +ActionCopyUnit=Duplicar +ActionCrossfades=Mezclar +ActionCut=Cortar +ActionDataManager=Guardi\u00E1n de los datos +ActionDataStructuresManager=Dise\u00F1ador de los datos +ActionDetails=Detalles +ActionDisplayAcc=Fijar +ActionDisplayItem=Fijar +ActionDisplayUnit=Fijar +ActionDown=Abajo +ActionDownload=Descarga +ActionEmpty=Nuevo +ActionErase=Borrar +ActionExport=Exportar +ActionExportPDF=Exporta en PDF +ActionFilter=Filtra +ActionForcePack=Ajusta la ventana +ActionFurnitureManager=Dise\u00F1ador de mobiliario +ActionHidden=Escondido +ActionHideItem=Esconde +ActionHorizontalCenter=Alinear en el centro +ActionHorizontalDistrib=Repartir (horizontal) +ActionHorizontalLeft=Alinear a la izquierda +ActionHorizontalRight=Alinear a la derecha +ActionHorizontalSpace=Espaciar (horizontal) +ActionHorizontalSpin=Volteada horizontalmente +ActionHttpServer=Protocolo HTTP +ActionImport=Importar +ActionJConsole=Consola +ActionLandscape=Orientaci\u00F3n de p\u00E1gina horizontal +ActionLicence=Licencia +ActionLinguist=Ling\u00FCista +ActionLoadMessage=Carga el mensaje \u2026 +ActionLocalRemove=Limpiar los archives locales +ActionLocalServer=Servidor Web Local +ActionLocale=Idioma +ActionLocalized=Internacionalizaci\u00F3n +ActionLock=Cerrojo +ActionMandatory=Obligatorio +ActionManual=Manual de utilizaci\u00F3n +ActionManualConfigProxy=especificar manualmente las opciones del proxy +ActionModifyAcc=Modificar +ActionModifyItem=Modificar +ActionModifyUnit=Modificar +ActionNewUnit=Nuevo +ActionNoFilter=Ignora +ActionNoProxy=No utilizar proxy +ActionNomouse=Modificaci\u00F3n sin el rat\u00F3n +ActionOnline=Puesta en l\u00EDnea +ActionOpen=Abrir +ActionPageSetup=Definir par\u00E1metros la impresora +ActionPaste=Pegar +ActionPatch="Patch" L\u00EDnea / Circuito +ActionPlotCity=Se sit\u00FAa sobre el centro ciudad +ActionPortrait=Orientaci\u00F3n de p\u00E1gina vertical +ActionPrint=Imprimir +ActionPromoteUnit=De pr\u00E9stamo a la carga +ActionQuit=Dejar +ActionRedo=Repetir +ActionRemoteRemove=Limpiar los archivos remotos +ActionRemove=Suprimir +ActionRemoveAcc=Suprimir +ActionRemoveImage=Suprimir +ActionRemoveItem=Suprimir +ActionRemoveUnit=Suprimir +ActionRemoveWorkspace=Suprimir +ActionRemoveZone=Suprime la \u00E1rea +ActionRenameUnit=Renombrar +ActionRestart=Comenzar de nuevo +ActionSave=Salveguardar +ActionSaveAll=Salveguardar todo +ActionSaveAs=Salveguardar como +ActionScale=Escala +ActionSearch=B\u00FAsqueda +ActionSelectAll=Seleccionar todo +ActionServerName=Nombre del servidor +ActionSetEnum=Establece las opciones +ActionSetProxy=Configuraci\u00F3n de red +ActionShowItem=Muestra +ActionStageManager=Administrador +ActionSystemConfigProxy=Utilizar la configuraci\u00F3n Java VM del proxy +ActionTag=Etiqueta +ActionTestedServer=versi\u00F3n de prueba +ActionToolBarProfil=Gesti\u00F3n de las barras de herramientas... +ActionTransformAcc=Transformar +ActionTransformItem=Transformar +ActionTransformUnit=Transformar +ActionTurnLeft=Gira a la izquierda +ActionTurnRight=Gira a la derecha +ActionUnchange=no modificaci\u00F3n +ActionUndo=Deshacer +ActionUp=Arriba +ActionUpdate=Actualizaci\u00F3n +ActionUpload=Cargar +ActionValidate=De ppr\u00E9stamo a la carga +ActionVerticalBottom=Alinear abajo +ActionVerticalCenter=Alinear al centro +ActionVerticalDistrib=Repartir (vertical) +ActionVerticalSpace=Espaciar (vertical) +ActionVerticalTop=Alinear arriba +ActionVisitor=Visitante +ActionWizard=No quieres saber\! +ActionYoda=Yoda +AdecWattStillRunningTitle=\ Cambios sin guardar +AdecWattTitle=\ AdecWatt (Esudio \: {0} /Hilo\: {1}) +AlreadyRegistredTool=Barra de herramientas {0} ya registrada en {1} \! +ChangeLocaleTitle=\ Cambio de idioma +ChangeRoleTitle=\ Qu\u00E9 la fuerza sea contigo\! +DetailsTitle=Detalles +DownloadTitle=Descarga de las actualizaciones +DumpTitle=Elecci\u00F3n de un archivo dump +EditTitle=Editar +EnumCheckPeriodDay=D\u00EDa +EnumCheckPeriodMonth=Mes +EnumCheckPeriodNoCheck=Nunca +EnumCheckPeriodWeek=Semana +EnumCheckPeriodYear=A\u00F1o +EnumPropTypeEnumArticle=Art\u00CDculo +EnumPropTypeEnumBuilding=Inmobiliario +EnumPropTypeEnumCity=Municipio +EnumPropTypeEnumCube=Volumen +EnumPropTypeEnumEnum=Selecci\u00F3n +EnumPropTypeEnumGeo=Localizaci\u00F3n +EnumPropTypeEnumIcon=Icono +EnumPropTypeEnumImage=Imagen +EnumPropTypeEnumNumber=N\u00FAmero +EnumPropTypeEnumPreview=Vistazo +EnumPropTypeEnumSquare=Superficie +EnumPropTypeEnumText=Texto +FileTitle=Archivo +HelpTitle=Ayuda +JConsoleTitle=Consola Java +LabelCheckingPeriod=Veriverificaci\u00F3n de las actualizaciones +LabelCircuit=Circuito +LabelCircuitless=Sin circuito +LabelDST=Editor +LabelData=Datos +LabelDownload=Descargado +LabelDumpFilter=Archivo Log +LabelExportFilter=Documento (.lpz) +LabelFileName=Archivo +LabelHelp-br_fr_breton=Ayuda en Bret\u00F3n +LabelHelp-br_fr_gallo=Ayuda en Gallo +LabelHelp-en_us=Ayuda en Ingl\u00E9s +LabelHelp-fr_fr=Ayuda en Franc\u00E9s +LabelHelp-images=Imagenes de la Ayuda +LabelHelpOSM=Desplazamiento\: clic derecho | Zoom\: Dobla clic izquierdo o rueda del rat\u00C3\u00B3n +LabelHost=Servidor proxy +LabelIcons=Iconos +LabelId=Identificar +LabelImageFilter=Imagen (.gif .jpg .jpeg .png .tif .tiff .bmp) +LabelImages=Imagenes +LabelLine=L\u00EDnea +LabelLocal=Local +LabelLocalDate=Data local +LabelLocalSize=Tama\u00F1o local +LabelLogin=Nombre de conexi\u00F3n +LabelPassword=Contrase\u00F1a +LabelPort=Puerto de proxy +LabelProperty=Propiedad +LabelRemote=Remoto +LabelRemoteDate=Data Remoto +LabelRemoteSize=Tama\u00F1o Remoto +LabelRemove=Borrado +LabelSRC=M\u00F3dulo +LabelShortcut=Cortocircuito +LabelSoft=Software +LabelTest=Test +LabelToolBarNamed=Barra de herramientas +LabelToolBarShowed=Ense\u00F1a +LabelType=Tipo +LabelUnits=Componente +LabelUnplug=No conectado +LabelUpload=Cargado +LabelWatt=Watt +LayoutTitle=\ Dise\u00F1o +LicenceTitle=\ Licencia +LocalizedTitle=\ Internacionalizaci\u00F3n +ManualTitle=\ Manual AdecWatt +MessageChangeRole="Los grandes poderes imponen una gran sabidur\u00EDa."\\n\\n "\u00BF Est\u00E1s listo?" +MessageChooseLocale=Selecciona unidioma +MessageConnectionFailed=Inicio de sesi\u00F3n fallido +MessageConnectionSucceeded=cconexi\u00F3n exitosa +MessageDownload=Descarga +MessageGiveName=Nuevo nombre\u00A0\: +MessageGiveSpace=Distancia (hohomog\u00E9neo por defecto) +MessageMixId=Varias referencias +MessageMixName=varios nombres +MessagePromoteConfirmation=\u00BF Quiere preparar la carga del elemento\: {0} (in {1})? +MessageQuitJAdecWatt=\u00BF Quiere abandonar todas las modificaciones? +MessageRemoveConfirmation=\u00BF Quiere suprimir el elemento\: {0} (in {1})? +MessageUpload=Carga +MessageUploadCompleted={0,choice,0\# Ningunacarga|0< {0} archivos cargados} +MessageWelcome=\u00A1 Bienvenida\! Comience con la actualizaci\u00F3n del software Para realizar modificaciones, habr\u00E1 que cambiar de funci\u00F3n. +NotCardinalPoint=\u00A1 {0} no es un punto cardinal \! +PlacementTitle=Disposici\u00F3n +ProxyTitle=Configuraci\u00F3n de red (Proxy) +SearchTitle=\ Busqueda +SelectImageTitle=\ Seleccionar una imagen +SliderTitle=\ Escala y mezclar +StoryAddAcc=A\u00F1ade accesorio +StoryAddItem=A\u00F1ade componente +StoryAddProp=A\u00F1ade propiedad +StoryAddSpinProp=A\u00F1ade reflejo +StoryChangeBuilding=Cambiar inmobiliario +StoryChangeEnum=Cambiar enumeraci\u00F3n +StoryChangeLabels=Cambiar etiqueta +StoryChangeModifiers=Cambiar modificar +StoryChangeName=Cambiar nombre +StoryChangeParent=Cambiar padre +StoryChangeSpin=Cambiar reflejo +StoryChangeType=Cambiar tipo +StoryChangeValue=Cambiar valor +StoryClearProp=Borra la valor +StoryCloneItem=Clonar componente +StoryConnectAcc=Conectar accesorio +StoryEdit=Modificaci\u00F3n +StoryLinkAcc=Ata accesorio +StoryLinkEmb=Ata componenteaccesorio +StoryLinkItem=Ata componente +StoryMoveItem=Desplazamiento +StoryOrderedProp=reorganisaci\u00F3n +StoryPasteItem=Pega componente +StoryRemoveAcc=Suprime accesorio +StoryRemoveEnum=Suprime enumeraci\u00F3n +StoryRemoveItem=Suprime componente +StoryRemoveLabels=Suprime etiqueta +StoryRemoveProp=Suprime propiedad +StoryResizeComp=Dimensiona componente +StoryRotItem=Rotaci\u00F3n +StorySelectItem=Selecciona componente +StoryTransform=Transformaci\u00C3\u00B3n +TransformTitle=\ Transforma +UploadTitle=Carga +YodaTitle=\ Yoda diff --git a/data/config/AdecWatt_fr_FR.properties b/data/config/AdecWatt_fr_FR.properties new file mode 100644 index 0000000..40f0e5f --- /dev/null +++ b/data/config/AdecWatt_fr_FR.properties @@ -0,0 +1,197 @@ +#Produit automatiquement par BundleManager +#Tue Jan 30 16:35:11 CET 2018 +LabelHelp-br_fr_breton=Aide en Breton +ActionTag=Etiquette +ActionFurnitureManager=Concepteur de mobilier +ActionCut=Couper +LabelHelp-br_fr_gallo=Aide en Gallo +LabelData=Donn\u00E9es +StoryAddSpinProp=Ajout reflet +EditTitle=\ Editer +ActionShowItem=Montre +ActionRemove=Supprime +StoryChangeBuilding=Change immobilier +ActionRemoveItem=Supprimer +ActionNewUnit=Nouveau +EnumPropTypeEnumBuilding=Immobilier +ActionSelectAll=Tout s\u00E9lectionner +ActionCopyUnit=Dupliquer +ActionStageManager=R\u00E9gisseur +LabelWatt=Watt +EnumPropTypeEnumSquare=Surface +LabelProperty=Propri\u00E9t\u00E9 +ActionChangeRole=Changer de r\u00F4le... +ActionHorizontalRight=Aligner \u00E0 droite +ActionVerticalDistrib=R\u00E9partir (vertical) +StoryRemoveLabels=Supprime \u00E9tiquette +MessageQuitJAdecWatt=Voulez-vous abandonner toutes les modifications ? +ActionLinguist=Linguiste +ChangeRoleTitle=\ Que la force soit avec toi \! +EnumPropTypeEnumGeo=G\u00E9olocalis\u00E9 +ActionDataManager=Gardien du serveur +LabelLine=Ligne +YodaTitle=\ Yoda +MessageGiveSpace=Distance (homog\u00E8ne par d\u00E9faut) +ActionCircuit=Affiche les circuits +ActionExportPDF=Exporte en PDF +ActionPatch="Patch" Ligne/Circuit +ActionMandatory=Obligatoire +MessageConnectionSucceeded=Connexion r\u00E9ussie +StoryPasteItem=Colle composant +LabelHelp-fr_fr=Aide en fran\u00E7ais +LabelSoft=Logiciel +ActionHorizontalLeft=Aligner \u00E0 gauche +LabelCircuit=Circuit +MessageChangeRole="De grands pouvoirs imposent une grande sagesse."\n\nEs-tu pr\u00EAt ?\n +LabelDST=\u00C9diteur +ActionYoda=Yoda +ActionVerticalBottom=Aligner en bas +ManualTitle=\ Le manuel AdecWatt +ActionExport=Exporter... +StoryResizeComp=Dimensionne composant +LabelIcons=Icons +ActionTransformItem=Transformer +LabelPassword=Mot de passe +StoryTransform=M\u00E9tamorphose +ActionAddPatch=Ajoute le "Patch" Ligne/Circuit +ActionModifyAcc=Modifier +StoryChangeLabels=Change \u00E9tiquette +ActionPaste=Coller +ActionHidden=Cach\u00E9 +StoryRemoveAcc=Supprime acc\u00E9ssoire +ActionErase=Efface +EnumPropTypeEnumIcon=Icon +ActionRemoveUnit=Supprimer +ActionNoFilter=Ignore +ActionSetEnum=fixe les choix +ActionRemoveAcc=Supprimer +TransformTitle=\ Transforme +LabelId=Identifiant +ActionFilter=Filtre +ActionImport=Importer... +EnumPropTypeEnumEnum=Choix +LabelShortcut=Court-circuit +MessageWelcome=Bienvenue \!\nCommencez par la mise \u00E0 jour du logiciel.\nPour r\u00E9aliser des modifications, il faudra changer de r\u00F4le. +LabelHelp-en_us=Aide en anglais +EnumPropTypeEnumNumber=Nombre +ActionAdd=Ajoute +ActionLandscape=Paysage +ActionCopy=Copier +ActionConnection=Connexion +LabelCircuitless=Sans circuit +ActionDataStructuresManager=Concepteur de donn\u00E9es +LabelTest=Test +StoryMoveItem=D\u00E9placement +StoryRemoveProp=Supprime propri\u00E9t\u00E9 +ActionWizard=Tu ne veux pas savoir \! +ActionClose=Fermer +ActionModifyItem=Modifier +ActionPageSetup=Param\u00E8trer l\u2019imprimante... +ActionLock=Verrou +ActionDisplayItem=Afficher +StoryLinkItem=Lie composant +StoryConnectAcc=Connecte acc\u00E9ssoire +SelectImageTitle=\ S\u00E9lectionnez une image +LabelLogin=Nom de connexion +SliderTitle=\ Echelle & Fondu +ActionPrint=Imprimer... +ActionLocalized=Internationalisation +ActionServerName=Nom du server +StoryAddAcc=Ajoute acc\u00E9ssoire +ActionCrossfades=Fondu +StoryAddProp=Ajout propri\u00E9t\u00E9 +ActionTurnLeft=Tourne \u00E0 gauche +EnumPropTypeEnumCity=Commune +EnumPropTypeEnumArticle=Article +LabelType=Type +LabelImages=Images +LayoutTitle=\ Mise en page +ActionRemoveZone=Supprime la zone +LabelExportFilter=Document (.lpz) +StoryOrderedProp=R\u00E9organisation +ActionTransformUnit=Transformer +ActionRemoveImage=Supprimer +ActionAddZone=Ajoute une zone +StoryChangeSpin=Change de reflet +StoryLinkAcc=Lie acc\u00E9ssoire +StorySelectItem=Selectionne composant +ActionAddPoster=Ajoute l\u2019affiche +StoryChangeParent=Change de mod\u00E8le +StoryChangeEnum=Change \u00E9num\u00E9ration +ActionValidate=Pr\u00E9pare au t\u00E9l\u00E9verssement +StoryRemoveEnum=Supprime \u00E9num\u00E9ration +MessageConnectionFailed=Echecs de connexion +ActionRenameUnit=Renomer +ActionRestart=Tout recommencer +ActionNomouse=Modification sans souris +ActionHorizontalCenter=Aligner au centre +ActionCloseAll=Tous fermer +ActionSearch=Recherche +ActionScale=Echelle +ActionManual=Manuel d\u2019utilisation... +StoryChangeType=Change de type +EnumPropTypeEnumImage=Image +ActionTurnRight=Tourne \u00E0 droite +LabelHelp-images=Images d\u2019aide +PlacementTitle=\ Disposition +LabelSRC=Mod\u00E8le +ActionTestedServer=version de test +StoryClearProp=Efface la valeur +ActionCopyItem=Dupliquer +ActionUnchange=Pas de changement +StoryRemoveItem=Supprime composant +EnumPropTypeEnumPreview=Aper\u00E7u +ActionArchitect=Architecte +ActionVisitor=Visiteur +LabelHelp-es_es=Aide en espagnol +StoryLinkEmb=Lie composant/acc\u00E9ssoire +StoryRotItem=Tourne +ActionModifyUnit=Modifier +ActionRemoveWorkspace=Supprimer +MessagePromoteConfirmation=Voulez-vous pr\u00E9parer le t\u00E9l\u00E9versement de l\u2019\u00E9l\u00E9ment \: {0} ({1}) ? +ActionVerticalTop=Aligner en haut +ActionAddProp=Ajouter une propri\u00E9t\u00E9 +ActionVerticalCenter=Aligner au milieu +ActionDisplayUnit=Afficher +LabelHelpOSM=D\u00E9placement \: click droit | Zoom \: double click gauche ou molette +LabelUnplug=Non connect\u00E9 +StoryCloneItem=Clone composant +StoryAddItem=Ajout composant +ActionTransformAcc=Transformer +MessageMixName=plusieurs noms +ActionHorizontalSpace=Espacer (horizontal) +StoryChangeModifiers=Change de qualification +LabelUnits=Composants +ActionPortrait=Portrait +ActionDisplayAcc=Afficher +ActionHttpServer=Protocole HTTP +ActionLocalServer=Server web local +AdecWattStillRunningTitle=\ Modifications non enregistr\u00E9s +StoryChangeName=Change de nom +AdecWattTitle=\ AdecWatt (Atelier \: {0} / Fil \: {1}) +MessageMixId=plusieurs ref\u00E9rences +SearchTitle=\ Recherche +ActionHorizontalDistrib=R\u00E9partir (horizontal) +StoryChangeValue=Change de valeur +ActionHorizontalSpin=Retournement horizontal +ActionChangeImage=Changer +ActionVerticalSpace=Espacer (vertical) +StoryEdit=Modification +MessageRemoveConfirmation=Voulez-vous supprimer l\u2019\u00E9l\u00E9ment \: {0} ({1}) ? +MessageGiveName=Nouveau nom \: +LabelImageFilter=Image (.gif .jpg .jpeg .png .tif .tiff .bmp) +ActionPromoteUnit=Pr\u00EAt au t\u00E9l\u00E9versement +EnumPropTypeEnumCube=Volume +ActionPlotCity=Place le centre ville +EnumPropTypeEnumText=Texte +ActionHideItem=Cache +ActionBoundGlue=Bordures aimant\u00E9es +ActionGridGlue=Grille aimant\u00E9es +ActionHandleGlue=Poign\u00E9es aimant\u00E9es +ActionMagnetPolicies=Strat\u00E9gies d\u0027aimantation... +LabelBoundGlue=Bordures aimant\u00E9es +LabelGridGlue=Grille aimant\u00E9e +LabelHandleGlue=Poign\u00E9es aimant\u00E9es +MagnetPoliciesTitle=\ Strat\u00E9gies d\u0027aimantation +LabelInSegmentGlue=Bordures uniquement (pas les lignes) +ActionInSegmentGlue=Bordures uniquement (pas les lignes) 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_US.properties b/data/config/RemoteUpdate_en_US.properties new file mode 100644 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_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_FR.properties b/data/config/RemoteUpdate_fr_FR.properties new file mode 100644 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/images/2017-festival-adec56.gif b/data/images/2017-festival-adec56.gif new file mode 100644 index 0000000..4e7a88d Binary files /dev/null and b/data/images/2017-festival-adec56.gif differ diff --git a/data/images/2017-festival-adec56.png b/data/images/2017-festival-adec56.png new file mode 100644 index 0000000..864926f Binary files /dev/null and b/data/images/2017-festival-adec56.png differ diff --git a/data/images/adecWatt-anim-noel.gif b/data/images/adecWatt-anim-noel.gif new file mode 100644 index 0000000..84d7422 Binary files /dev/null and b/data/images/adecWatt-anim-noel.gif differ diff --git a/data/images/adecWatt-anim.gif b/data/images/adecWatt-anim.gif new file mode 100644 index 0000000..542aeb9 Binary files /dev/null and b/data/images/adecWatt-anim.gif differ diff --git a/data/images/adecWatt.png b/data/images/adecWatt.png new file mode 100644 index 0000000..b12bf63 Binary files /dev/null and b/data/images/adecWatt.png differ diff --git a/data/images/button/Add.png b/data/images/button/Add.png new file mode 100644 index 0000000..a956a80 Binary files /dev/null and b/data/images/button/Add.png differ diff --git a/data/images/button/AddPatch.png b/data/images/button/AddPatch.png new file mode 100644 index 0000000..e7a1f5d Binary files /dev/null and b/data/images/button/AddPatch.png differ diff --git a/data/images/button/AddPoster.png b/data/images/button/AddPoster.png new file mode 100644 index 0000000..23f4a12 Binary files /dev/null and b/data/images/button/AddPoster.png differ diff --git a/data/images/button/AddProp.png b/data/images/button/AddProp.png new file mode 100644 index 0000000..eefb01e Binary files /dev/null and b/data/images/button/AddProp.png differ diff --git a/data/images/button/AddZone.png b/data/images/button/AddZone.png new file mode 100644 index 0000000..a956a80 Binary files /dev/null and b/data/images/button/AddZone.png differ diff --git a/data/images/button/Architect.png b/data/images/button/Architect.png new file mode 100644 index 0000000..607f562 Binary files /dev/null and b/data/images/button/Architect.png differ diff --git a/data/images/button/ArchitectOff.png b/data/images/button/ArchitectOff.png new file mode 100644 index 0000000..26614be Binary files /dev/null and b/data/images/button/ArchitectOff.png differ diff --git a/data/images/button/ArchitectOn.png b/data/images/button/ArchitectOn.png new file mode 100644 index 0000000..607f562 Binary files /dev/null and b/data/images/button/ArchitectOn.png differ diff --git a/data/images/button/BreakIcon.png b/data/images/button/BreakIcon.png new file mode 100644 index 0000000..05cf6b0 Binary files /dev/null and b/data/images/button/BreakIcon.png differ diff --git a/data/images/button/ChangeRole.png b/data/images/button/ChangeRole.png new file mode 100644 index 0000000..20d7103 Binary files /dev/null and b/data/images/button/ChangeRole.png differ diff --git a/data/images/button/CircuitOff.png b/data/images/button/CircuitOff.png new file mode 100644 index 0000000..c7f56c8 Binary files /dev/null and b/data/images/button/CircuitOff.png differ diff --git a/data/images/button/CircuitOn.png b/data/images/button/CircuitOn.png new file mode 100644 index 0000000..5186a53 Binary files /dev/null and b/data/images/button/CircuitOn.png differ diff --git a/data/images/button/Close.png b/data/images/button/Close.png new file mode 100644 index 0000000..50f2b94 Binary files /dev/null and b/data/images/button/Close.png differ diff --git a/data/images/button/CloseAll.png b/data/images/button/CloseAll.png new file mode 100644 index 0000000..bd9a56e Binary files /dev/null and b/data/images/button/CloseAll.png differ diff --git a/data/images/button/Copy.png b/data/images/button/Copy.png new file mode 100644 index 0000000..54eaf77 Binary files /dev/null and b/data/images/button/Copy.png differ diff --git a/data/images/button/Cut.png b/data/images/button/Cut.png new file mode 100644 index 0000000..f4a55e3 Binary files /dev/null and b/data/images/button/Cut.png differ diff --git a/data/images/button/DataManager.png b/data/images/button/DataManager.png new file mode 100644 index 0000000..cfa89ea Binary files /dev/null and b/data/images/button/DataManager.png differ diff --git a/data/images/button/DataManagerOff.png b/data/images/button/DataManagerOff.png new file mode 100644 index 0000000..12e33ff Binary files /dev/null and b/data/images/button/DataManagerOff.png differ diff --git a/data/images/button/DataManagerOn.png b/data/images/button/DataManagerOn.png new file mode 100644 index 0000000..cfa89ea Binary files /dev/null and b/data/images/button/DataManagerOn.png differ diff --git a/data/images/button/DataStructuresManager.png b/data/images/button/DataStructuresManager.png new file mode 100644 index 0000000..c70960e Binary files /dev/null and b/data/images/button/DataStructuresManager.png differ diff --git a/data/images/button/DataStructuresManagerOff.png b/data/images/button/DataStructuresManagerOff.png new file mode 100644 index 0000000..7695a10 Binary files /dev/null and b/data/images/button/DataStructuresManagerOff.png differ diff --git a/data/images/button/DataStructuresManagerOn.png b/data/images/button/DataStructuresManagerOn.png new file mode 100644 index 0000000..c70960e Binary files /dev/null and b/data/images/button/DataStructuresManagerOn.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/EmptyIcon.png b/data/images/button/EmptyIcon.png new file mode 100644 index 0000000..2b8166f Binary files /dev/null and b/data/images/button/EmptyIcon.png differ diff --git a/data/images/button/Erase.png b/data/images/button/Erase.png new file mode 100644 index 0000000..b8853fb Binary files /dev/null and b/data/images/button/Erase.png differ diff --git a/data/images/button/EraseOff.png b/data/images/button/EraseOff.png new file mode 100644 index 0000000..b8853fb Binary files /dev/null and b/data/images/button/EraseOff.png differ diff --git a/data/images/button/EraseOn.png b/data/images/button/EraseOn.png new file mode 100644 index 0000000..f123942 Binary files /dev/null and b/data/images/button/EraseOn.png differ diff --git a/data/images/button/Export.png b/data/images/button/Export.png new file mode 100644 index 0000000..3b8784b Binary files /dev/null and b/data/images/button/Export.png differ diff --git a/data/images/button/ExportPDF.png b/data/images/button/ExportPDF.png new file mode 100644 index 0000000..ad6a39f Binary files /dev/null and b/data/images/button/ExportPDF.png differ diff --git a/data/images/button/Filter.png b/data/images/button/Filter.png new file mode 100644 index 0000000..9cabc5a Binary files /dev/null and b/data/images/button/Filter.png differ diff --git a/data/images/button/FurnitureManager.png b/data/images/button/FurnitureManager.png new file mode 100644 index 0000000..682c312 Binary files /dev/null and b/data/images/button/FurnitureManager.png differ diff --git a/data/images/button/FurnitureManagerOff.png b/data/images/button/FurnitureManagerOff.png new file mode 100644 index 0000000..2b9e1b6 Binary files /dev/null and b/data/images/button/FurnitureManagerOff.png differ diff --git a/data/images/button/FurnitureManagerOn.png b/data/images/button/FurnitureManagerOn.png new file mode 100644 index 0000000..682c312 Binary files /dev/null and b/data/images/button/FurnitureManagerOn.png differ diff --git a/data/images/button/HiddenOff.png b/data/images/button/HiddenOff.png new file mode 100644 index 0000000..00903d2 Binary files /dev/null and b/data/images/button/HiddenOff.png differ diff --git a/data/images/button/HiddenOn.png b/data/images/button/HiddenOn.png new file mode 100644 index 0000000..d4058b8 Binary files /dev/null and b/data/images/button/HiddenOn.png differ diff --git a/data/images/button/HorizontalCenter.png b/data/images/button/HorizontalCenter.png new file mode 100644 index 0000000..6d03050 Binary files /dev/null and b/data/images/button/HorizontalCenter.png differ diff --git a/data/images/button/HorizontalDistrib.png b/data/images/button/HorizontalDistrib.png new file mode 100644 index 0000000..22d7c23 Binary files /dev/null and b/data/images/button/HorizontalDistrib.png differ diff --git a/data/images/button/HorizontalLeft.png b/data/images/button/HorizontalLeft.png new file mode 100644 index 0000000..91d9c5e Binary files /dev/null and b/data/images/button/HorizontalLeft.png differ diff --git a/data/images/button/HorizontalRight.png b/data/images/button/HorizontalRight.png new file mode 100644 index 0000000..886f1ab Binary files /dev/null and b/data/images/button/HorizontalRight.png differ diff --git a/data/images/button/HorizontalSpace.png b/data/images/button/HorizontalSpace.png new file mode 100644 index 0000000..404c74f Binary files /dev/null and b/data/images/button/HorizontalSpace.png differ diff --git a/data/images/button/HorizontalSpin.png b/data/images/button/HorizontalSpin.png new file mode 100644 index 0000000..c9e0ecf Binary files /dev/null and b/data/images/button/HorizontalSpin.png differ diff --git a/data/images/button/HorizontalSpinOff.png b/data/images/button/HorizontalSpinOff.png new file mode 100644 index 0000000..f142557 Binary files /dev/null and b/data/images/button/HorizontalSpinOff.png differ diff --git a/data/images/button/HorizontalSpinOn.png b/data/images/button/HorizontalSpinOn.png new file mode 100644 index 0000000..c9e0ecf Binary files /dev/null and b/data/images/button/HorizontalSpinOn.png differ diff --git a/data/images/button/Image.png b/data/images/button/Image.png new file mode 100644 index 0000000..da61192 Binary files /dev/null and b/data/images/button/Image.png differ diff --git a/data/images/button/Import.png b/data/images/button/Import.png new file mode 100644 index 0000000..0a391d6 Binary files /dev/null and b/data/images/button/Import.png differ diff --git a/data/images/button/Landscape.png b/data/images/button/Landscape.png new file mode 100644 index 0000000..c395ab9 Binary files /dev/null and b/data/images/button/Landscape.png differ diff --git a/data/images/button/Linguist.png b/data/images/button/Linguist.png new file mode 100644 index 0000000..8a2085f Binary files /dev/null and b/data/images/button/Linguist.png differ diff --git a/data/images/button/LinguistOff.png b/data/images/button/LinguistOff.png new file mode 100644 index 0000000..98e2802 Binary files /dev/null and b/data/images/button/LinguistOff.png differ diff --git a/data/images/button/LinguistOn.png b/data/images/button/LinguistOn.png new file mode 100644 index 0000000..8a2085f Binary files /dev/null and b/data/images/button/LinguistOn.png differ diff --git a/data/images/button/LocalizedOff.png b/data/images/button/LocalizedOff.png new file mode 100644 index 0000000..9f3aa16 Binary files /dev/null and b/data/images/button/LocalizedOff.png differ diff --git a/data/images/button/LocalizedOn.png b/data/images/button/LocalizedOn.png new file mode 100644 index 0000000..77ea807 Binary files /dev/null and b/data/images/button/LocalizedOn.png differ diff --git a/data/images/button/LockOff.png b/data/images/button/LockOff.png new file mode 100644 index 0000000..0857aaa Binary files /dev/null and b/data/images/button/LockOff.png differ diff --git a/data/images/button/LockOn.png b/data/images/button/LockOn.png new file mode 100644 index 0000000..ac2fd6f Binary files /dev/null and b/data/images/button/LockOn.png differ diff --git a/data/images/button/MandatoryOff.png b/data/images/button/MandatoryOff.png new file mode 100644 index 0000000..09952e9 Binary files /dev/null and b/data/images/button/MandatoryOff.png differ diff --git a/data/images/button/MandatoryOn.png b/data/images/button/MandatoryOn.png new file mode 100644 index 0000000..95950c6 Binary files /dev/null and b/data/images/button/MandatoryOn.png differ diff --git a/data/images/button/Manual.png b/data/images/button/Manual.png new file mode 100644 index 0000000..70911ef Binary files /dev/null and b/data/images/button/Manual.png differ diff --git a/data/images/button/MixIcon.png b/data/images/button/MixIcon.png new file mode 100644 index 0000000..3673bba Binary files /dev/null and b/data/images/button/MixIcon.png differ diff --git a/data/images/button/NewBuilding.png b/data/images/button/NewBuilding.png new file mode 100644 index 0000000..36ce140 Binary files /dev/null and b/data/images/button/NewBuilding.png differ diff --git a/data/images/button/NewLightPlot.png b/data/images/button/NewLightPlot.png new file mode 100644 index 0000000..36ce140 Binary files /dev/null and b/data/images/button/NewLightPlot.png differ diff --git a/data/images/button/NoFilter.png b/data/images/button/NoFilter.png new file mode 100644 index 0000000..5196d43 Binary files /dev/null and b/data/images/button/NoFilter.png differ diff --git a/data/images/button/NomouseOff.png b/data/images/button/NomouseOff.png new file mode 100644 index 0000000..87db6bf Binary files /dev/null and b/data/images/button/NomouseOff.png differ diff --git a/data/images/button/NomouseOn.png b/data/images/button/NomouseOn.png new file mode 100644 index 0000000..c89e35f Binary files /dev/null and b/data/images/button/NomouseOn.png differ diff --git a/data/images/button/PageSetup.png b/data/images/button/PageSetup.png new file mode 100644 index 0000000..aae8a14 Binary files /dev/null and b/data/images/button/PageSetup.png differ diff --git a/data/images/button/Paste.png b/data/images/button/Paste.png new file mode 100644 index 0000000..3f71b1c Binary files /dev/null and b/data/images/button/Paste.png differ diff --git a/data/images/button/Patch.png b/data/images/button/Patch.png new file mode 100644 index 0000000..950999e Binary files /dev/null and b/data/images/button/Patch.png differ diff --git a/data/images/button/PlotCity.png b/data/images/button/PlotCity.png new file mode 100644 index 0000000..ee69755 Binary files /dev/null and b/data/images/button/PlotCity.png differ diff --git a/data/images/button/Portrait.png b/data/images/button/Portrait.png new file mode 100644 index 0000000..2680326 Binary files /dev/null and b/data/images/button/Portrait.png differ diff --git a/data/images/button/Print.png b/data/images/button/Print.png new file mode 100644 index 0000000..5977b3d Binary files /dev/null and b/data/images/button/Print.png differ diff --git a/data/images/button/Remove.png b/data/images/button/Remove.png new file mode 100644 index 0000000..0b6199a Binary files /dev/null and b/data/images/button/Remove.png differ diff --git a/data/images/button/RemoveZone.png b/data/images/button/RemoveZone.png new file mode 100644 index 0000000..0b6199a Binary files /dev/null and b/data/images/button/RemoveZone.png differ diff --git a/data/images/button/Restart.png b/data/images/button/Restart.png new file mode 100644 index 0000000..19a1665 Binary files /dev/null and b/data/images/button/Restart.png differ diff --git a/data/images/button/Save.png b/data/images/button/Save.png new file mode 100644 index 0000000..3f7fd63 Binary files /dev/null and b/data/images/button/Save.png differ diff --git a/data/images/button/SaveAll.png b/data/images/button/SaveAll.png new file mode 100644 index 0000000..d97aecf Binary files /dev/null and b/data/images/button/SaveAll.png differ diff --git a/data/images/button/Search.png b/data/images/button/Search.png new file mode 100644 index 0000000..ee69755 Binary files /dev/null and b/data/images/button/Search.png differ diff --git a/data/images/button/SelectAll.png b/data/images/button/SelectAll.png new file mode 100644 index 0000000..a97255e Binary files /dev/null and b/data/images/button/SelectAll.png differ diff --git a/data/images/button/SetEnum.png b/data/images/button/SetEnum.png new file mode 100644 index 0000000..eef49b3 Binary files /dev/null and b/data/images/button/SetEnum.png differ diff --git a/data/images/button/SetGeoPos.png b/data/images/button/SetGeoPos.png new file mode 100644 index 0000000..ccd1913 Binary files /dev/null and b/data/images/button/SetGeoPos.png differ diff --git a/data/images/button/StageManager.png b/data/images/button/StageManager.png new file mode 100644 index 0000000..ee71831 Binary files /dev/null and b/data/images/button/StageManager.png differ diff --git a/data/images/button/StageManagerOff.png b/data/images/button/StageManagerOff.png new file mode 100644 index 0000000..3c33cde Binary files /dev/null and b/data/images/button/StageManagerOff.png differ diff --git a/data/images/button/StageManagerOn.png b/data/images/button/StageManagerOn.png new file mode 100644 index 0000000..ee71831 Binary files /dev/null and b/data/images/button/StageManagerOn.png differ diff --git a/data/images/button/Tag.png b/data/images/button/Tag.png new file mode 100644 index 0000000..6b441cd Binary files /dev/null and b/data/images/button/Tag.png differ diff --git a/data/images/button/Text.png b/data/images/button/Text.png new file mode 100644 index 0000000..04cf575 Binary files /dev/null and b/data/images/button/Text.png differ diff --git a/data/images/button/TurnLeft.png b/data/images/button/TurnLeft.png new file mode 100644 index 0000000..facad55 Binary files /dev/null and b/data/images/button/TurnLeft.png differ diff --git a/data/images/button/TurnRight.png b/data/images/button/TurnRight.png new file mode 100644 index 0000000..6b6a518 Binary files /dev/null and b/data/images/button/TurnRight.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/Validate.png b/data/images/button/Validate.png new file mode 100644 index 0000000..909a2f0 Binary files /dev/null and b/data/images/button/Validate.png differ diff --git a/data/images/button/VerticalBottom.png b/data/images/button/VerticalBottom.png new file mode 100644 index 0000000..e4ba851 Binary files /dev/null and b/data/images/button/VerticalBottom.png differ diff --git a/data/images/button/VerticalCenter.png b/data/images/button/VerticalCenter.png new file mode 100644 index 0000000..788ff79 Binary files /dev/null and b/data/images/button/VerticalCenter.png differ diff --git a/data/images/button/VerticalDistrib.png b/data/images/button/VerticalDistrib.png new file mode 100644 index 0000000..493f32c Binary files /dev/null and b/data/images/button/VerticalDistrib.png differ diff --git a/data/images/button/VerticalSpace.png b/data/images/button/VerticalSpace.png new file mode 100644 index 0000000..20cede1 Binary files /dev/null and b/data/images/button/VerticalSpace.png differ diff --git a/data/images/button/VerticalSpin.png b/data/images/button/VerticalSpin.png new file mode 100644 index 0000000..d45403a Binary files /dev/null and b/data/images/button/VerticalSpin.png differ diff --git a/data/images/button/VerticalSpinOff.png b/data/images/button/VerticalSpinOff.png new file mode 100644 index 0000000..1f800dd Binary files /dev/null and b/data/images/button/VerticalSpinOff.png differ diff --git a/data/images/button/VerticalSpinOn.png b/data/images/button/VerticalSpinOn.png new file mode 100644 index 0000000..d45403a Binary files /dev/null and b/data/images/button/VerticalSpinOn.png differ diff --git a/data/images/button/VerticalTop.png b/data/images/button/VerticalTop.png new file mode 100644 index 0000000..ac8ba5e Binary files /dev/null and b/data/images/button/VerticalTop.png differ diff --git a/data/images/button/Visitor.png b/data/images/button/Visitor.png new file mode 100644 index 0000000..20d7103 Binary files /dev/null and b/data/images/button/Visitor.png differ diff --git a/data/images/button/VisitorOff.png b/data/images/button/VisitorOff.png new file mode 100644 index 0000000..532abe7 Binary files /dev/null and b/data/images/button/VisitorOff.png differ diff --git a/data/images/button/VisitorOn.png b/data/images/button/VisitorOn.png new file mode 100644 index 0000000..20d7103 Binary files /dev/null and b/data/images/button/VisitorOn.png differ diff --git a/data/images/button/Wizard.png b/data/images/button/Wizard.png new file mode 100644 index 0000000..403714a Binary files /dev/null and b/data/images/button/Wizard.png differ diff --git a/data/images/button/Yoda.png b/data/images/button/Yoda.png new file mode 100644 index 0000000..8311d4b Binary files /dev/null and b/data/images/button/Yoda.png differ diff --git a/data/images/button/YodaOff.png b/data/images/button/YodaOff.png new file mode 100644 index 0000000..ba18e42 Binary files /dev/null and b/data/images/button/YodaOff.png differ diff --git a/data/images/button/YodaOn.png b/data/images/button/YodaOn.png new file mode 100644 index 0000000..8311d4b Binary files /dev/null and b/data/images/button/YodaOn.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/button/distribute-horizontal-x.png b/data/images/button/distribute-horizontal-x.png new file mode 100644 index 0000000..fd98af1 Binary files /dev/null and b/data/images/button/distribute-horizontal-x.png differ diff --git a/data/images/button/distribute-vertical-y.png b/data/images/button/distribute-vertical-y.png new file mode 100644 index 0000000..e85450a Binary files /dev/null and b/data/images/button/distribute-vertical-y.png differ diff --git a/data/images/button/handler.png b/data/images/button/handler.png new file mode 100644 index 0000000..187cf75 Binary files /dev/null and b/data/images/button/handler.png differ diff --git a/data/server/furniture/000-0052.lpt b/data/server/furniture/000-0052.lpt new file mode 100644 index 0000000..bb643f2 --- /dev/null +++ b/data/server/furniture/000-0052.lpt @@ -0,0 +1,9 @@ + + + + + + + +
+ diff --git a/data/texts/AboutAdecWatt.html b/data/texts/AboutAdecWatt.html new file mode 100644 index 0000000..eaf6678 --- /dev/null +++ b/data/texts/AboutAdecWatt.html @@ -0,0 +1,31 @@ + + + + + A propos de AdecWatt + + + +

AdecWatt V1.3 (version du 4/2/2018)

+
+

+ Ce logiciel est en cours de développement par l'ADEC56. + Il est téléchargeable sur adecwatt.parlenet.org +

+
+ + diff --git a/data/texts/AdecWattLicence.html b/data/texts/AdecWattLicence.html new file mode 100644 index 0000000..e563d27 --- /dev/null +++ b/data/texts/AdecWattLicence.html @@ -0,0 +1,44 @@ + + + + + CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL + + + +

Avertissement

+
+

Comme toute oeuvre, la reproduction, même partielle de ce logiciel est protégé par le droit d'auteur. En particulier, en dehors d'une autorisation explicite écrite, son utilisation dans le cadre d'une réalisation lucrative est une fraude. Ce logiciel n'est pas destiné à être vendu (y compris de manière hypocrite en infligeant des bandeaux publicitaires). +

+

+ Ce logiciel est sous contrat de licence de logiciel libre CeCILL1. + Cette mention est indissociable du logiciel. + +

    +
  • Ce logiciel est libre. Vous n'avez pas à payer pour l'utiliser. Des bénévoles de l'ADEC56 l'on développé.
  • +
  • Ce logiciel n'est pas gratuit. Vous ne serez donc pas vendu à une propagande commerciale pour financer son utilisation. Votre utilisation ne sera pas non plus tracée en vue d'une manipulation politique.
  • +
+ +

+
+ + + diff --git a/data/texts/ManualAdecWatt.html b/data/texts/ManualAdecWatt.html new file mode 100644 index 0000000..67d814e --- /dev/null +++ b/data/texts/ManualAdecWatt.html @@ -0,0 +1,106 @@ + + + + + Manuel d'utilisation + + + + +

Manuel d'utilisation

+

+ Ce logiciel sert à réaliser des plans de feu. + + Ce manuel est en cours de rédaction. +

+ +

1. Première mise en route

+

+ Vous devez mettre à jour le logiciel avec la commande : . +

+ +

2. Modification de salle de spectacle

+

+ Ce mode n'est pas terminé (changement de taille, de plan de fond, ...). + + Sur la partie gauche, sélectionnez l'onglet "Immobilier", puis double-cliquez sur la salle que vous voulez modifier. + Elle apparaît sur la partie droite. + + Choisissez dans l'onglet mobilier des éléments à ajouter. +

+ +

3. Ajout de mobilier

+

+ Sur la partie gauche, sélectionnez l'onglet "Mobilier", puis faire glisser le mobilier choisi dans la salle ou le plan de feu (partie droite). + + Par la suite on peu : +

    +
  • ajuster la position en cliquant (clique gauche) sur l'objet et en le glissant.
  • +
  • ajuster l'orientation en appuyant sur "Ctrl" et en cliquant là où l'objet doit pointer.
  • +
+

+ +

4. Modification d'échelle

+

+ Placer la sourie sur la salle ou le plan de feu (partie droite) et appuyer sur la touche "Ctrl". + La molette de la sourie permet : +

    +
  • agrandir (molette vers l'avant).
  • +
  • réduire (molette vers l'arrière).
  • +
+

+ +

5. Déplacement dans la vue

+

+ Placer la sourie sur la salle ou le plan de feu (partie droite). + La molette de la sourie permet : +

    +
  • de monter (vers l'avant) ou décendre (ver l'arrière).
  • +
  • et en appuyant sur la touche "Maj", d'aller à gauche (vers l'avant) ou à droite (ver l'arrière).
  • +
+

+ +

6. Modification de plan de feu

+

+ Sur la partie gauche, sélectionnez l'onglet "Immobilier", puis double-cliquez sur la salle que vous voulez modifier. + Elle apparaît sur la partie droite. + + On peut comme pour une salle : +

    +
  • ajouter du mobilier
  • +
  • changer le rapport d'échelle
  • +
  • déplacer la vue
  • +
+ + On peut également changer de salle en choisissant une salle (onglet "Immobilier" en partie gauche) sur le plan de feu. +

+ +

7. Fermeture des vues

+

+ Pour fermer une vue, il faut cliquer avec le bouto de droite sur l'onglet pour faire apparaître un menu. + La fermeture d'une vue est indépendante de la sauvegarde. + Un objet non sauvé pourra être rééditer plus tard avant d'être sauver. +

+ +

8. Historique des commandes

+

+ Un historique des commandes permet de gérrer l'annulation et la réexécution des actions indépendament des objets édités. +

+ +



+ + +

Bons plans de feu !!!

+ + diff --git a/soft/JMapViewer.jar b/soft/JMapViewer.jar new file mode 100644 index 0000000..7fe9a63 Binary files /dev/null and b/soft/JMapViewer.jar differ diff --git a/soft/Misc.jar b/soft/Misc.jar new file mode 100644 index 0000000..04db1d1 Binary files /dev/null and b/soft/Misc.jar differ diff --git a/src/java/adecWatt/control/AdecWattController.java b/src/java/adecWatt/control/AdecWattController.java new file mode 100644 index 0000000..6ee2b4f --- /dev/null +++ b/src/java/adecWatt/control/AdecWattController.java @@ -0,0 +1,187 @@ +package adecWatt.control; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Image; +import java.text.MessageFormat; +import javax.swing.JMenuBar; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import misc.Bundle; +import misc.Config; +import misc.Controller; +import misc.HelpManager; +import misc.HtmlDialog; +import misc.MultiToolBarBorderLayout; +import misc.ProxyManager; +import misc.RemoteUpdate; +import misc.RemoteUpdateManager; +import misc.StoryManager; +import misc.ToolBarManager; +import misc.Util; + +import adecWatt.model.AdecWatt; +import adecWatt.model.Unit; +import adecWatt.model.User; +import adecWatt.view.JAdecWatt; +import adecWatt.view.JAdecWattDialog; +import adecWatt.view.JAdecWattMenuBar; +import adecWatt.view.JAdecWattSearchToolBar; +import adecWatt.view.JAdecWattToolBar; +import adecWatt.view.JWorkspaceSlidersToolBar; + +public class AdecWattController extends Controller { + + // ======================================== + AdecWatt adecWatt; + RemoteUpdate remoteUpdate; + + JAdecWatt jAdecWatt; + + JAdecWattMenuBar jAdecWattMenuBar; + JAdecWattToolBar jAdecWattToolBar; + JAdecWattDialog jAdecWattDialog; + JAdecWattSearchToolBar jAdecWattSearchToolBar; + JWorkspaceSlidersToolBar jWorkspaceSlidersToolBar; + + HtmlDialog manualDialog; + + AdecWattManager adecWattManager; + HelpManager helpManager; + ToolBarManager toolBarManager; + StoryManager storyManager; + ProxyManager proxyManager; + RemoteUpdateManager remoteUpdateManager; + + // ======================================== + public AdecWattController (AdecWatt adecWatt) { + super (adecWatt); + } + + public void restart () { + adecWattManager.actionRestart (); + } + + // ======================================== + protected void createModel (AdecWatt adecWatt) { + this.adecWatt = adecWatt; + adecWatt.addUpdateObserver (this, AdecWatt.BroadcastTitle); + adecWatt.getUser ().addUpdateObserver (this, User.BroadcastUserChangeProfil); + Bundle.addBundleObserver (this); + remoteUpdate = + new RemoteUpdate (AdecWattManager.protocol, AdecWattManager.remoteServerName, AdecWattManager.stableVersion, AdecWattManager.urlModel, + new String [] {"soft"}, + new String [] {"data", "data", "server"}, + new String [] {"help-fr_FR", "data", "texts", "help-fr_FR"}, + new String [] {"help-images", "data", "texts", "help-images"}, + new String [] {"help-en_US", "data", "texts", "help-en_US"}, + new String [] {"help-br_FR_breton", "data", "texts", "help-br_FR_breton"}, + new String [] {"help-br_FR_gallo", "data", "texts", "help-br_FR_gallo"}, + new String [] {"help-es_ES", "data", "texts", "help-es_ES"} + //new String [] {"test", "data", "test", "server"} + ); + } + + // ======================================== + protected Component createGUI () { + jAdecWatt = new JAdecWatt (adecWatt); + jAdecWattDialog = new JAdecWattDialog (this); + jWorkspaceSlidersToolBar = new JWorkspaceSlidersToolBar (jAdecWatt); + jAdecWattSearchToolBar = new JAdecWattSearchToolBar (jAdecWatt); + manualDialog = new HtmlDialog (jFrame, "Manual", "data/texts/help-"+Bundle.getLocale ()+"/index.html"); + + Frame frame = new Frame (); + frame.setIconImage (getIcon ()); + JPanel contentPane = new JPanel (new MultiToolBarBorderLayout ()); + toolBarManager = new ToolBarManager (getIcon (), contentPane); + + storyManager = new StoryManager (); + remoteUpdateManager = new RemoteUpdateManager (this, remoteUpdate, + new Runnable () { + public void run () { + restart (); + } + }); + remoteUpdateManager.check (); + adecWattManager = + new AdecWattManager (adecWatt, storyManager, remoteUpdateManager, + jAdecWatt, jWorkspaceSlidersToolBar, jAdecWattDialog, manualDialog); + helpManager = new HelpManager (this, "AdecWatt"); + proxyManager = new ProxyManager (this); + jAdecWattToolBar = new JAdecWattToolBar (this, + adecWattManager, storyManager, proxyManager, remoteUpdateManager, helpManager, toolBarManager, + jAdecWattSearchToolBar, jWorkspaceSlidersToolBar); + contentPane.add (jAdecWatt, BorderLayout.CENTER); + + return contentPane; + } + + protected void newJFrame () { + manualDialog.setJFrame (jFrame); + // XXX pas RemoteUpdate ! et les outres ? + } + + public void updateBundle () { + super.updateBundle (); + SwingUtilities.invokeLater (new Runnable () { + public void run () { + manualDialog.changeFileName ("data/texts/help-"+Bundle.getLocale ()+"/index.html"); + } + }); + } + + // ======================================== + public String getTitle () { + Unit currentWorkspace = jAdecWatt.getCurrentWorkspace (); + Unit sharedUnitStory = adecWattManager.getSharedUnitStory (); + return MessageFormat.format (Bundle.getTitle ("AdecWatt"), + currentWorkspace == null ? Bundle.getAction ("Empty") : currentWorkspace.toString (), + sharedUnitStory == null ? "?" : sharedUnitStory.toString ()); + } + + public Image getIcon () { + try { + return Util.loadImage (Config.getString ("AdecWattIcon", "data/images/adecWatt.png")); + } catch (Exception e) { + return null; + } + } + + public void updateTitle () { + updateBundle (); + } + public void updateUserChangeProfil () { + User user = adecWatt.getUser (); + if (jAdecWattMenuBar != null) + jAdecWattMenuBar.changeProfil (user); + if (jAdecWattToolBar != null) + jAdecWattToolBar.changeProfil (user); + } + + // ======================================== + protected JMenuBar createMenuBar () { + return jAdecWattMenuBar = new JAdecWattMenuBar (this, adecWattManager, storyManager, proxyManager, remoteUpdateManager, helpManager, toolBarManager); + } + + // ======================================== + protected boolean tryClosingWindows () { + Config.save ("AdecWatt"); + if (adecWatt.getModified ()) + switch (JOptionPane.showConfirmDialog (jFrame, Bundle.getMessage ("QuitJAdecWatt"), + Bundle.getTitle ("AdecWattStillRunning"), + JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE)) { + case JOptionPane.YES_OPTION: + return true; + case JOptionPane.NO_OPTION: + case JOptionPane.CANCEL_OPTION: + case JOptionPane.CLOSED_OPTION: + return false; + } + return true; + } + + // ======================================== +} diff --git a/src/java/adecWatt/control/AdecWattManager.java b/src/java/adecWatt/control/AdecWattManager.java new file mode 100644 index 0000000..77a6948 --- /dev/null +++ b/src/java/adecWatt/control/AdecWattManager.java @@ -0,0 +1,686 @@ +package adecWatt.control; + +import java.awt.Container; +import java.awt.Desktop; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.TreeSet; +import java.util.Vector; +import javax.swing.AbstractButton; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import misc.ApplicationManager; +import misc.Config; +import misc.HtmlDialog; +import misc.RemoteUpdateManager; +import misc.Story; +import misc.StoryManager; +import misc.Util; + +import adecWatt.model.Acc; +import adecWatt.model.AdecWatt; +import adecWatt.model.Editable; +import adecWatt.model.ImageDB; +import adecWatt.model.Item; +import adecWatt.model.PermanentDB; +import adecWatt.model.Unit; +import adecWatt.model.unit.Workspace; +import adecWatt.view.JAdecWatt; +import adecWatt.view.JAdecWattDialog; +import adecWatt.view.JWorkspaceSlidersToolBar; +import adecWatt.view.JWorkspaceView; +import adecWatt.view.PrintWorkspace; + +public class AdecWattManager implements ApplicationManager, ActionListener { + + // ======================================== + public static String protocol = "https"; + public static String remoteServerName = "adecwatt.parlenet.org"; + public String testedServerName = "adecwatt.parlenet.local"; + public String currentServerName = remoteServerName; + public static String stableVersion = "v3"; + public String testedVersion = "test"; + public String currentVersion = stableVersion; + public static String + urlModel = "/lib/plugins/adecwatt/adecWattBD.php?version={0}&action={1}&name={2}"; + + // ======================================== + static public final String + actionChangeRole = "ChangeRole", + actionRestart = "Restart", + actionSave = "Save", + actionSaveAll = "SaveAll", + actionImport = "Import", + actionExport = "Export", + actionPageSetup = "PageSetup", + actionPrint = "Print", + actionExportPDF = "ExportPDF", + actionClose = "Close", + actionCloseAll = "CloseAll", + + actionSelectAll = "SelectAll", + actionCut = "Cut", + actionCopy = "Copy", + actionPaste = "Paste", + actionMagnetPolicies = "MagnetPolicies", + actionPatch = "Patch", + + actionHorizontalLeft = "HorizontalLeft", + actionHorizontalCenter = "HorizontalCenter", + actionHorizontalRight = "HorizontalRight", + actionVerticalTop = "VerticalTop", + actionVerticalCenter = "VerticalCenter", + actionVerticalBottom = "VerticalBottom", + + actionHorizontalSpace = "HorizontalSpace", + actionHorizontalDistrib = "HorizontalDistrib", + actionVerticalSpace = "VerticalSpace", + actionVerticalDistrib = "VerticalDistrib", + actionWizard = "Wizard", + actionHttpServer = "HttpServer", + actionLocalServer = "LocalServer", + actionTestedServer = "TestedServer", + actionServerName = "ServerName", + actionManual = "Manual"; + + static public Util.ActionControl[] actionsControl = { + new Util.ActionControl (actionSave, KeyEvent.VK_S), + new Util.ActionControl (actionSelectAll, KeyEvent.VK_A), + new Util.ActionControl (actionCut, KeyEvent.VK_X), + // new Util.ActionControl (actionCut, KeyEvent.VK_DELETE, false), + // new Util.ActionControl (actionCut, KeyEvent.VK_BACK_SPACE, false), + new Util.ActionControl (actionCopy, KeyEvent.VK_C), + new Util.ActionControl (actionPaste, KeyEvent.VK_V), + new Util.ActionControl (StoryManager.actionUndo, KeyEvent.VK_Z), + new Util.ActionControl (StoryManager.actionRedo, KeyEvent.VK_Y), + }; + + // ======================================== + /** popup Menu. */ + static public final String + actionDisplayUnit = "DisplayUnit", + actionModifyUnit = "ModifyUnit", + actionRenameUnit = "RenameUnit", + actionTransformUnit = "TransformUnit", + actionCopyUnit = "CopyUnit", + actionNewUnit = "NewUnit", + actionPromoteUnit = "PromoteUnit", + actionRemoveUnit = "RemoveUnit", + actionRemoveImage = "RemoveImage", + actionChangeImage = "ChangeImage", + actionUnchange = "Unchange"; + + static public final String + actionDisplayItem = "DisplayItem", + actionModifyItem = "ModifyItem", + actionHideItem = "HideItem", + actionShowItem = "ShowItem", + actionTransformItem = "TransformItem", + actionCopyItem = "CopyItem", + actionRemoveItem = "RemoveItem", + + actionHideShowItem = "HideShowItem"; + + static public final String + actionDisplayAcc = "DisplayAcc", + actionModifyAcc = "ModifyAcc", + actionTransformAcc = "TransformAcc", + actionRemoveAcc = "RemoveAcc"; + + // ======================================== + static public final List + fileActionsNames = Arrays.asList (actionChangeRole, actionRestart, + actionSave, actionSaveAll, actionImport, actionExport, + actionPageSetup, actionPrint, //actionExportPDF, + actionClose, actionCloseAll), + editActionsNames = Arrays.asList (actionSelectAll, actionCut, actionCopy, actionPaste, actionMagnetPolicies, actionPatch), + placementActionsNames = Arrays.asList (actionHorizontalLeft, actionHorizontalCenter, actionHorizontalRight, + actionVerticalTop, actionVerticalCenter, actionVerticalBottom, + actionHorizontalSpace, actionHorizontalDistrib, + actionVerticalSpace, actionVerticalDistrib), + yodaActionsNames = Arrays.asList (actionHttpServer, actionLocalServer, actionTestedServer, actionServerName, actionWizard), + yodaNoCheckActionsNames = Arrays.asList (actionServerName, actionWizard), + helpActionsNames = Arrays.asList (actionManual); + + // ======================================== + @SuppressWarnings ("unchecked") + static public final Hashtable actionsMethod = + Util.collectMethod (AdecWattManager.class, + fileActionsNames, editActionsNames, placementActionsNames, yodaActionsNames, helpActionsNames); + + public void actionPerformed (ActionEvent e) { + Util.actionPerformed (actionsMethod, e, this); + } + + // ======================================== + AdecWatt adecWatt; + PermanentDB permanentDB; + StoryManager storyManager; + RemoteUpdateManager remoteUpdateManager; + + JAdecWatt jAdecWatt; + JWorkspaceSlidersToolBar jWorkspaceSlidersToolBar; + JAdecWattDialog jAdecWattDialog; + HtmlDialog manualDialog; + JCheckBoxMenuItem httpServerCB; + JCheckBoxMenuItem localServerCB; + JCheckBoxMenuItem testedServerCB; + + // ======================================== + public AdecWattManager (AdecWatt adecWatt, StoryManager storyManager, RemoteUpdateManager remoteUpdateManager, + JAdecWatt jAdecWatt, JWorkspaceSlidersToolBar jWorkspaceSlidersToolBar, JAdecWattDialog jAdecWattDialog, + HtmlDialog manualDialog) { + this.adecWatt= adecWatt; + permanentDB = adecWatt.getPermanentDB (); + this.storyManager = storyManager; + this.jAdecWatt = jAdecWatt; + this.jWorkspaceSlidersToolBar = jWorkspaceSlidersToolBar; + this.jAdecWattDialog = jAdecWattDialog; + this.manualDialog = manualDialog; + this.remoteUpdateManager = remoteUpdateManager; + + jAdecWatt.stateNotifier.addUpdateObserver (this, JAdecWatt.BroadcastWorkspace, JAdecWatt.BroadcastSelection); + jAdecWatt.stateNotifier.addMsgObserver (this, JAdecWatt.BroadcastUnitStory); //, JAdecWatt.BroadcastEditableSelection); + + adecWatt.addUpdateObserver (this, + AdecWatt.BroadcastStory); + adecWatt.addMsgObserver (this, + AdecWatt.BroadcastUnitStory, + actionClose, + actionDisplayUnit, actionModifyUnit, actionRenameUnit, actionTransformUnit, + actionCopyUnit, actionNewUnit, actionPromoteUnit, actionRemoveUnit, + actionDisplayItem, actionModifyItem, actionHideShowItem, actionTransformItem, actionCopyItem, actionRemoveItem, + Unit.BroadcastSetSelectionItems, Unit.BroadcastConnection, + actionDisplayAcc, actionModifyAcc, actionTransformAcc, actionRemoveAcc); + } + + // ======================================== + public void addMenuItem (JMenu... jMenu) { + int idx = 0; + Util.addMenuItem (fileActionsNames, this, jMenu[idx++]); + Util.addMenuItem (editActionsNames, this, jMenu[idx++]); + Util.addMenuItem (placementActionsNames, this, jMenu[idx++]); + httpServerCB = Util.addCheckMenuItem (actionHttpServer, this, false, jMenu[idx]); + localServerCB = Util.addCheckMenuItem (actionLocalServer, this, false, jMenu[idx]); + testedServerCB = Util.addCheckMenuItem (actionTestedServer, this, false, jMenu[idx]); + actionHttpServer (); + actionLocalServer (); + actionTestedServer (); + Util.addMenuItem (yodaNoCheckActionsNames, this, jMenu[idx++]); + Util.addMenuItem (helpActionsNames, this, jMenu[idx++]); + } + + // ======================================== + public void addIconButtons (Container... containers) { + int idx = 0; + Util.addIconButton (fileActionsNames, this, containers[idx++]); + Util.addIconButton (editActionsNames, this, containers[idx++]); + Util.addIconButton (placementActionsNames, this, containers[idx++]); + idx++; + idx++; + Util.addIconButton (helpActionsNames, this, containers[idx++]); + } + + // ======================================== + private ArrayList enabledSaveButtons = new ArrayList (); + private ArrayList enabledSaveAllButtons = new ArrayList (); + private ArrayList enabledCloseButtons = new ArrayList (); + private ArrayList enabledPasteButtons = new ArrayList (); + private ArrayList enabledSelectionButtons = new ArrayList (); + private ArrayList enabledMultiSelectionButtons = new ArrayList (); + public void addActiveButtons (Hashtable buttons) { + enabledSaveButtons.add (buttons.get (actionSave)); + enabledSaveAllButtons.add (buttons.get (actionSaveAll)); + enabledCloseButtons.add (buttons.get (actionPrint)); + //enabledCloseButtons.add (buttons.get (actionExportPDF)); + enabledCloseButtons.add (buttons.get (actionPatch)); + enabledCloseButtons.add (buttons.get (actionExport)); + enabledCloseButtons.add (buttons.get (actionClose)); + enabledCloseButtons.add (buttons.get (actionCloseAll)); + enabledCloseButtons.add (buttons.get (actionSelectAll)); + enabledPasteButtons.add (buttons.get (actionPaste)); + enabledSelectionButtons.add (buttons.get (actionCopy)); + enabledSelectionButtons.add (buttons.get (actionCut)); + for (String action : placementActionsNames) + enabledMultiSelectionButtons.add (buttons.get (action)); + updateActiveButtons (); + } + + public void updateActiveButtons () { + remoteUpdateManager.updateActiveButtons (); + updateStory (); + updateWorkspace (); + updatePaste (); + } + + // ======================================== + Unit sharedUnitStory; + public Unit getSharedUnitStory () { return sharedUnitStory; } + public void displayUnitStory (Object... objects) { + // if (objects[0] == null) + // return; + sharedUnitStory = (Unit) objects[0]; + adecWatt.broadcastUpdate (AdecWatt.BroadcastTitle); + storyManager.setStory (sharedUnitStory == null ? null : sharedUnitStory.story); + updateStory (); + } + public void updateStory () { + boolean saveAll = permanentDB.isModifiedUnit (); + boolean save = false; + if (sharedUnitStory != null) { + Story story = sharedUnitStory.story; + save = story.isModified (); + } + for (AbstractButton button : enabledSaveButtons) + button.setEnabled (save); + for (AbstractButton button : enabledSaveAllButtons) + button.setEnabled (saveAll); + jAdecWatt.updateUnit (sharedUnitStory, false); + } + + public void updateWorkspace () { + boolean close = jAdecWatt.hasWorkspace (); + for (AbstractButton button : enabledCloseButtons) + button.setEnabled (close); + Workspace currentWorkspace = jAdecWatt.getCurrentWorkspace (); + displayUnitStory (currentWorkspace); + updateSelection (); + JWorkspaceView jWorkspaceView = jAdecWatt.getCurrentJWorkspace (); + jWorkspaceSlidersToolBar.setJWorkspaceView (jWorkspaceView); + } + + public void updateSelection () { + JWorkspaceView jWorkspaceView = jAdecWatt.getCurrentJWorkspace (); + int nbSelection = jWorkspaceView == null ? 0 : jWorkspaceView.getNbSelectedItems (); + boolean selection = nbSelection > 0; + boolean multiSelection = nbSelection > 1; + for (AbstractButton button : enabledSelectionButtons) + button.setEnabled (selection); + for (AbstractButton button : enabledMultiSelectionButtons) + button.setEnabled (multiSelection); + } + + // ======================================== + public void actionRestart () { + if (adecWatt.getModified () && !jAdecWattDialog.abortModification ()) + return; + actionCloseAll (); + adecWatt.reset (); + jAdecWatt.stateNotifier.broadcastDisplay (JAdecWatt.BroadcastUnitStory, (Unit) null); + } + + public void actionSave () { + if (sharedUnitStory == null) + return; + sharedUnitStory.save (); + } + + public void actionSaveAll () { + adecWatt.saveAll (); + } + + public void actionSelectAll () { + JWorkspaceView jWorkspaceView = jAdecWatt.getCurrentJWorkspace (); + if (jWorkspaceView == null) + return; + jWorkspaceView.selectAllItems (); + } + + public void actionImport () { + permanentDB.importFile (jAdecWattDialog.getChooseOpenFile (permanentDB.getLastExport ())); + } + + public void actionExport () { + Workspace currentWorkspace = jAdecWatt.getCurrentWorkspace (); + if (currentWorkspace == null) + return; + permanentDB.exportFile (currentWorkspace, jAdecWattDialog.getChooseSaveFile (permanentDB.getLastExport ())); + } + + Vector clip = new Vector (); + + public void updatePaste () { + boolean paste = clip.size () > 0; + for (AbstractButton button : enabledPasteButtons) + button.setEnabled (paste); + } + + public void actionCut () { + actionCopy (); + JWorkspaceView jWorkspaceView = jAdecWatt.getCurrentJWorkspace (); + if (jWorkspaceView == null) + return; + jWorkspaceView.getWorkspace ().storyRemoveItems (clip); + } + + public void actionCopy () { + clip.clear (); + try { + clip.addAll (jAdecWatt.getCurrentJWorkspace ().getSelectedItems ()); + } catch (Exception e) { + } + updatePaste (); + } + + public void actionPaste () { + Workspace currentWorkspace = jAdecWatt.getCurrentWorkspace (); + if (currentWorkspace == null) + return; + currentWorkspace.storyPasteItem (clip); + } + + + // ======================================== + public void displayClose (Object... objects) { + if (objects[0] == null || ! (objects[0] instanceof Workspace)) + return; + Workspace workspace = (Workspace) objects[0]; + jAdecWattDialog.removeDisplay (workspace); + jAdecWatt.closeWorkspace (workspace); + } + + public void actionClose () { + Workspace currentWorkspace = jAdecWatt.getCurrentWorkspace (); + jAdecWattDialog.removeDisplay (currentWorkspace); + jAdecWatt.closeWorkspace (currentWorkspace); + } + + public void actionCloseAll () { + jAdecWattDialog.removeAllDisplay (); + jAdecWatt.closeWorkspaces (); + } + + public void actionChangeRole () { + jAdecWattDialog.checkAdmin (adecWatt.getUser (), remoteUpdateManager); + } + + public void actionHorizontalLeft () { align (Workspace.Alignment.LEFT); } + public void actionHorizontalCenter () { align (Workspace.Alignment.CENTER); } + public void actionHorizontalRight () { align (Workspace.Alignment.RIGHT); } + public void actionVerticalTop () { align (Workspace.Alignment.TOP); } + public void actionVerticalCenter () { align (Workspace.Alignment.MIDDLE); } + public void actionVerticalBottom () { align (Workspace.Alignment.BOTTOM); } + public void actionHorizontalSpace () { distrib (true, true); } + public void actionHorizontalDistrib () { distrib (true, false); } + public void actionVerticalSpace () { distrib (false, true); } + public void actionVerticalDistrib () { distrib (false, false); } + + + public void distrib (boolean isHorizontal, boolean isSpace) { + JWorkspaceView jWorkspaceView = jAdecWatt.getCurrentJWorkspace (); + if (jWorkspaceView == null) + return; + Double value = jAdecWattDialog.getSpace (); + if (value != null && value < 0) + return; + Vector items = jWorkspaceView.getSelectedItems (); + if (items == null || items.size () < 2) + return; + Workspace workspace = jWorkspaceView.getWorkspace (); + if (isSpace) + workspace.storySpaceItem (items, isHorizontal, value); + else + workspace.storyDistributeItem (items, isHorizontal, value); + } + + public void align (Workspace.Alignment alignment) { + JWorkspaceView jWorkspaceView = jAdecWatt.getCurrentJWorkspace (); + if (jWorkspaceView == null) + return; + Vector items = jWorkspaceView.getSelectedItems (); + if (items == null || items.size () < 2) + return; + jWorkspaceView.getWorkspace ().storyAlignItem (items, alignment); + } + + // ======================================== + public void actionManual () { + try { + Desktop.getDesktop ().browse (Config.getDataUrl ("data", "texts", "help-"+misc.Bundle.getLocale (), "index.html").toURI ()); + } catch (Exception e) { + e.printStackTrace (); + manualDialog.restart (); + manualDialog.setVisible (true); + } + } + + private PrinterJob printer = null; + private PageFormat page = null; + + public void actionPageSetup() { + if (printer == null) + printer = PrinterJob.getPrinterJob (); + if (page == null) + page = printer.defaultPage (); + page = printer.pageDialog (page); + printer.defaultPage (page); + } + + public void actionPrint () { + Workspace currentWorkspace = jAdecWatt.getCurrentWorkspace (); + if (printer == null) + printer = PrinterJob.getPrinterJob (); + if (!printer.printDialog ()) + return; + PrintWorkspace.print (jAdecWattDialog.getOwnFrame (), printer, currentWorkspace); + } + + public void actionExportPDF () { + Workspace currentWorkspace = jAdecWatt.getCurrentWorkspace (); + if (printer == null) + printer = PrinterJob.getPrinterJob (); + if (!printer.printDialog ()) + return; + PrintWorkspace.print (jAdecWattDialog.getOwnFrame (), printer, currentWorkspace); + } + + public void actionMagnetPolicies () { + jAdecWattDialog.magnetPolicies (adecWatt); + } + + public void actionPatch () { + jAdecWattDialog.patch (jAdecWatt.getCurrentWorkspace ()); + } + + public void actionHttpServer () { + remoteUpdateManager.getRemoteUpdate ().protocol = + httpServerCB.isSelected () ? "http" : protocol; + Config.setBoolean ("HttpServer"+Config.checkedPostfix, httpServerCB.isSelected ()); + // XXX ??? + javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier (new javax.net.ssl.HostnameVerifier () { + public boolean verify (String hostname, javax.net.ssl.SSLSession session) { + return true; + } + }); + } + public void actionLocalServer () { + remoteUpdateManager.getRemoteUpdate ().serverName = + localServerCB.isSelected () ? testedServerName : remoteServerName; + + javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier (new javax.net.ssl.HostnameVerifier () { + public boolean verify (String hostname, javax.net.ssl.SSLSession session) { + return true; + } + }); + } + public void actionTestedServer () { + remoteUpdateManager.getRemoteUpdate ().versionName = + testedServerCB.isSelected () ? testedVersion : stableVersion; + + javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier (new javax.net.ssl.HostnameVerifier () { + public boolean verify (String hostname, javax.net.ssl.SSLSession session) { + return true; + } + }); + } + public void actionServerName () { + String newServer = jAdecWattDialog.getSimpleMessage ("ServerName", testedServerName); + if (newServer != null) + testedServerName = newServer; + } + public void actionWizard () { + try { + System.err.println ("coucou: wizard"); + java.net.URL newURL = Config.getDataUrl ("data", "texts", "help-"+misc.Bundle.getLocale (), "index.html"); + System.err.println ("coucou file:"+newURL+" --- "+newURL.toURI ()); + + java.awt.Desktop.getDesktop ().browse (newURL.toURI ()); + // XXX + } catch (Exception e) { + e.printStackTrace (); + } + } + + // ======================================== + public void displayDisplayUnit (Object... objects) { + @SuppressWarnings("unchecked") + List> selectedUnits = (List>) objects[0]; + jAdecWattDialog.display (false, selectedUnits); + } + public void displayModifyUnit (Object... objects) { + @SuppressWarnings("unchecked") + List> selectedUnits = (List>) objects[0]; + jAdecWattDialog.display (true, selectedUnits); + } + public void displayRenameUnit (Object... objects) { + @SuppressWarnings("unchecked") + List> selectedUnits = (List>) objects[0]; + if (selectedUnits.size () != 1) { + System.err.println ("coucou pb selectedUnits:"+selectedUnits); + return; + } + Unit unit = (Unit) selectedUnits.get (0); + if (unit.getParent () == null) + return; + String name = jAdecWattDialog.getName (unit.getName ()); + unit.storyTransform (null, null, name, null); + } + public void displayTransformUnit (Object... objects) { + jAdecWattDialog.transform ((Unit) objects[0]); + } + public void displayCopyUnit (Object... objects) { + Unit unit = (Unit) objects[0]; + String name = jAdecWattDialog.getName (unit.getName ()); + if (name == null) + return; + unit.getCopy (name); + } + public void displayNewUnit (Object... objects) { + Unit unit = (Unit) objects[0]; + String name = jAdecWattDialog.getName (unit.getName ()); + if (name == null) + return; + unit.getNewChild (name); + } + public void displayPromoteUnit (Object... objects) { + Unit unit = (Unit) objects[0]; + ImageDB iconDB = adecWatt.getIconDB (); + ImageDB imageDB = adecWatt.getImageDB (); + HashSet> units = new HashSet> (); + TreeSet icons = new TreeSet (); + TreeSet images = new TreeSet (); + unit.findPromote (units, icons, images); + iconDB.renameVisitor (icons); + imageDB.renameVisitor (images); + permanentDB.renameVisitor (units); + if (!jAdecWattDialog.validation ("PromoteConfirmation", unit.getLocalName (), unit.getLocation (), + units, icons, images)) + return; + iconDB.promote (icons); + imageDB.promote (images); + permanentDB.promote (units); + } + public void displayRemoveUnit (Object... objects) { + Unit unit = (Unit) objects[0]; + if (!jAdecWattDialog.validation ("RemoveConfirmation", unit.getLocalName (), unit.getLocation ())) + return; + unit.remove (); + } + public void displayConnection (Object... objects) { + // XXX jAdecWatt.getJWorkspace ((Workspace) objects[0]).updateConnectionLayer (); + } + + // ======================================== + + public void displayDisplayItem (Object... objects) { + @SuppressWarnings ("unchecked") + List> selectedItems = (List>) objects[0]; + jAdecWattDialog.display (false, selectedItems); + } + public void displayModifyItem (Object... objects) { + @SuppressWarnings("unchecked") + List> selectedItems = (List>) objects[0]; + jAdecWattDialog.display (true, selectedItems); + } + public void displayHideShowItem (Object... objects) { + JWorkspaceView jWorkspaceView = (JWorkspaceView) objects[0]; + @SuppressWarnings ("unchecked") + List selectedItems = (List) objects[1]; + Boolean hidden = (Boolean) objects[2]; + jWorkspaceView.hideShowItem (selectedItems, hidden); + } + public void displayTransformItem (Object... objects) { + jAdecWattDialog.transform ((Item) objects[0]); + } + public void displayCopyItem (Object... objects) { + JWorkspaceView jWorkspaceView = (JWorkspaceView) objects[0]; + @SuppressWarnings ("unchecked") + List selectedItems = (List) objects[1]; + Point pos = (Point) objects[2]; + jWorkspaceView.cloneItem (selectedItems.get (0), pos); + } + public void displayRemoveItem (Object... objects) { + JWorkspaceView jWorkspaceView = (JWorkspaceView) objects[0]; + @SuppressWarnings ("unchecked") + List selectedItems = (List) objects[1]; + jWorkspaceView.eraseItem (selectedItems); + } + @SuppressWarnings ("unchecked") + public void displaySetSelectionItems (Object... objects) { + try { + jAdecWatt.getJWorkspace ((Workspace) objects[0]).setSelectedItems ((List) objects[1]); + } catch (Exception e) { + } + } + + // ======================================== + public void displayDisplayAcc (Object... objects) { + @SuppressWarnings("unchecked") + List> selectedAccs = (List>) objects[0]; + jAdecWattDialog.display (false, selectedAccs); + } + public void displayModifyAcc (Object... objects) { + @SuppressWarnings("unchecked") + List> selectedAccs = (List>) objects[0]; + jAdecWattDialog.display (true, selectedAccs); + } + public void displayTransformAcc (Object... objects) { + jAdecWattDialog.transform ((Acc) objects[0]); + } + public void displayRemoveAcc (Object... objects) { + JWorkspaceView jWorkspaceView = (JWorkspaceView) objects[0]; + Acc acc = (Acc) objects[1]; + jWorkspaceView.eraseAcc (acc); + } + + // ======================================== + // private Editable lastSelection; + // private Editable lastCopy; + // public void displayEditableSelection (Object... objects) { + // lastSelection = (Editable) objects[0]; + // } + // YYY faire remove/copie/paste avec + + // ======================================== +} + diff --git a/src/java/adecWatt/control/LaunchAdecWatt.java b/src/java/adecWatt/control/LaunchAdecWatt.java new file mode 100644 index 0000000..fb50daa --- /dev/null +++ b/src/java/adecWatt/control/LaunchAdecWatt.java @@ -0,0 +1,77 @@ +package adecWatt.control; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import misc.Bundle; +import misc.Config; +import misc.RemoteUpdate; + +import adecWatt.model.AdecWatt; +import adecWatt.view.JProp; + +public class LaunchAdecWatt { + + // ======================================== + static public void main (String[] args) { + try { + Config.setPWD (LaunchAdecWatt.class); + Config.load ("AdecWatt"); + Bundle.load ("Help"); + Bundle.load ("ToolBar"); + Bundle.load ("Proxy"); + Bundle.load ("RemoteUpdate"); + Bundle.load ("Story"); + Bundle.load ("Controller"); + Bundle.load ("AdecWatt"); + Bundle.load (JProp.AdecWattUser); + + updateShell (); + + final AdecWatt adecWatt = new AdecWatt (); + SwingUtilities.invokeLater (new Runnable () { + public void run () { + AdecWattController adecWattController = new AdecWattController (adecWatt); + adecWatt.broadcastDisplay ("Console", Bundle.getMessage ("Welcome")); + adecWattController.updateUserChangeProfil (); + } + }); + } catch (Exception e) { + File softDir = new File (Config.getPWD ().getParentFile (), "soft"); + File jar = new File (softDir, "UpdatedAdecWatt.jar"); + RemoteUpdate.launch (jar); + } + } + + public static void updateShell () { + try { + File dir = Config.getPWD ().getParentFile (); + File oldLaunch = new File (dir, "launch-lightPlot.sh"); + File softDir = new File (dir, "soft"); + File newJar = new File (softDir, "AdecWatt.jar"); + File oldJar = new File (softDir, "LightPlot.jar"); + if (newJar.length () < 1024) + return; + if (oldLaunch.length () > 70) { + PrintWriter pw = new PrintWriter (oldLaunch); + pw.println ("#!/bin/bash"); + pw.println ("cd `dirname \"$0\"`"); + pw.println ("java -jar soft/AdecWatt.jar"); + pw.flush (); + pw.close (); + JOptionPane.showMessageDialog (null, + "Votre logiciel a \u00E9t\u00E9 mis \u00E0 jour.\n"+ + "Vous devez relancer l'application\n", "Information", JOptionPane.ERROR_MESSAGE); + System.exit (0); + } + if (oldJar.exists ()) + oldJar.delete (); + } catch (FileNotFoundException e) { + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/control/LaunchUpdatedAdecWatt.java b/src/java/adecWatt/control/LaunchUpdatedAdecWatt.java new file mode 100644 index 0000000..10c7a9c --- /dev/null +++ b/src/java/adecWatt/control/LaunchUpdatedAdecWatt.java @@ -0,0 +1,22 @@ +package adecWatt.control; + +import java.io.File; + +import misc.Config; +import misc.RemoteUpdate; + +public class LaunchUpdatedAdecWatt { + + // ======================================== + static public void main (String[] args) { + Config.setPWD (LaunchUpdatedAdecWatt.class); + File dir = Config.getPWD ().getParentFile (); + RemoteUpdate.renameNewFile (dir); + + File softDir = new File (dir, "soft"); + File jar = new File (softDir, "AdecWatt.jar"); + RemoteUpdate.launch (jar); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/Acc.java b/src/java/adecWatt/model/Acc.java new file mode 100644 index 0000000..04ce42b --- /dev/null +++ b/src/java/adecWatt/model/Acc.java @@ -0,0 +1,198 @@ +// XXX test eclipse + +package adecWatt.model; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Collection; +import misc.DimensionDouble; +import misc.ScaledImage; +import misc.Story; + +import adecWatt.model.unit.Accessory; +import adecWatt.model.unit.Workspace; +import adecWatt.model.xml.XmlAcc; + +public class Acc extends Embedded, Acc> { + // ======================================== + public Collection getModifiersSet () { return AccModifiersSet; } + public AccTypeEnum getTypeToken () { return AccTypeEnum.Accessory; } + public AccAttrEnum getNameToken () { return AccAttrEnum.Name; } + public AccAttrEnum getModifierToken () { return AccAttrEnum.Modifier; } + public AccAttrEnum getPlaceIdToken () { return AccAttrEnum.Placeid; } + public AccAttrEnum getModelToken () { return AccAttrEnum.Model; } + + public Workspace getStoryUnit () { return ((Comp)container).container; } + public Acc getLink (Editable support) { return new Acc (name, placeId, support, (Accessory) model); } + + // ======================================== + public Acc (Editable support, XmlAcc xmlAcc) { + super (support, xmlAcc); + } + public Acc (String name, String placeName, Editable support, Accessory model) { + super (name, placeName, support, model); + } + public Acc (Editable support, Accessory model) { + super (null, "", support, model); + } + public Acc clone (Editable support) { + Acc result = new Acc (support, (Accessory) model); + result.importFrom (this); + return result; + } + + // ======================================== + public boolean search (String text) { + if (getName ().toLowerCase ().indexOf (text) >= 0 || + getLocalName ().toLowerCase ().indexOf (text) >= 0 || + getId ().indexOf (text) >= 0) + return true; + return false; + } + + public String getCircuit (Comp realContainer) { + String result = super.getCircuit (); + if (result != null) + return result; + return realContainer.getCircuit (); + } + public double getWatt (Comp realContainer) { + double result = super.getWatt (); + if (result > 0) + return result; + return realContainer.getWatt (); + } + + // ======================================== + public void validateContainer (Story.Commands commands, String commandName) { + container.validateContainer (commands, commandName); + if (container.getLocalEmbedded (getId ()) == this) + return; + Story story = commands.getStory (); + commands.add (story.new Command (commandName) { + @SuppressWarnings ("unchecked") + public void exec () { ((Editable>) container).addEmbedded (Acc.this); } + @SuppressWarnings ("unchecked") + public void undo () { ((Editable>) container).removeEmbedded (Acc.this); } + public void display () { container.updateView (); } + }); + } + + public void storyChange (Story.Commands commands, ArrayList changeProps) { + storyChange (commands, true, ownProps, changeProps); + } + public void storyTransform (Story.Commands commands, Collection modifiers, Unit permanent, String newName, ArrayList transProps) { + storyTransform (commands, null, modifiers, permanent, ownProps, transProps); + } + public void updateView () { + ((Comp) container).updateView (); + } + + // ======================================== + public void changeConnectedTo (String connectedTo) { + getLocalProp (Prop.PropConnectedTo, Prop.PropTypeEnum.Text).setValue (connectedTo); + } + public void changeConnectedOn (String connectedOn) { + getLocalProp (Prop.PropConnectedOn, Prop.PropTypeEnum.Text).setValue (connectedOn); + } + + // ======================================== + public String toString () { + return getName (); + } + + // ======================================== + public void print (Graphics2D printGraphics, Comp comp) { + Point2D.Double accPos = getPos (); + DimensionDouble accSize = getSize (); + ScaledImage accIcon = getIcon (); + if (comp.isLow ()) { + ScaledImage scaledLowImage = getLowIcon (); + if (scaledLowImage != null) + accIcon = scaledLowImage; + } + Color accColor = getColor (); + if (accColor != null) + accIcon = comp.getAdecWatt ().getIconDB ().getColoredScaledImages (accIcon, accColor); + DimensionDouble compSize = comp.getSize (); + if (accSize.width < 0) + accSize.width *= -compSize.width; + if (accSize.height < 0) + accSize.height *= -compSize.height; + accPos.x = accPos.x < 0 ? (-accPos.x-.5)*(compSize.width-accSize.width) : accPos.x - (compSize.width-accSize.width)/2.; + accPos.y = accPos.y < 0 ? (-accPos.y-.5)*(compSize.height-accSize.height) : accPos.y - (compSize.height-accSize.height)/2.; + // XXX double accThetaDegree = acc.getThetaDegree (); + double thetaDegree = comp.getThetaDegree (); + AffineTransform at = AffineTransform.getRotateInstance (Math.toRadians ((int) thetaDegree)); + double [] center = new double [] {accPos.x, accPos.y}; + at.transform (center, 0, center, 0, 1); + Point2D.Double compPos = comp.getPos (); + Point2D.Double absPos = new Point2D.Double (compPos.getX ()+center[0], compPos.getY ()+center[1]); + String id = getId (); + comp.accCenter.put (id, absPos); + comp.accSize.put (id, accSize); + Workspace.printImage (printGraphics, accIcon, absPos, accSize, thetaDegree, null); + Workspace.printText (printGraphics, getLabel (), getLabelColor (), absPos, accSize, thetaDegree); + } + + // ======================================== + static public final BasicStroke solidConnection = new BasicStroke (2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + static public final Color connectionColor = Color.GRAY; + static public final Color boxColor = new Color (0, 1, 0, .5F); + static public final Color warningColor = new Color (1, .5F, 0, .7F); + static public final Color errorColor = new Color (1, 0, 0, .7F); + static public final Color circuitColor = Color.BLACK; + + static public void printCircuit (Graphics2D connectionGraphics, double printScale, Point2D center, Circuits.CircuitState circuitState) { + printCircuit (connectionGraphics, center, circuitState, 20/printScale); + } + static public void printCircuit (Graphics2D connectionGraphics, Point2D center, Circuits.CircuitState circuitState, double boxSide) { + Ellipse2D.Double box = new Ellipse2D.Double (center.getX ()-boxSide/2, center.getY ()-boxSide/2, boxSide, boxSide); + Color color = boxColor; + switch (circuitState.state) { + case PLUG: + break; + case LOOP: + case UNPLUG: + color = warningColor; + break; + case SHORTCUT: + color = errorColor; + } + connectionGraphics.setPaint (color); + connectionGraphics.fill (box); + if (circuitState.name == null) + return; + Workspace.printText (connectionGraphics, String.format ("%2s", circuitState.name), + circuitColor, center, new DimensionDouble (boxSide, boxSide)); + } + + static public void printConnection (Graphics2D connectionGraphics, double printScale, Point2D begin, Point2D end) { + printConnection (connectionGraphics, begin, end, + 20/printScale, new BasicStroke ((float)(2/printScale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + } + static public void printConnection (Graphics2D connectionGraphics, Point2D begin, Point2D end, double boxSide) { + printConnection (connectionGraphics, begin, end, boxSide, solidConnection); + } + static public void printConnection (Graphics2D connectionGraphics, Point2D begin, Point2D end, + double boxSide, BasicStroke solidConnection) { + GeneralPath gp = new GeneralPath (Path2D.WIND_NON_ZERO); + gp.moveTo (begin.getX (), begin.getY ()); + if (Math.abs (begin.getX ()-end.getX ()-1) < Math.abs (begin.getY ()-end.getY ())) + gp.curveTo (begin.getX (), end.getY (), end.getX (), begin.getY (), end.getX (), end.getY ()); + else + gp.curveTo (end.getX (), begin.getY (), begin.getX (), end.getY (), end.getX (), end.getY ()); + connectionGraphics.setPaint (connectionColor); + connectionGraphics.setStroke (solidConnection); + connectionGraphics.draw (gp); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/AdecWatt.java b/src/java/adecWatt/model/AdecWatt.java new file mode 100644 index 0000000..22ee5d0 --- /dev/null +++ b/src/java/adecWatt/model/AdecWatt.java @@ -0,0 +1,119 @@ +package adecWatt.model; + +import java.io.File; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.TreeMap; +import javax.swing.JOptionPane; + +import misc.Bundle; +import misc.Config; +import misc.RemoteUpdate; +import misc.StateNotifier; +import misc.Story; + +/** + */ +public class AdecWatt extends StateNotifier { + + static public final double lowLevel = 0.3; + + static public final String + BroadcastUnitRoots = "UnitRoots", + BroadcastConsole = "Console", + BroadcastUnitStory = "UnitStory", + BroadcastStory = Story.BroadcastStory, + BroadcastTitle = "Title", + BroadcastUpdateUnitTree = "UpdateUnitTree", //UpdateWorkspaceTree + BroadcastUpdateWorkspace = "UpdateWorkspace"; + + // ======================================== + private ImageDB iconDB = new ImageDB (this, ImageDB.iconDirName); + private ImageDB imageDB = new ImageDB (this, ImageDB.imageDirName); + private PermanentDB permanentDB = new PermanentDB (this); + private InseeDB inseeDB; + private User user = new User (); + private boolean + handleGlue = Config.getBoolean ("HandleGlue", true), + boundGlue = Config.getBoolean ("BoundGlue", true), + gridGlue = Config.getBoolean ("GridGlue", true), + inSegmentGlue = Config.getBoolean ("InSegmentGlue", true); + + public User getUser () { return user; } + public PermanentDB getPermanentDB () { return permanentDB; } + public ImageDB getIconDB () { return iconDB; } + public ImageDB getImageDB () { return imageDB; } + public InseeDB getInseeDB () { return inseeDB; } + public Hashtable> getNamedRoots () { return permanentDB.namedRoots; } + public boolean getHandleGlue () { return handleGlue; } + public boolean getBoundGlue () { return boundGlue; } + public boolean getGridGlue () { return gridGlue; } + public boolean getInSegmentGlue () { return inSegmentGlue; } + public void setHandleGlue (boolean handleGlue) { Config.setBoolean ("HandleGlue", this.handleGlue = handleGlue); } + public void setBoundGlue (boolean boundGlue) { Config.setBoolean ("BoundGlue", this.boundGlue = boundGlue); } + public void setGridGlue (boolean gridGlue) { Config.setBoolean ("GridGlue", this.gridGlue = gridGlue); } + public void setInSegmentGlue (boolean inSegmentGlue) { Config.setBoolean ("InSegmentGlue", this.inSegmentGlue = inSegmentGlue); } + + // ======================================== + public AdecWatt () { + reset (); + } + + public void reloadSoft () { + if (JOptionPane.showConfirmDialog (null, Bundle.getMessage ("UpdateSoft"), + Bundle.getTitle ("UpdateSoft"), + JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) + return; + File softDir = new File (Config.getPWD ().getParentFile (), "soft"); + File jar = new File (softDir, "UpdatedAdecWatt.jar"); + RemoteUpdate.launch (jar); + } + + public void reset () { + File dir = Config.getPWD ().getParentFile (); + RemoteUpdate.renameNewFile (dir); + if (RemoteUpdate.newFileExists (dir)) + reloadSoft (); + iconDB.reload (); + imageDB.reload (); + permanentDB.reload (); + inseeDB = InseeDB.readDocument (Config.getDataUrl ("data", "server", "Insee.xml")); + broadcastUpdate (BroadcastUnitRoots); + } + + public void updateStory () { + broadcastUpdate (BroadcastStory); + } + + + // ======================================== + public void newNamePlan () { + TreeMap iconMap = iconDB.newNamePlan (); + TreeMap imageMap = imageDB.newNamePlan (); + permanentDB.newNamePlan (iconMap, imageMap); + saveAll (); + } + + // ======================================== + public boolean getModified () { + for (Unit unit : permanentDB.idUnit.values ()) + if (unit.story.isModified ()) + return true; + return false; + } + + // ======================================== + public void saveAll () { + for (Unit root : permanentDB.namedRoots.values ()) { + // if (root.story.isModified ()) + // root.save (); + for (Enumeration e = root.unitNode.depthFirstEnumeration (); e.hasMoreElements (); ) { + Unit unit = ((UnitNode) e.nextElement ()).getUnit (); + if (unit.story.isModified ()) + unit.save (); + } + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/Circuits.java b/src/java/adecWatt/model/Circuits.java new file mode 100644 index 0000000..7c9e3e4 --- /dev/null +++ b/src/java/adecWatt/model/Circuits.java @@ -0,0 +1,171 @@ +package adecWatt.model; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; +import java.util.TreeSet; + +import adecWatt.model.unit.Building; +import adecWatt.model.unit.Workspace; + +public class Circuits { + + static public enum State { + PLUG, LOOP, SHORTCUT, UNPLUG; + } + static public String SHORTCUT = "Shortcut"; + static public String UNPLUG = "Unplug"; + static public String CIRCUITLESS = "Circuitless"; + + static public Comparator lineComparator = + new Comparator () { + public int compare (String s1, String s2) { + if (s1 == s2) + return 0; + try { + int i1 = Integer.parseInt (s1); + int i2 = Integer.parseInt (s2); + return i1-i2; + } catch (Exception e) { + } + return s1.compareTo (s2); + } + }; + + static public class Circuit { + HashSet nodes = new HashSet (); + TreeSet names = new TreeSet (lineComparator); + int consumption; + Circuit (HashSet nodes, String name, int consumption) { + add (nodes, name, consumption); + } + void add (HashSet nodes, String name, int consumption) { + this.nodes.addAll (nodes); + this.consumption += consumption; + if (name == null || name.isEmpty ()) + return; + names.add (name); + } + } + + private HashSet loop = new HashSet (); + private HashMap allCircuits = new HashMap (); + private HashSet plugedComps; + + public Set keySet () { return allCircuits.keySet (); } + public Circuit get (Comp lastComp) { return allCircuits.get (lastComp); } + public HashSet getPlugedComps () { return plugedComps; } + public boolean inLoop (Acc acc) { return loop.contains (acc); } + + public Circuits (HashMap linked, HashSet plugedComps) { + this (linked); + this.plugedComps = plugedComps; + } + public Circuits (HashMap linked) { + loopStart: + for (Acc beginAcc : linked.keySet ()) { + Comp beginComp = (Comp) beginAcc.getContainer (); + int consumption = (int) beginAcc.getWatt (beginComp); + HashSet nodes = new HashSet (); + nodes.add (beginAcc); + String name = beginAcc.getCircuit (beginComp); + Comp lastComp = null; + parseThread: + for (;;) { + Comp nextComp = linked.get (beginAcc); + if (nextComp == null) + break; + lastComp = nextComp; + for (String nextAccId : nextComp.getEmbeddedIds ()) + try { + Acc nextAcc = nextComp.findEmbedded (nextAccId); + if (nextAcc.getConnectedTo () == null) + continue; + if (nodes.contains (nextAcc)) { + loop.addAll (nodes); + continue loopStart; + } + nodes.add (nextAcc); + beginAcc = nextAcc; + continue parseThread; + } catch (Exception e) { + } + break; + } + Circuit circuit = allCircuits.get (lastComp); + if (circuit == null) { + allCircuits.put (lastComp, new Circuit (nodes, name, consumption)); + continue; + } + circuit.add (nodes, name, consumption); + } + } + + static public Circuits getCircuits (Workspace workspace, String plugId) { + Hashtable namedComps = new Hashtable (); + for (Item item : workspace.getInheritedEmbeddedValues ()) + try { + namedComps.put (item.getId (), (Comp) item); + } catch (Exception e) { + } + Building building = workspace.getBuilding (); + if (building != null) + for (Item item : building.getInheritedEmbeddedValues ()) + try { + namedComps.putIfAbsent (item.getId (), (Comp) item); + } catch (Exception e) { + } + HashSet plugedComps = new HashSet (); + HashMap linked = new HashMap (); + for (Comp beginComp : namedComps.values ()) { + if (beginComp.isReserved ()) + continue; + for (String accId : beginComp.getEmbeddedIds ()) + try { + Acc beginAcc = beginComp.findEmbedded (accId); + if (beginAcc.getDirectUnit ().isDescendingFrom (plugId)) + plugedComps.add (beginComp); + Comp nextComp = namedComps.get (beginAcc.getConnectedTo ()); + linked.put (beginAcc, nextComp); + } catch (Exception e) { + } + } + return new Circuits (linked, plugedComps); + } + + static public class CircuitState { + public String name; + public State state; + public CircuitState (State state, String name) { + this.name = name; + this.state = state; + } + } + + public CircuitState getState (Comp comp, Acc acc) { + if (acc == null) + return null; + String circuitName = acc.getCircuit (comp); + if (loop.contains (acc)) + return new CircuitState (State.LOOP, circuitName); + for (Comp lastComp : allCircuits.keySet ()) { + Circuit circuit = allCircuits.get (lastComp); + if (!circuit.nodes.contains (acc)) + continue; + switch (circuit.names.size ()) { + case 0: + return null; + case 1: + // XXX limitation pour doublette ? + // if (circuitName == null) + // return null; + return new CircuitState (lastComp.getLine () == null ? State.UNPLUG : State.PLUG, circuit.names.first ()); + default: + return new CircuitState (State.SHORTCUT, circuitName); + } + } + return circuitName == null ? null : new CircuitState (State.UNPLUG, circuitName); + } +} diff --git a/src/java/adecWatt/model/Comp.java b/src/java/adecWatt/model/Comp.java new file mode 100644 index 0000000..4930f50 --- /dev/null +++ b/src/java/adecWatt/model/Comp.java @@ -0,0 +1,121 @@ +package adecWatt.model; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Point2D; +import java.util.Collection; +import java.util.HashSet; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.DimensionDouble; +import misc.ScaledImage; +import adecWatt.model.unit.NonWorkspace; +import adecWatt.model.unit.Workspace; +import adecWatt.model.xml.XmlComp; + +public class Comp extends Item { + // ======================================== + public int available; + + // ======================================== + public Collection getModifiersSet () { return CompModifiersSet; } + public CompTypeEnum getTypeToken () { return CompTypeEnum.Component; } + public CompAttrEnum getNameToken () { return CompAttrEnum.Name; } + public CompAttrEnum getModifierToken () { return CompAttrEnum.Modifier; } + public CompAttrEnum getPlaceIdToken () { return CompAttrEnum.Placeid; } + public CompAttrEnum getModelToken () { return CompAttrEnum.Model; } + + public Comp getLink (Editable workspace) { return new Comp (name, placeId, (Workspace) workspace, model); } + + // ======================================== + public Comp (Workspace workspace, XmlComp xmlComp) { + super (workspace, xmlComp); + try { + available = Integer.parseInt (xmlComp.getFacet (CompAttrEnum.Available)); + } catch (Exception e) { + } + } + public Comp (String name, String placeName, Workspace workspace, NonWorkspace model) { + super (name, placeName, workspace, model); + } + public Comp (Workspace workspace, NonWorkspace model) { + super (null, null, workspace, model); + } + public Comp clone (Workspace workspace) { + Comp result = new Comp (workspace, model); + result.importFrom (this); + return result; + } + + // ======================================== + public Element getXml (Node parent, Document document) { + Element child = super.getXml (parent, document); + if (isReserved ()) + XmlComp.putFacet (child, CompAttrEnum.Available, ""+available); + return child; + } + + // ======================================== + public void changeThetaDegree (double thetaDegree) { + if (isSticky ()) + return; + getLocalProp (Prop.PropRot, Prop.PropTypeEnum.Cube).setThetaDegree (thetaDegree); + } + public void changeSize (DimensionDouble size) { + if (isSticky ()) + return; + getLocalProp (Prop.PropSize, Prop.PropTypeEnum.Cube).setSize (size); + } + + // ======================================== + public String getLine () { + try { + String name = getPropVal (Prop.PropLine).sValue; + if (!name.isEmpty ()) + return name; + } catch (Exception e) { + } + return null; + } + + // ======================================== + public HashSet allPlugs = new HashSet (); + public static String plugId; + + public void print (Graphics2D printGraphics, Workspace workspace, String plugId) { + this.plugId = plugId; + print (printGraphics, workspace, getPos (), getSize (), getThetaDegree ()); + } + + public void print (Graphics2D printGraphics, Workspace workspace, Point2D pos, DimensionDouble size, double thetaDegree) { + accCenter.clear (); + accSize.clear (); + allPlugs.clear (); + ScaledImage scaledImage = getIcon (); + if (isLow ()) { + ScaledImage scaledLowImage = getLowIcon (); + if (scaledLowImage != null) + scaledImage = scaledLowImage; + } + Color compColor = getColor (); + if (compColor != null) + scaledImage = getAdecWatt ().getIconDB ().getColoredScaledImages (scaledImage, compColor); + Workspace.printImage (printGraphics, scaledImage, pos, size, thetaDegree, getTileSize ()); + double minSide = Math.min (size.width, size.height); + Workspace.printText (printGraphics, getLabel (), getLabelColor (), pos, new DimensionDouble (minSide, minSide)); + for (String accId : getEmbeddedIds ()) + try { + Acc acc = findEmbedded (accId); + acc.print (printGraphics, this); + if (acc.getDirectUnit ().isDescendingFrom (plugId)) { + workspace.addPlugedComps (this); + allPlugs.add (acc); + } + } catch (Exception e) { + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/Editable.java b/src/java/adecWatt/model/Editable.java new file mode 100644 index 0000000..7f3c40c --- /dev/null +++ b/src/java/adecWatt/model/Editable.java @@ -0,0 +1,1095 @@ +package adecWatt.model; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; +import javax.swing.ImageIcon; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.DimensionDouble; +import misc.ScaledImage; +import misc.Story; +import misc.Util; + +import adecWatt.model.unit.Building; +import adecWatt.model.xml.*; + +public abstract class Editable

, + T extends Enum, + A extends Enum, + E extends Embedded> + extends Permanent { + // ======================================== + static public final String + StoryAddAcc = "AddAcc", + StoryAddItem = "AddItem", + StoryAddProp = "AddProp", + StoryAddSpinProp = "AddSpinProp", + StoryChangeBuilding = "ChangeBuilding", + StoryChangeEnum = "ChangeEnum", + StoryChangeLabels = "ChangeLabels", + StoryChangeModifiers = "ChangeModifiers", + StoryChangeName = "ChangeName", + StoryChangeParent = "ChangeParent", + StoryChangeSpin = "ChangeSpin", + StoryChangeType = "ChangeType", + StoryChangeValue = "ChangeValue", + StoryClearProp = "ClearProp", + StoryCloneItem = "CloneItem", + StoryConnectAcc = "ConnectAcc", + StoryEdit = "Edit", + StoryHideItem = "HideItem", + StoryLinkAcc = "LinkAcc", + StoryLinkEmb = "LinkEmb", + StoryLinkItem = "LinkItem", + StoryMoveItem = "MoveItem", + StoryOrderedProp = "OrderedProp", + StoryPasteItem = "PasteItem", + StoryRemoveAcc = "RemoveAcc", + StoryRemoveEnum = "RemoveEnum", + StoryRemoveItem = "RemoveItem", + StoryRemoveLabels = "RemoveLabels", + StoryRemoveProp = "RemoveProp", + StoryRotItem = "RotItem", + StoryRotResizeItem = "RotResizeItem", + StorySelectItem = "SelectItem", + StoryTransform = "Transform"; + + // ======================================== + protected Hashtable ownProps = new Hashtable (); + protected String embeddedPrefix = "c"; // XXX dans Unit et pas dans comp + private int embIdCount; + protected Hashtable embedded; + + // ======================================== + public abstract AdecWatt getAdecWatt (); + public abstract String getId (); + public abstract Editable getParent (); + public abstract Unit getDirectUnit (); + public abstract Unit getParentUnit (); + public abstract Unit getStoryUnit (); + public abstract Editable getModel (); + public Editable getContainer () { return null; } + + // public boolean hasChild (String childName) { return false; } + public E getLocalEmbedded (String id) { return embedded == null ? null : embedded.get (id); } + public Hashtable getLocalEmbedded () { return embedded; } + + public abstract void setParentUnit (Unit parent); + + public boolean match (String text) { + return + Util.removeAccent (getName ()).toLowerCase ().indexOf (text) >= 0 || + Util.removeAccent (getLocalName ()).toLowerCase ().indexOf (text) >= 0 || + getId ().indexOf (text) >= 0; + } + + public boolean parentMatch (String text) { + for (Editable editable = this; editable != null; editable = editable.getParentUnit ()) + if (editable.match (text)) + return true; + return false; + } + + // ======================================== + private ArrayList reservedEmbName; + private boolean isReservedEmbName (String name) { + return reservedEmbName != null && reservedEmbName.contains (name); + } + private void reservedEmbName (String name) { + if (reservedEmbName == null) + reservedEmbName = new ArrayList (); + reservedEmbName.add (name); + } + private void freeEmbName (String name) { + if (reservedEmbName == null) + return; + reservedEmbName.remove (name); + if (reservedEmbName.size () == 0) + reservedEmbName = null; + } + public String getUniqName () { + String thisId = getId (); + for (; ; embIdCount++) { + String embeddedName = embeddedPrefix+embIdCount; + if (embedded != null && embedded.containsKey (thisId+":"+embeddedName)) + continue; + if (isReservedEmbName (embeddedName)) + continue; + reservedEmbName (embeddedName); + return embeddedName; + } + } + @SuppressWarnings ("unchecked") + public E getCloseEmbedded (E emb) { + if (embedded == null) + embedded = new Hashtable (); + E result = embedded.get (emb.getId ()); + if (result == null) + // attention emb doit exister ! + result = (E) emb.getLink (this); + return result; + } + @SuppressWarnings ("unchecked") + public E findEmbedded (String id) { + for (Editable editable = this; + editable != null; + editable = editable.getParent ()) { + E emb = editable.getLocalEmbedded (id); + if (emb != null) + return emb; + } + Editable model = getModel (); + if (model != null) + for (Editable editable = (Editable) model; + editable != null; + editable = editable.getParent ()) { + E emb = editable.getLocalEmbedded (id); + if (emb != null) + return emb; + } + return null; + } + public E findEmbeddedRootOf (Unit model) { + for (String embId : getEmbeddedIds ()) { + E emb = findEmbedded (embId); + if (emb == null || !model.isDescendingFrom (emb.getModel ().getId ())) + continue; + return emb; + } + return null; + } + + public E findEmbeddedBaseOn (String parentId) { + for (String embId : getEmbeddedIds ()) { + E emb = findEmbedded (embId); + if (emb == null || !emb.getDirectUnit ().isDescendingFrom (parentId)) + continue; + return emb; + } + return null; + } + + public TreeSet getEmbeddedIds () { + TreeSet result = new TreeSet (); + for (Editable editable = this; editable != null; editable = editable.getParent ()) { + if (editable.embedded == null) + continue; + result.addAll (editable.embedded.keySet ()); + } + Editable model = getModel (); + if (model != null) + for (Editable editable = model; editable != null; editable = editable.getParent ()) { + if (editable.embedded == null) + continue; + result.addAll (editable.embedded.keySet ()); + } + return result; + } + + // ======================================== + public void addEmbedded (E emb) { + if (embedded == null) + embedded = new Hashtable (); + String embId = emb.getId (); + if (embedded.get (embId) != null) + System.err.println ("Already embedded name recorded ("+embId+" = "+emb.getName ()+" in "+name+")."); + embedded.put (embId, emb); + freeEmbName (embId); + } + public void removeEmbedded (E emb) { + if (embedded == null) + return; + embedded.remove (emb.getId ()); + } + public Collection getInheritedEmbeddedValues () { + Hashtable inherited = getInheritedEmbedded (); + if (inherited == null) + return new Vector (); + return inherited.values (); + } + + @SuppressWarnings ("unchecked") + public Hashtable getInheritedEmbedded () { + Editable parent = getParent (); + if (parent == null) + return embedded; + Hashtable result = parent.getInheritedEmbedded (); + if (result == null) + return embedded; + if (embedded == null) + return result; + result = (Hashtable) result.clone (); + // for (String key : embedded.keySet ()) + // result.put (key, embedded.get (key)); + result.putAll (embedded); + return result; + } + @SuppressWarnings ("unchecked") + public Hashtable getAllEmbedded () { + // + + // si workspace le dernier building dans les getparentunit + // si comp le dernier modèle dans le + Editable pattern = getModel (); + Hashtable result = getInheritedEmbedded (); + if (pattern == null) + return result; + Hashtable resultP = (Hashtable) pattern.getInheritedEmbedded (); + if (result == null) + return resultP; + if (resultP == null) + return result; + resultP = (Hashtable) resultP.clone (); + resultP.putAll (result); + return resultP; + } + + public abstract void storyChange (Story.Commands commands, ArrayList changeProps); + public abstract void storyTransform (Story.Commands commands, Collection modifiers, Unit permanent, String newName, ArrayList transProps); + public void storyTransform (Collection modifiers, Unit permanent, String newName, ArrayList transProps) { + Story story = getStoryUnit ().story; + Story.Commands commands = story.new Commands (StoryTransform) { + public void display () { updateView (); } + }; + storyTransform (commands, modifiers, permanent, newName, transProps); + story.add (commands); + } + + // ======================================== + protected Editable () { + } + protected Editable (P xmlPermanent) { + super (xmlPermanent); + collectOwnProps (); + } + protected void initXml (P xmlPermanent) { + super.initXmlAvantOwnProp (xmlPermanent); + collectOwnProps (); + } + public void collectEmbedded () { + if (xmlPermanent == null) + return; + for (XmlAcc xmlAcc : xmlPermanent.getAccs ()) { + Acc acc = new Acc (this, xmlAcc); + acc.fixName (false); + } + } + + // ======================================== + public void importFrom (Editable from) { + super.importFrom (from); + for (String propName : from.ownProps.keySet ()) + ownProps.putIfAbsent (propName, from.ownProps.get (propName).clone ()); + if (from.embedded == null) + return; + if (embedded == null) + embedded = new Hashtable (); + // XXX ??? n'y a-t-il pas partage des emb ? + for (String embId : from.embedded.keySet ()) + embedded.putIfAbsent (embId, from.embedded.get (embId)); + } + + public void newNamePlan (HashSet> visited, TreeMap iconMap, TreeMap imageMap) { + if (visited.contains (this)) + return; + visited.add (this); + if (embedded != null) + for (E emb : embedded.values ()) + emb.newNamePlan (visited, iconMap, imageMap); + Story story = getStoryUnit ().story; + Story.Commands commands = story.new Commands (StoryEdit) { + public void display () { } + }; + for (String propName : ownProps.keySet ()) { + final Prop prop = getPropVal (propName); + if (prop == null) + continue; + TreeMap map = null; + switch (prop.getTypeToken ()) { + case Icon: + map = iconMap; + break; + case Image: + map = imageMap; + break; + default: + continue; + } + final String newValue = map.get (prop.sValue); + if (newValue == null) + continue; + commands.add (story.new Command (StoryChangeValue+" "+prop.name) { + String oldValue = prop.sValue; + public void exec () { prop.setValue (newValue); } + public void undo () { prop.setValue (oldValue); } + }); + } + story.add (commands); + } + public boolean renameUnits (TreeMap translateMap) { + Editable parent = getParent (); + boolean result = parent != null && translateMap.containsValue (parent.getId ()); + if (embedded != null) + for (E emb : embedded.values ()) + result |= emb.renameUnits (translateMap); + for (String propName : ownProps.keySet ()) { + Prop prop = getPropVal (propName); + if (prop == null) + continue; + switch (prop.getTypeToken ()) { + case Text: + case Building: + String newVal = translateMap.get (prop.sValue); + if (newVal != null) { + prop.sValue = newVal; + result = true; + continue; + } + int idx = prop.sValue.indexOf (":"); + if (idx < 0) + continue; + newVal = translateMap.get (prop.sValue.substring (0, idx)); + if (newVal == null) + continue; + prop.sValue = newVal+prop.sValue.substring (idx); + result = true; + } + } + return result; + } + public boolean renameImages (TreeMap translateMap) { + boolean result = false; + if (embedded != null) + for (E emb : embedded.values ()) + result |= emb.renameImages (translateMap); + for (String propName : ownProps.keySet ()) { + Prop prop = getPropVal (propName); + if (prop == null) + continue; + switch (prop.getTypeToken ()) { + case Icon: + case Image: + String newVal = translateMap.get (Util.getBase (prop.sValue)); + if (newVal == null) + continue; + prop.sValue = newVal; + result = true; + break; + } + } + return result; + } + public void getLocalLink (HashSet> visited, + HashSet> unitLinks, TreeSet iconsLinks, TreeSet imagesLinks) { + if (visited.contains (this)) + return; + visited.add (this); + if (embedded != null) + for (E emb : embedded.values ()) + emb.getLocalLink (visited, unitLinks, iconsLinks, imagesLinks); + for (String propName : ownProps.keySet ()) { + Prop prop = getPropVal (propName); + if (prop == null) + continue; + switch (prop.getTypeToken ()) { + case Icon: + if (!getAdecWatt ().getIconDB ().isRemote (prop.sValue)) + iconsLinks.add (prop.sValue); + break; + case Image: + if (!getAdecWatt ().getImageDB ().isRemote (prop.sValue)) + imagesLinks.add (prop.sValue); + break; + case Building: + Building building = getBuilding (); + if (building == null) + continue; + building.getLocalLink (visited, unitLinks, iconsLinks, imagesLinks); + break; + } + } + } + + // ======================================== + public void removeOwnProp (String propName) { + ownProps.remove (propName); + } + + public void collectOwnProps () { + for (XmlProp xmlProp : xmlPermanent.getProps ()) { + Prop prop = new Prop (xmlProp); + ownProps.put (prop.name, prop); + } + } + public Prop getOwnProp (String propName) { + return ownProps.get (propName); + } + public ArrayList getOrderedOwnProps () { + return Prop.getOrderedProps (ownProps.values ()); + } + public ArrayList getOrderedPropsName () { + Unit parent = getParentUnit (); + ArrayList result = parent == null ? new ArrayList () : parent.getOrderedPropsName (); + for (Prop prop : getOrderedOwnProps ()) { + if (result.contains (prop.name)) + continue; + result.add (prop.name); + } + return result; + } + + public Element getXml (Node parent, Document document) { + Element child = super.getXml (parent, document); + ArrayList tmp = new ArrayList (ownProps.values ()); + tmp.sort (Prop.propComparator); + for (Prop prop : tmp) + prop.getXml (child, document); + if (embedded != null) + for (String embId : embedded.keySet ()) + embedded.get (embId).getXml (child, document); + return child; + } + + // ======================================== + public ScaledImage getIconFromFileName (String fileName, boolean horizontalSpin) { + return getAdecWatt ().getIconDB ().getImage (fileName, horizontalSpin); + } + public ScaledImage getImageFromFileName (String fileName, boolean horizontalSpin) { + return getAdecWatt ().getImageDB ().getImage (fileName, horizontalSpin); + } + public ImageIcon getIcon (int max) { + ScaledImage scaledIcon = getIcon (); + return scaledIcon == null ? null : scaledIcon.getSide (max); + } + + // ======================================== + public interface ComputeProp { + public R applyOnProp (Prop prop); + } + public R parentWalk (String propName, ComputeProp computeProp, boolean skipFirst) { + for (Editable editable = skipFirst ? getParent () : this; + editable != null; + editable = editable.getParent ()) + try { + R result = computeProp.applyOnProp (editable.ownProps.get (propName)); + if (result != null) + return result; + } catch (Exception e) { + } + return null; + } + public R parentAndModelWalk (String propName, ComputeProp computeProp, boolean skipFirst) { + R result = parentWalk (propName, computeProp, skipFirst); + if (result != null) + return result; + try { + result = getContainer ().getModel ().findEmbedded (getId ()).parentWalk (propName, computeProp, false); + if (result != null) + return result; + } catch (Exception e) { + } + try { + result = getModel ().parentWalk (propName, computeProp, false); + if (result != null) + return result; + } catch (Exception e) { + } + return null; + } + + // ======================================== + public Collection getPropModifiers (String propName) { + return getPropModifiers (propName, false); + } + public Collection getParentPropModifiers (String propName) { + return getPropModifiers (propName, true); + } + public Collection getPropModifiers (String propName, boolean skipFirst) { + return parentAndModelWalk (propName, new ComputeProp> () { + public Collection applyOnProp (Prop prop) { + return prop.modifiers; + } + }, skipFirst); + } + public String getPropModifiers (final String modifier, String propName) { + return parentAndModelWalk (propName, new ComputeProp () { + public String applyOnProp (Prop prop) { + if (prop.modifiers.contains (modifier)) + return modifier; + return null; + } + }, false); + } + public Collection getPropEnumChoice (String propName) { + return parentAndModelWalk (propName, new ComputeProp> () { + public Collection applyOnProp (Prop prop) { + if (prop != null && prop.enumChoice != null) + return prop.enumChoice; + return null; + } + }, false); + } + public List getPropLabel (String propName) { + return parentAndModelWalk (propName, new ComputeProp> () { + public List applyOnProp (Prop prop) { + return prop.multiLabel; + } + }, false); + } + public Prop getPropVal (String propName) { + return getPropVal (propName, false); + } + public Prop getParentPropVal (String propName) { + return getPropVal (propName, true); + } + public Prop getPropVal (String propName, boolean skipFirst) { + return parentAndModelWalk (propName, new ComputeProp () { + public Prop applyOnProp (Prop prop) { + if (prop != null && prop.sValue != null) // XXX et "".equals... + return prop; + return null; + } + }, skipFirst); + } + public Prop getProp (String propName) { + return getProp (propName, false); + } + public Prop getParentProp (String propName) { + return getProp (propName, true); + } + public Prop getProp (String propName, boolean skipFirst) { + return parentAndModelWalk (propName, new ComputeProp () { + public Prop applyOnProp (Prop prop) { + return prop; + } + }, skipFirst); + } + public Double[] getPartialProp (String propName, Double[] result) { + return getPartialProp (propName, result, false); + } + public Double[] getParentPartialProp (String propName, Double[] result) { + return getPartialProp (propName, result, true); + } + public Double[] getPartialProp (String propName, final Double[] result, boolean skipFirst) { + return parentAndModelWalk (propName, new ComputeProp () { + public Double[] applyOnProp (Prop prop) { + // XXX test nbVal >= result.length + if (prop != null && prop.values != null) { + boolean complete = true; + for (int i = 0; i < result.length; i++) + if (result [i] == null) { + if (prop.values [i] != null) { + result [i] = prop.values [i]; + continue; + } + complete = false; + } + if (complete) + return result; + } + return null; + } + }, skipFirst); + } + // ======================================== + public interface ComputeSpin { + public boolean getSpin (Prop prop); + } + public boolean parentSpinWalk (String propName, ComputeSpin computeSpin, boolean skipFirst) { + boolean spin = false; + for (Editable editable = skipFirst ? getParent () : this; + editable != null; + editable = editable.getParent ()) + try { + spin ^= computeSpin.getSpin (editable.ownProps.get (propName)); + } catch (Exception e) { + } + return spin; + } + public boolean parentAndModelSpinWalk (String propName, ComputeSpin computeSpin, boolean skipFirst) { + boolean spin = parentSpinWalk (propName, computeSpin, skipFirst); + try { + spin ^= getContainer ().getModel ().findEmbedded (getId ()).parentSpinWalk (propName, computeSpin, false); + } catch (Exception e) { + } + try { + spin ^= getModel ().parentSpinWalk (propName, computeSpin, false); + } catch (Exception e) { + } + return spin; + } + public boolean getPropHorizontalSpin (String propName) { + return getPropHorizontalSpin (propName, false); + } + public boolean getParentPropHorizontalSpin (String propName) { + return getPropHorizontalSpin (propName, true); + } + public boolean getPropHorizontalSpin (String propName, boolean skipFirst) { + return parentSpinWalk (propName, new ComputeSpin () { + public boolean getSpin (Prop prop) { + return prop.horizontalSpin; + } + }, skipFirst); + } + + // ======================================== + public boolean getPropHidden (String propName) { + return getPropModifiers (Permanent.Hidden, propName) != null; + } + public boolean getPropLock (String propName) { + return getPropModifiers (Permanent.Lock, propName) != null; + } + public boolean getPropLocalized (String propName) { + return getPropModifiers (Permanent.Localized, propName) != null; + } + public boolean getPropNoMouse (String propName) { + return getPropModifiers (Permanent.NoMouse, propName) != null; + } + public ScaledImage getIcon () { + return getIconImage (Prop.PropIcon); + } + public ScaledImage getLowIcon () { + return getIconImage (Prop.PropLowIcon); + } + public ScaledImage getBlueprint () { + return getIconImage (Prop.PropBlueprint); + } + public Double getBlueprintVisibility () { + try { + return getPropVal (Prop.PropBlueprintVisibility).values [0]; + } catch (Exception e) { + return null; + } + } + public DimensionDouble getBlueprintSize () { + return getSize (Prop.PropBlueprintSize); + } + public Point2D.Double getBlueprintPos () { + return getPos (Prop.PropBlueprintPos); + } + public ScaledImage getIconImage (String propName) { + return getIconImage (getPropVal (propName), getPropHorizontalSpin (propName)); + } + public ScaledImage getIconImage (Prop iconImageProp, boolean horizontalSpin) { + if (iconImageProp == null) + return null; + switch (iconImageProp.getTypeToken ()) { + case Icon: + return getAdecWatt ().getIconDB ().getImage (iconImageProp.sValue, horizontalSpin); + case Image: + return getAdecWatt ().getImageDB ().getImage (iconImageProp.sValue, horizontalSpin); + default: + throw new IllegalArgumentException ("Bad type ("+iconImageProp.getTypeToken ()+") for icon or image!"); + } + } + private Double dummy; + protected Double [] + seek12 = new Double[] {null, null}, + seek3 = new Double[] {dummy, dummy, null}; + public DimensionDouble getRealSize () { + return getSize (); + } + + // ======================================== + public DimensionDouble getSize () { + return getSize (Prop.PropSize); + } + public Double[] getTileSize () { + Double [] seek = seek12.clone (); + getPartialProp (Prop.PropTileSize, seek); + if (seek[0] == null && seek[1] == null) + return null; + return seek; + } + static public Dimension getTile (Double [] tileSize, DimensionDouble realSize) { + return tileSize == null ? ScaledImage.ONE_TILE : + new Dimension (tileSize[0] == null ? 1 : (int) Math.max (1, Math.round (realSize.width/tileSize[0])), + tileSize[1] == null ? 1 : (int) Math.max (1, Math.round (realSize.height/tileSize[1]))); + } + public DimensionDouble getSize (String propName) { + Double [] seek = seek12.clone (); + getPartialProp (propName, seek); + if (seek[0] == null || seek[1] == null) + return null; + return new DimensionDouble (seek [0], seek [1]); + } + public Point2D.Double getPos () { + return getPos (Prop.PropPos); + } + public Point2D.Double getPos (String propName) { + Double [] seek = seek12.clone (); + getPartialProp (propName, seek); + if (seek[0] == null || seek[1] == null) + return null; + return new Point2D.Double (seek [0], seek [1]); + } + public double getThetaDegree () { + try { + Double [] seek = seek3.clone (); + getPartialProp (Prop.PropRot, seek); + return seek [2]; + } catch (Exception e) { + return 0; + } + } + public double getLevel () { + try { + Double [] seek = seek3.clone (); + getPartialProp (Prop.PropPos, seek); + return seek [2]; + } catch (Exception e) { + return 0; + } + } + public double getLength () { + try { + return getPropVal (Prop.PropLength).values[0]; + } catch (Exception e) { + return 0; + } + } + public double getWidth () { + try { + return getPropVal (Prop.PropWidth).values[0]; + } catch (Exception e) { + return 0; + } + } + public double getAngle () { + try { + return getPropVal (Prop.PropAngle).values[0]; + } catch (Exception e) { + return 0; + } + } + public String getStyle () { + try { + return getPropVal (Prop.PropStyle).sValue; + } catch (Exception e) { + return null; + } + } + public String getBegin () { + try { + return getPropVal (Prop.PropBegin).sValue; + } catch (Exception e) { + return null; + } + } + public String getEnd () { + try { + return getPropVal (Prop.PropEnd).sValue; + } catch (Exception e) { + return null; + } + } + public boolean isLow () { + return getLevel () <= AdecWatt.lowLevel; + } + public Building getBuilding () { + try { + return (Building) getAdecWatt ().getPermanentDB ().getUnitById (getProp (Prop.PropBuilding).sValue); + } catch (Exception e) { + return null; + } + } + public Color getColor () { + try { + return LPColor.getColor (getPropVal (Prop.PropColor).sValue); + } catch (Exception e) { + return Color.black; + } + } + public String getConnectedTo () { + try { + return getPropVal (Prop.PropConnectedTo).sValue; + } catch (Exception e) { + return null; + } + } + public String getConnectedOn () { + try { + return getPropVal (Prop.PropConnectedOn).sValue; + } catch (Exception e) { + return null; + } + } + + // ======================================== + public abstract void updateView (); + + // ======================================== + public void validateContainer (Story.Commands commands, String commandName) { + // unit has no container + } + + // ======================================== + protected void storyChange (Story.Commands commands, boolean comp, final Hashtable ownProps, ArrayList changeProps) { + Story story = commands.getStory (); + validateContainer (commands, StoryLinkEmb); + for (Prop[] changeProp : changeProps) { + final Prop type = changeProp[0]; + Prop parentVal = changeProp[1]; + final Prop src = changeProp [2]; + final Prop dst = changeProp [3] == null ? null : changeProp [3].getApplyMixProp (src, parentVal); + if (dst != null && dst.sValue == Prop.PropMix) + continue; + boolean isParentValue = Prop.isSValue (parentVal); + boolean isDstValue = Prop.isSValue (dst); + boolean changeParentValue = + isParentValue != isDstValue || (isDstValue && !dst.sValue.equals (parentVal.sValue)); + if (src == dst && changeParentValue) + continue; + boolean dstSpin = dst != null && dst.horizontalSpin; + // add + if (src == null) { + if (isDstValue && changeParentValue) { + commands.add (story.new Command (StoryAddProp+" "+dst.name) { + public void exec () { ownProps.put (dst.name, dst); } + public void undo () { ownProps.remove (dst.name); } + }); + continue; + } + if (!dstSpin) + continue; + final Prop newSpin = new Prop (dst.name, dst.getTypeToken (), dst.horizontalSpin); + commands.add (story.new Command (StoryAddSpinProp+" "+newSpin.name) { + public void exec () { ownProps.put (newSpin.name, newSpin); } + public void undo () { ownProps.remove (newSpin.name); } + }); + continue; + } + boolean srcSpin = src != null && (src.horizontalSpin); + boolean changeSpin = (srcSpin != dstSpin) || + (srcSpin && dstSpin && src.horizontalSpin != dst.horizontalSpin); + // change + if (changeSpin) { + final boolean oldHorizontalSpin = src.horizontalSpin; + commands.add (story.new Command (StoryChangeSpin+" "+src.name) { + public void exec () { + src.horizontalSpin = dst.horizontalSpin; + } + public void undo () { + src.horizontalSpin = oldHorizontalSpin; + } + }); + } + if (isDstValue && changeParentValue) { + if (dst.sValue.equals (src.sValue)) + continue; + // XXX a tester si remove partiel de Prop.PropSize ou Prop.PropPos et rien chez parent + // XXX faire modif partiel de multilabel + // XXX peut impliquer un remove + commands.add (story.new Command (StoryChangeValue+" "+dst.name+"<"+src.sValue+","+dst.sValue+">") { + String newValue = dst.sValue; + String oldValue = src.sValue; + public void exec () { src.setValue (newValue); } + public void undo () { src.setValue (oldValue); } + }); + } + // XXX si unit && "name" + // => faire un backup du fichier... mais quand ? + // => refaire héritage => marquer les héritier direct a sauver (boolean changement parent) + // XXX si comp && si size = 0 ou pos hors du Workspace => remove + // XXX si unit ou dérivé dans des workspace && si size = 0 ou pos hors du Workspace => remove + + if (dstSpin || (isDstValue && changeParentValue)) + continue; + // remove + if (comp && (type.name.equals (Prop.PropSize) || type.name.equals (Prop.PropPos))) { + if (!isParentValue) + continue; + Double [] seek = seek12.clone (); + getParentPartialProp (type.name, seek); + if (seek[0] == null || seek[1] == null) + continue; + } + if (getParentProp (type.name) == null || + src.unknownSpin != null || + (src.enumChoice != null && (parentVal == null || !parentVal.getEnumString ().equals (src.getEnumString ()))) || + (src.multiLabel != null && (parentVal == null || !parentVal.getLabelString ().equals (src.getLabelString ()))) || + src.getModifiersString ().equals (getModifiersString (getPropModifiers (src.name))) ) { + final String oldValue = src.sValue; + if (oldValue == null || oldValue.isEmpty ()) + continue; + commands.add (story.new Command (StoryClearProp+" "+src.name) { + public void exec () { src.setValue (null); } + public void undo () { src.setValue (oldValue); } + }); + continue; + } + commands.add (story.new Command (StoryRemoveProp+" "+type.name) { + public void exec () { ownProps.remove (type.name); } + public void undo () { ownProps.put (type.name, src); } + }); + } + } + + // ======================================== + public void storyTransform (Story.Commands commands, final String newName, final Collection newModifiers, + final Unit permanent, final Hashtable ownProps, ArrayList transProps) { + Story story = commands.getStory (); + validateContainer (commands, StoryLinkEmb); + if (newName != null) { + final String oldName = getName (); + if (!newName.equals (oldName)) { + commands.add (story.new Command (StoryChangeName) { + // XXX incidance sur PermanentDB si root ou powerSocket ou powerPlug + public void exec () { Editable.this.name = newName; } + public void undo () { Editable.this.name = oldName; } + public void display () { getDirectUnit ().updateTree (); } + }); + } + } + if (newModifiers != null && !getModifiersString ().equals (getModifiersString (newModifiers))) { + final Collection oldModifiers = getModifiers (); + commands.add (story.new Command (StoryChangeModifiers) { + public void exec () { setModifiers (newModifiers); } + public void undo () { setModifiers (oldModifiers); } + }); + } + if (permanent != null) { + //System.err.println ("coucou change parent:"+getName ()+" => "+permanent.getName ()); + final Unit oldPermanent = getParentUnit (); + if (!(oldPermanent == permanent || + permanent == this || + getParent () == null)) + commands.add (story.new Command (StoryChangeParent) { + public void exec () { setParentUnit (permanent); } + public void undo () { setParentUnit (oldPermanent); } + public void display () { permanent.updateTree (); oldPermanent.updateTree (); getDirectUnit ().updateTree (); } + }); + } + if (transProps != null) { + ArrayList oldProps = new ArrayList (ownProps.values ()); + // change + for (Prop[] transProp : transProps) { + final Prop src = transProp [0]; + final Prop dst = transProp [1]; + if (src == null) + continue; + oldProps.remove (src); + if (src.rank == dst.rank) + continue; + if (src.rank == null || !src.rank.equals (dst.rank)) { + final Integer oldRank = src.rank; + commands.add (story.new Command (StoryOrderedProp+" "+src.name) { + public void exec () { src.rank = dst.rank; } + public void undo () { src.rank = oldRank; } + }); + } + if (!src.getModifiersString ().equals (dst.getModifiersString ())) { + final Collection oldModifiers = src.getModifiers (); + commands.add (story.new Command (StoryChangeModifiers+" "+src.name) { + public void exec () { src.setModifiers (dst.getModifiers ()); } + public void undo () { src.setModifiers (oldModifiers); } + }); + } + if (!src.name.equals (dst.name)) { + final String oldPropName = src.name; + final String newPropName = dst.name; + commands.add (story.new Command (StoryChangeName+" "+oldPropName+" "+newPropName) { + public void exec () { + if (ownProps.get (oldPropName) == src) + ownProps.remove (oldPropName); + src.name = newPropName; + ownProps.put (newPropName, src); + } + public void undo () { + if (ownProps.get (newPropName) == src) + ownProps.remove (newPropName); + src.name = oldPropName; + ownProps.put (oldPropName, src); + } + }); + } + if (src.getTypeToken () != dst.getTypeToken ()) { + final PropTypeEnum oldType = src.getTypeToken (); + final PropTypeEnum newType = dst.getTypeToken (); + commands.add (story.new Command (StoryChangeType+" "+src.name) { + public void exec () { src.setType (newType); } + public void undo () { src.setType (oldType); } + }); + } + if (!src.getEnumString ().equals (dst.getEnumString ())) { + final Collection oldEnum = src.enumChoice; + final Collection newEnum = dst.enumChoice; + commands.add (story.new Command (StoryChangeEnum+" "+src.name) { + public void exec () { src.enumChoice = newEnum; } + public void undo () { src.enumChoice = oldEnum; } + }); + } + if (!src.getLabelString ().equals (dst.getLabelString ())) { + final List oldLabels = src.multiLabel; + final List newLabels = dst.multiLabel; + commands.add (story.new Command (StoryChangeLabels+" "+src.name) { + public void exec () { src.multiLabel = newLabels; } + public void undo () { src.multiLabel = oldLabels; } + }); + } + } + // add + for (Prop[] transProp : transProps) { + Prop src = transProp [0]; + final Prop dst = transProp [1]; + if (src != null) + continue; + final Prop oldSrc = ownProps.get (dst.name); + if (oldSrc != null) { + oldProps.remove (oldSrc); + commands.add (story.new Command (StoryRemoveProp+" "+dst.name) { + public void exec () { ownProps.remove (dst.name); } + public void undo () { ownProps.put (dst.name, oldSrc); } + }); + } + commands.add (story.new Command (StoryAddProp+" "+dst.name) { + public void exec () { ownProps.put (dst.name, dst); } + public void undo () { ownProps.remove (dst.name); } + }); + } + // clean + Unit parent = getParentUnit (); + for (final Prop prop : oldProps) { + // if (prop.enumChoice == null && (parent != null && parent.getProp (prop.name) != null)) + // // XXX enum # parent aussi ? + // continue; + // XXX Et si plus de prop (masquée) ? + if (prop.sValue != null || prop.horizontalSpin) { + final Collection enumChoice = prop.enumChoice; + if (enumChoice != null) + commands.add (story.new Command (StoryRemoveEnum+" "+prop.name) { + public void exec () { prop.enumChoice = null; } + public void undo () { prop.enumChoice = enumChoice; } + }); + final List multiLabel = prop.multiLabel; + if (multiLabel != null) + commands.add (story.new Command (StoryRemoveLabels+" "+prop.name) { + public void exec () { prop.multiLabel = null; } + public void undo () { prop.multiLabel = multiLabel; } + }); + continue; + } + commands.add (story.new Command (StoryRemoveProp+" "+prop.name) { + String oldPropName = prop.name; + public void exec () { + if (ownProps.get (oldPropName) == prop) + ownProps.remove (prop.name); + } + public void undo () { ownProps.put (oldPropName, prop); } + }); + } + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/Embedded.java b/src/java/adecWatt/model/Embedded.java new file mode 100644 index 0000000..06db360 --- /dev/null +++ b/src/java/adecWatt/model/Embedded.java @@ -0,0 +1,210 @@ +package adecWatt.model; + +import java.awt.Color; +import java.util.HashSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import adecWatt.model.xml.XmlPermanent; +import adecWatt.model.unit.NonWorkspace; + +public abstract class Embedded

, T extends Enum, A extends Enum, C extends Editable, E extends Embedded> + extends Editable { + + static public final String globalPlace = "ean"; // ean = Everywhere and Nowhere + + // ======================================== + protected C container, containerRef; + protected String placeId, id; + protected NonWorkspace model; + + // ======================================== + public abstract A getPlaceIdToken (); + public abstract A getModelToken (); + public abstract Embedded getLink (Editable container); + + public AdecWatt getAdecWatt () { return container.getAdecWatt (); } + public String getId () { return id; } + + // public Unit getPermanent () { return model; } + public Unit getDirectUnit () { return model; } + public Unit getParentUnit () { return model; } + public NonWorkspace getModel () { return model; } + public C getContainer () { return container; } + + public void setModel (NonWorkspace model) { this.model = model; } + + @SuppressWarnings ("unchecked") + public Embedded getParent () { + for (Editable containerParent = container.getParent (); + containerParent != null; + containerParent = containerParent.getParent ()) { + Embedded parent = (Embedded) containerParent.getLocalEmbedded (id); + if (parent != null) + return parent; + } + return null; + } + + public void setParentUnit (Unit parent) { model = (NonWorkspace) parent; } + + // ======================================== + protected Embedded (C container, P xmlPermanent) { + super (xmlPermanent); + this.container = container; + placeId = xmlPermanent.getFacet (getPlaceIdToken ()); + if (placeId == null) + placeId = container.getId (); + if (name != null) + updateId (); + String modelId = xmlPermanent.getFacet (getModelToken ()); + if (modelId == null) + throw new IllegalArgumentException ("Unknown XML embedded has no model ("+xmlPermanent+")."); + model = (NonWorkspace) getAdecWatt ().getPermanentDB ().getUnitById (modelId); + } + protected Embedded (String name, String placeId, C container, NonWorkspace model) { + this.name = name == null ? container.getUniqName () : name; + this.placeId = placeId == null ? container.getId () : placeId; + this.container = container; + this.model = model; + updateId (); + } + protected void updateId () { + id = placeId+":"+name; + } + @SuppressWarnings ("unchecked") + public void fixName (boolean isLocal) { + if (name == null) { + name = container.getUniqName (); + placeId = isLocal ? container.getId () : globalPlace; + } + updateId (); + ((Editable>) container).addEmbedded (this); + } + @SuppressWarnings ("unchecked") + protected void importFrom (Embedded from) { + for (Embedded current = from; current != null; current = current.getParent ()) + super.importFrom (current); + Editable model = from.getModel (); + if (model == null) + return; + super.importFrom ((Editable) model); + } + @SuppressWarnings ("rawtypes") + public abstract Embedded clone (C container); + + @SuppressWarnings ("rawtypes") + protected Embedded clone () { + throw new IllegalArgumentException ("Clone an Embedded forbidden"); + } + + // ======================================== + public Element getXml (Node parent, Document document) { + Element child = super.getXml (parent, document); + if (!container.getId ().equals (placeId)) + XmlPermanent.putFacet (child, getPlaceIdToken (), placeId); + // XXX model == null si pas trouvé au chargement exemple : comp de réserve + XmlPermanent.putFacet (child, getModelToken (), model.getId ()); + return child; + } + + public void getLocalLink (HashSet> visited, + HashSet> unitLinks, TreeSet iconsLinks, TreeSet imagesLinks) { + if (visited.contains (this)) + return; + super.getLocalLink (visited, unitLinks, iconsLinks, imagesLinks); + model.getLocalLink (visited, unitLinks, iconsLinks, imagesLinks); + } + + public boolean renameUnits (TreeMap translateMap) { + boolean result = model != null && translateMap.containsValue (model.getId ()); + if (placeId != null && translateMap.containsKey (placeId)) { + placeId = translateMap.get (placeId); + if (name != null) + updateId (); + result = true; + } + return super.renameUnits (translateMap) || result; + } + + // ======================================== + public Prop getLocalProp (String name, Prop.PropTypeEnum type) { + // pas de type en paramètre mais rechercher dans model + for (Prop prop : ownProps.values ()) + if (name.equals (prop.name)) { + // test type + return prop; + } + // Prop result = model.getProp (name); + // result = (result != null) ? result.clone () : new Prop (name, type); + Prop result = new Prop (name, type); + ownProps.put (name, result); + return result; + } + + // ======================================== + // XXX getPropVal => super && !!! container.model.getEmbedded.getPropVal + // XXX getPartialProp => super && !!! container.model.getEmbedded.getPartialProp + // XXX getProp => super && !!! container.model.getEmbedded.getProp + + static public String labelPattern = "\\{\\{([^}]*)\\}\\}"; + public String getLabel () { + try { + Pattern p = Pattern.compile (labelPattern); + String mString = getPropVal (Prop.PropLabelProp).sValue; + Matcher m = p.matcher (mString); + StringBuffer sb = new StringBuffer (); + while (m.find ()) { + String key = mString.substring (m.start ()+2, m.end ()-2); + String val = ""; //"{{"+key+"=?}}"; + try { + val = getPropVal (key).sValue; + } catch (Exception e) { + } + m.appendReplacement (sb, val); + } + m.appendTail (sb); + return sb.toString (); + } catch (Exception e) { + return null; + } + } + public Color getLabelColor () { + try { + return LPColor.getColor (getPropVal (Prop.PropLabelColor).sValue); + } catch (Exception e) { + return Color.black; + } + } + public double getLabelSize () { + try { + return getPropVal (Prop.PropLabelSize).values[0]; + } catch (Exception e) { + return 0; + } + } + public String getCircuit () { + try { + String name = getPropVal (Prop.PropCircuit).sValue; + if (!name.isEmpty ()) + return name; + } catch (Exception e) { + } + return null; + } + public double getWatt () { + try { + return getPropVal (Prop.PropWatt).values[0]; + } catch (Exception e) { + } + return 0; + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/ImageDB.java b/src/java/adecWatt/model/ImageDB.java new file mode 100644 index 0000000..55da55a --- /dev/null +++ b/src/java/adecWatt/model/ImageDB.java @@ -0,0 +1,431 @@ +package adecWatt.model; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Collection; +import java.util.Comparator; +import java.util.Hashtable; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +import misc.ScaledImage; +import misc.Util; +import static misc.Config.FS; + +import static adecWatt.model.PermanentDB.backExtention; +import static adecWatt.model.PermanentDB.dataDir; +import static adecWatt.model.PermanentDB.localRemoteDir; +import static adecWatt.model.PermanentDB.localToken; +import static adecWatt.model.PermanentDB.serverToken; +import static adecWatt.model.PermanentDB.cacheToken; + +public class ImageDB { + static { + ImageIO.setUseCache (false); + } + + // ======================================== + static public final String iconDirName = "icon", imageDirName = "image"; + static public class FileFilterImageName implements FileFilter { + private String baseImageName; + public FileFilterImageName (String imageName) { + baseImageName = Util.getBase (imageName); + } + public boolean accept (File file) { + return file.isFile () && !file.isHidden () && Util.getBase (file).equals (baseImageName) && ! Util.getExtention (file).toLowerCase ().equals (backExtention); + } + }; + + // ======================================== + private AdecWatt adecWatt; + private String dir; + private TagDB tagDB; + public PreviewCache previewCache; + + // ======================================== + private File getDir (String placeToken) { + return new File (new File (dataDir, placeToken), dir); + } + public Collection getTags (String imageName) { + return tagDB.getTags (imageName); + } + public void putTags (String imageName, Collection imageTags) { + tagDB.putTags (imageName, imageTags); + } + + // ======================================== + public ImageDB (AdecWatt adecWatt, String dir) { + this.adecWatt = adecWatt; + this.dir = dir; + tagDB = new TagDB (dir); + previewCache = new PreviewCache (new File (new File (dataDir, cacheToken), dir)); + } + + // ======================================== + Hashtable> coloredScaledImages = new Hashtable> (); + final int toReplace = Color.BLUE.getRGB (); + + public ScaledImage getColoredScaledImages (ScaledImage scaledImage, Color color) { + Hashtable colorList = coloredScaledImages.get (scaledImage); + if (colorList == null) { + colorList = new Hashtable (); + coloredScaledImages.put (scaledImage, colorList); + } + ScaledImage coloredScaledImage = colorList.get (color); + if (coloredScaledImage == null) { + int newColor = color.getRGB (); + BufferedImage reference = scaledImage.reference; + int width = reference.getWidth (); + int height = reference.getHeight (); + BufferedImage colored = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { + int c = reference.getRGB (x, y); + if (c == toReplace) + c = newColor; + colored.setRGB (x, y, c); + } + coloredScaledImage = new ScaledImage (colored); + colorList.put (color, coloredScaledImage); + } + return coloredScaledImage; + } + + // ======================================== + private Hashtable bufferedImages = new Hashtable (); + private Hashtable scaledImages = new Hashtable (); + + public ScaledImage getImage (String imageName, boolean horizontalSpin) { + try { + ScaledImage result = getScaled (findBufferedImage (imageName)); + return horizontalSpin ? result.getNewSpin (horizontalSpin, false) : result; + } catch (Exception e) { + return null; + } + } + public ScaledImage getScaled (BufferedImage bufferedImage) { + if (bufferedImage == null) + return null; + ScaledImage scaledImage = scaledImages.get (bufferedImage); + if (scaledImage != null) + return scaledImage; + scaledImage = new ScaledImage (bufferedImage); + scaledImages.put (bufferedImage, scaledImage); + return scaledImage; + } + + static public Comparator nameLocalComparator = + new Comparator () { + public int compare (NameLocal o1, NameLocal o2) { + if (o1 == o2) + return 0; + int diff = o1.fileName.compareToIgnoreCase (o2.fileName); + if (diff != 0) + return diff > 0 ? 1 : -1; + if (o1.isLocal == o2.isLocal) + return 0; + return o1.isLocal ? 1 : -1; + } + }; + + public class NameLocal { + public String fileName; + public boolean isLocal; + public ImageIcon icon; + public NameLocal (String fileName, boolean isLocal) { + this.fileName = fileName; + this.isLocal = isLocal; + } + } + public boolean isRemote (String imageName) { + FileFilterImageName fileFilterImageName = new FileFilterImageName (imageName); + boolean result = true; + for (String srcDir : localRemoteDir) + try { + result = !result; + if (new File (new File (dataDir, srcDir), dir).listFiles (fileFilterImageName).length > 0) + return result; + } catch (Exception e) { + } + return false; + } + + public File getFile (String imageName, boolean isLocal) { + if (!localRemoteDir.get (0).equals (localToken)) + isLocal = ! isLocal; + String srcDir = localRemoteDir.get (isLocal ? 0 : 1); + try { + return getDir (srcDir).listFiles (new FileFilterImageName (imageName))[0]; + } catch (Exception e) { + } + return null; + } + + public void renameLocalImage (String imageName, String newImageName) { + if (imageName == null || newImageName == null || imageName.equals (newImageName)) + return; + BufferedImage image = bufferedImages.get (imageName); + if (image != null) { + bufferedImages.remove (imageName); + bufferedImages.put (newImageName, image); + } + File oldFile = getFile (imageName, true); + if (oldFile == null) + return; + File newFile = new File (oldFile.getParent (), newImageName+"."+Util.getExtention (oldFile).toLowerCase ()); + try { + Files.move (oldFile.toPath (), newFile.toPath (), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + } + if (oldFile.exists ()) { + // XXX si pas de move ? + System.err.println ("coucou l'image n'a pas été renommée:"+oldFile); + } + } + public void removeImage (String imageName) { + try { + File oldFile = getFile (imageName, true); + Util.backup (oldFile, Util.getExtention (oldFile), backExtention); + clearBufferedImage (imageName); + previewCache.clean (imageName); + } catch (Exception e) { + } + } + + private String getNewImageName (File file) { + return adecWatt.getUser ().getDataId ()+"."+Util.getExtention (file).toLowerCase (); + } + private String getImageName (String imageName, File file) { + return Util.getBase (imageName)+"."+Util.getExtention (file); + } + public String addImage (File file) { + String newImageName = getNewImageName (file); + File dstDir = new File (new File (dataDir, localToken), dir); + try { + dstDir.mkdirs (); + Util.copy (new FileInputStream (file), new FileOutputStream (new File (dstDir, newImageName)), null, null); + } catch (Exception e) { + e.printStackTrace (); + } + return newImageName; + } + public void renameVisitor (TreeSet imageNames) { + if (imageNames.size () == 0) + return; + PermanentDB permanentDB = adecWatt.getPermanentDB (); + TreeMap translateMap = new TreeMap (); + String pattern = String.format ("%03d-", User.visitorId); + User user = adecWatt.getUser (); + for (String imageName : imageNames) { + if (!imageName.startsWith (pattern)) + continue; + String newImageName = user.getDataId (); + String ext = Util.getExtention (imageName); + if (ext != null) { + System.err.println ("coucou renameVisitor has ext:"+imageName); + imageNames.remove (imageName); + imageName = Util.getBase (imageName); + } + renameLocalImage (imageName, newImageName); + translateMap.put (imageName, newImageName); + } + permanentDB.renameImages (translateMap); + tagDB.renameImages (translateMap); + if (translateMap.size () < 1) + return; + imageNames.removeAll (translateMap.keySet ()); + imageNames.addAll (translateMap.values ()); + } + public void promoteTag (TreeSet imageNames) { + tagDB.promote (imageNames); + } + public void promote (TreeSet imageNames) { + if (imageNames.size () == 0) + return; + // liste des id à écrire + // XXX tag par id + for (String imageName : imageNames) { + // XXX mis à jours des "tags" local => sever + File file = getFile (imageName, true); + // XXX autre méthode ? + if (file == null) { + // XXX si pas sauvé => trouver extension et utiliser scaledImage (pas copy) + continue; + } + File newFile = new File (new File (new File (dataDir, serverToken), dir), file.getName ()); + try { + Files.move (file.toPath (), newFile.toPath (), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + } + if (file.exists ()) { + // XXX si pas de move ? + System.err.println ("coucou l'image "+imageName+" n'a pas été déplacée"); + } + } + } + public String updateImage (NameLocal nameLocal, File file) { + String newImageName = getImageName (nameLocal.fileName, file); + File dstDir = getDir (localToken); + if (nameLocal.isLocal) + removeImage (nameLocal.fileName); + try { + dstDir.mkdirs (); + // XXX utiliser un tmp ? + Util.copy (new FileInputStream (file), new FileOutputStream (new File (dstDir, newImageName)), null, null); + clearBufferedImage (newImageName); + } catch (Exception e) { + e.printStackTrace (); + } + return newImageName; + } + + public boolean importFile (String dirName, String fileName, ByteArrayInputStream dataIn) { + if (!dir.equals (dirName)) + return false; + try { + bufferedImages.put (fileName, ImageIO.read (dataIn)); + } catch (Exception e) { + } + return true; + } + + public void addImageZip (ZipOutputStream out, String iconName) + throws IOException { + if (iconName == null || iconName.isEmpty ()) + return; + ZipEntry ze = new ZipEntry (dir+"/"+iconName); + out.putNextEntry (ze); + File srcDir = new File (new File (dataDir, localToken), dir); + File srcFile = new File (srcDir, iconName); + int length = (int) srcFile.length (); + byte[] tmp = new byte[length]; + FileInputStream fileInputStream = new FileInputStream (srcFile); + try { + fileInputStream.read (tmp); + } finally { + fileInputStream.close (); + } + out.write (tmp); + out.closeEntry(); + out.flush (); + } + public Vector listImage () { + Vector result = new Vector (); + Vector filesNames = new Vector (); + Boolean isLocal = localRemoteDir.get (0).equals (localToken); + isLocal = ! isLocal; + for (String srcDir : localRemoteDir) + try { + isLocal = ! isLocal; + File[] files = new File (dataDir, srcDir+FS+dir).listFiles (PreviewCache.fileImageFilter); + if (files == null) + continue; + int maxSize = result.size ()+filesNames.size (); + result.ensureCapacity (maxSize); + filesNames.ensureCapacity (maxSize); + for (File file : files) { + String fileName = file.getName (); + if (!filesNames.contains (fileName)) { + filesNames.add (fileName); + result.add (new NameLocal (fileName, isLocal)); + } + } + } catch (Exception e) { + e.printStackTrace (); + } + result.sort (nameLocalComparator); + return result; + } + + public TreeMap newNamePlan () { + TreeMap result = new TreeMap (); + for (String srcDir : localRemoteDir) + try { + File[] files = new File (dataDir, srcDir+FS+dir).listFiles (PreviewCache.fileImageFilter); + if (files == null) + continue; + for (File file : files) { + String fileName = file.getName (); + if (User.splitId (fileName) != null) + continue; + String newName = result.get (fileName); + if (newName == null) + result.put (fileName, newName = getNewImageName (file)); + Files.move (file.toPath (), new File (file.getParent (), newName).toPath (), StandardCopyOption.REPLACE_EXISTING); + } + } catch (Exception e) { + e.printStackTrace (); + } + return result; + } + + public void clearBufferedImage (String imageName) { + if (imageName == null) + return; + imageName = Util.getBase (imageName); + BufferedImage bufferedImage = bufferedImages.get (imageName); + if (bufferedImage == null) + return; + ScaledImage scaledImage = scaledImages.get (bufferedImage); + bufferedImages.remove (imageName); + if (scaledImage == null) + return; + scaledImages.remove (bufferedImage); + coloredScaledImages.remove (scaledImage); + } + + public BufferedImage findBufferedImage (String imageName) { + if (imageName == null) + return null; + imageName = Util.getBase (imageName); + BufferedImage bufferedImage = bufferedImages.get (imageName); + if (bufferedImage != null) + return bufferedImage; + FileFilterImageName fileFilterImageName = new FileFilterImageName (imageName); + for (String srcDir : localRemoteDir) + try { + for (File file : new File (new File (dataDir, srcDir), dir).listFiles (fileFilterImageName)) { + bufferedImage = ImageIO.read (file); + bufferedImages.put (imageName, bufferedImage); + return bufferedImage; + } + } catch (Exception e) { + } + System.err.println ("coucou not found:"+dir+FS+imageName); + return null; + } + + // ======================================== + public void updateDataId () { + User user = adecWatt.getUser (); + for (String srcDir : localRemoteDir) + try { + for (File file : new File (dataDir, srcDir+FS+dir).listFiles (PreviewCache.fileImageFilter)) + user.updateDataId (file.getName ()); + } catch (Exception e) { + } + } + + // ======================================== + public void reload () { + tagDB.reload (); + bufferedImages.clear (); + scaledImages.clear (); + updateDataId (); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/InseeDB.java b/src/java/adecWatt/model/InseeDB.java new file mode 100644 index 0000000..ca6af46 --- /dev/null +++ b/src/java/adecWatt/model/InseeDB.java @@ -0,0 +1,87 @@ +package adecWatt.model; + +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import misc.Log; +import misc.Util; + +public class InseeDB { + + // http://www.geonames.org/export/codes.html + // http://download.geonames.org/export/dump/ (PPL) + + // ======================================== + static public class Insee { + public String code, name; + public double latitude, longitude; + + public Insee (String code, String name, double latitude, double longitude) { + this.code = code; + this.name = name; + this.latitude = latitude; + this.longitude = longitude; + } + } + + // ======================================== + private ArrayList cities = new ArrayList (); + public InseeDB (Node node) { + parse (node); + } + + public ArrayList getCities (String pattern) { + pattern = Util.removeAccent (pattern.toLowerCase ().replaceAll ("-", " ")); + ArrayList result = new ArrayList (); + for (Insee insee : cities) + if (Util.removeAccent (insee.name.toLowerCase ().replaceAll ("-", " ")).indexOf (pattern) >= 0 || + insee.code.indexOf (pattern) >= 0) + result.add (insee); + return result; + } + + // ======================================== + static public InseeDB readDocument (URL url) { + try { + return readDocument (url.openStream ()); + } catch (Exception e) { + } + return null; + } + static public InseeDB readDocument (InputStream stream) { + try { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder (); + Document document = documentBuilder.parse (stream); + document.normalizeDocument (); + return new InseeDB (document.getFirstChild ()); + } catch (Exception e) { + Log.keepLastException ("InseeDB::readDocument", e); + throw new IllegalArgumentException ("Not XML file input."); + } + } + + private void parse (Node node) { + //XX insee =? node.getNodeName () + NodeList childrens = node.getChildNodes (); + for (int i = 0; i < childrens.getLength (); i++) { + try { + Node child = childrens.item (i); + NamedNodeMap allFacets = child.getAttributes (); + cities.add (new Insee (allFacets.getNamedItem ("code").getNodeValue (), allFacets.getNamedItem ("name").getNodeValue (), + Double.parseDouble (allFacets.getNamedItem ("lat").getNodeValue ()), + Double.parseDouble (allFacets.getNamedItem ("long").getNodeValue ()))); + } catch (Exception e) { + } + } + } + + // ======================================== +} + diff --git a/src/java/adecWatt/model/Item.java b/src/java/adecWatt/model/Item.java new file mode 100644 index 0000000..be52d2f --- /dev/null +++ b/src/java/adecWatt/model/Item.java @@ -0,0 +1,337 @@ +package adecWatt.model; + +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Dimension2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.DimensionDouble; +import misc.Story; + +import adecWatt.model.unit.NonWorkspace; +import adecWatt.model.unit.Workspace; +import adecWatt.model.xml.XmlPermanent; + +public abstract class Item

, T extends Enum, A extends Enum> + extends Embedded { + + // ======================================== + protected Workspace placeUnit; + + // ======================================== + public Workspace getStoryUnit () { return container; } + + // ======================================== + public Item (Workspace workspace, P xml) { + super (workspace, xml); + collectEmbedded (); + } + public Item (String name, String placeName, Workspace workspace, NonWorkspace model) { + super (name, placeName, workspace, model); + } + public Item (Workspace workspace, NonWorkspace model) { + super (null, null, workspace, model); + } + abstract public Item clone (Workspace workspace); + protected void updateId () { + super.updateId (); + try { + boolean localItem = container.getId ().equals (placeId); + if (!localItem) + placeUnit = (Workspace) getAdecWatt ().getPermanentDB ().getUnitById (placeId); + } catch (Exception e) { + } + } + + // ======================================== + public ArrayList findAccs (Point2D.Double realPos, double close) { + ArrayList result = new ArrayList (); + double theta = Math.toRadians (-getThetaDegree ()); + double [] coord = new double [] {realPos.x, realPos.y}; + for (String accId : getEmbeddedIds ()) + try { + coord[0] = realPos.x; + coord[1] = realPos.y; + Point2D.Double accPos = accCenter.get (accId); + DimensionDouble accSize = this.accSize.get (accId); + AffineTransform at = new AffineTransform (); + at.rotate (theta); + at.translate (-accPos.x, -accPos.y); + at.transform (coord, 0, coord, 0, 1); + double halfWidth = accSize.width/2+close, halfHeight = accSize.height/2+close; + if (coord[0] >= -halfWidth && coord[0] <= halfWidth && + coord[1] >= -halfHeight && coord[1] <= halfHeight) + result.add (findEmbedded (accId)); + } catch (Exception e) { + } + return result; + } + + public R parentAndModelWalk (String propName, ComputeProp computeProp, boolean skipFirst) { + R result = parentWalk (propName, computeProp, skipFirst); + if (result != null) + return result; + try { + boolean localItem = placeId.equals (getContainer ().getId ()); + result = placeUnit.findEmbedded (getId ()).parentWalk (propName, computeProp, localItem); + if (result != null) + return result; + } catch (Exception e) { + } + try { + result = getModel ().parentWalk (propName, computeProp, false); + if (result != null) + return result; + } catch (Exception e) { + } + return null; + } + + public Element getXml (Node parent, Document document) { + return super.getXml (parent, document); + } + + // ======================================== + public boolean match (String text) { + return + super.match (text) || + model.parentMatch (text); + // if (container.search (text).size () > 0) + // return true; + // if (embedded != null) + // for (Acc acc: embedded.values ()) + // if (acc.search (text)) + // return true; + // XXX ou accéssoire + } + + // ======================================== + public void validateContainer (Story.Commands commands, String commandName) { + if (container.getLocalEmbedded (getId ()) == this) + return; + commands.add (container.story.new Command (commandName) { + public void exec () { container.addEmbedded (Item.this); } + public void undo () { container.removeEmbedded (Item.this); } + public void displayExec () { updateView (Unit.BroadcastNewItem); } + public void displayUndo () { updateView (Unit.BroadcastRemoveItem); } + }); + } + + public void storyChange (Story.Commands commands, ArrayList changeProps) { + storyChange (commands, true, ownProps, changeProps); + } + public void storyTransform (Story.Commands commands, Collection modifiers, Unit permanent, String newName, ArrayList transProps) { + storyTransform (commands, null, modifiers, permanent, ownProps, transProps); + } + public void updateView () { + updateView (Unit.BroadcastUpdateItem); + } + @SuppressWarnings ("unchecked") + public void updateView (String msg) { + for (Enumeration e = container.unitNode.breadthFirstEnumeration (); e.hasMoreElements (); ) { + Unit> unit = ((UnitNode>) e.nextElement ()).getUnit (); + unit.stateNotifier.broadcastDisplay (msg, this); + } + } + + // ======================================== + public boolean inside (Rectangle2D.Double selection) { + try { + Point2D.Double center = getPos (); + DimensionDouble size = getRotSize (getSize (), getThetaDegree ()); + double halfWidth = size.width/2; + double halfHeight = size.height/2; + return + selection.x <= center.x-halfWidth && selection.x+selection.width >= center.x+halfWidth && + selection.y <= center.y-halfHeight && selection.y+selection.height >= center.y+halfHeight; + } catch (Exception e) { + return false; + } + } + + public boolean isPosOutside (DimensionDouble inside) { + Point2D.Double pos = getPos (); + DimensionDouble size = getRotSize (getSize (), getThetaDegree ()); + double halfWidth = size.width/2; + double halfHeight = size.height/2; + return + pos.x < halfWidth || pos.y < halfHeight || + pos.x > inside.width-halfWidth || pos.y > inside.height-halfHeight; + } + + static public DimensionDouble getRotSize (DimensionDouble size, double thetaDegree) { + if (thetaDegree == 0) + return size; + double [] bounds = getShapeBounds (size, thetaDegree); + return new DimensionDouble (Math.max (Math.abs (bounds[4]-bounds[0]), + Math.abs (bounds[6]-bounds[2])), + Math.max (Math.abs (bounds[5]-bounds[1]), + Math.abs (bounds[7]-bounds[3]))); + } + public double getCloseBound (Point2D.Double pos, double close, Point2D.Double result) { + return getCloseBound (getBounds (), pos, close, result); + } + public double[] getBounds () { + return getBounds (getPos (), getSize (), getThetaDegree ()); + } + + static public Point2D.Double getPosInside (DimensionDouble inside, Point2D.Double pos, double thetaDegree, DimensionDouble refSize) { + DimensionDouble size = getRotSize (refSize, thetaDegree); + double halfWidth = size.width/2; + double halfHeight = size.height/2; + return new + Point2D.Double (Math.min (Math.max (pos.x, halfWidth), inside.width-halfWidth), + Math.min (Math.max (pos.y, halfHeight), inside.height-halfHeight)); + } + static public double getCloseBound (double[] bounds, Point2D.Double pos, double close, Point2D.Double result) { + for (int x = 0, y = 1; x < 18; x+=2, y+=2) { + double d = pos.distance (bounds[x], bounds[y]); + if (d < close) { + close = d; + result.x = bounds[x]; + result.y = bounds[y]; + } + } + return close; + } + static public double[] getBounds (Point2D.Double pos, Dimension2D size, double thetaDegree) { + double halfWidth = size.getWidth ()/2, halfHeight = size.getHeight ()/2; + AffineTransform at = AffineTransform.getTranslateInstance (pos.x, pos.y); + at.rotate (Math.toRadians (thetaDegree)); + double [] bounds = new double [] { + -halfWidth, -halfHeight, + -halfWidth, halfHeight, + halfWidth, halfHeight, + halfWidth, -halfHeight, + -halfWidth, 0, + 0, halfHeight, + halfWidth, 0, + 0, -halfHeight, + 0, 0 + }; + //System.err.println ("coucou A:"+java.util.Arrays.toString (bounds)); + at.transform (bounds, 0, bounds, 0, 9); + //System.err.println ("coucou B:"+java.util.Arrays.toString (bounds)); + return bounds; + } + static public double[] getShapeBounds (Dimension2D size, double thetaDegree) { + double halfWidth = size.getWidth ()/2, halfHeight = size.getHeight ()/2; + AffineTransform at = AffineTransform.getRotateInstance (Math.toRadians (thetaDegree)); + double [] bounds = new double [] {-halfWidth, -halfHeight, -halfWidth, halfHeight, halfWidth, halfHeight, halfWidth, -halfHeight}; + at.transform (bounds, 0, bounds, 0, 4); + return bounds; + } + public boolean containsClose (double [] coord, double close) { + try { + Point2D.Double center = getPos (); + DimensionDouble size = getSize (); + AffineTransform at = new AffineTransform (); + at.rotate (Math.toRadians (-getThetaDegree ())); + at.translate (-center.x, -center.y); + at.transform (coord, 0, coord, 0, 1); + double halfWidth = size.width/2+close, halfHeight = size.height/2+close; + return + coord[0] >= -halfWidth && coord[0] <= halfWidth && + coord[1] >= -halfHeight && coord[1] <= halfHeight; + } catch (Exception e) { + return false; + } + } + // ======================================== + abstract public void changeThetaDegree (double thetaDegree); + abstract public void changeSize (DimensionDouble size); + + public void changeRotSize (Point2D.Double pos, double thetaDegree, DimensionDouble size) { + if (isSticky ()) + return; + // XXX ? si parent valeur identique ? + getLocalProp (Prop.PropPos, Prop.PropTypeEnum.Cube).setPosition (pos); + changeThetaDegree (thetaDegree); + changeSize (size); + } + + public void changePos (Point2D.Double pos) { + if (isSticky ()) + return; + // XXX ? si parent valeur identique ? + getLocalProp (Prop.PropPos, Prop.PropTypeEnum.Cube).setPosition (pos); + } + + // ======================================== + static public Comparator xPosComparator = new AxeItemComparator (0, 1, 2); + static public Comparator yPosComparator = new AxeItemComparator (1, 0, 2); + static public Comparator zPosComparator = new AxeItemComparator (2, 0, 1); + + static class AxeItemComparator implements Comparator { + int a, b, c; + public AxeItemComparator (int a, int b, int c) { + this.a = a; + this.b = b; + this.c = c; + } + public int compare (Item o1, Item o2) { + if (o1 == o2) + return 0; + Double [] seekProp1 = new Double[] {null, null, null}; + Double [] seekProp2 = new Double[] {null, null, null}; + o1.getPartialProp (Prop.PropPos, seekProp1); + o2.getPartialProp (Prop.PropPos, seekProp2); + if (seekProp1[a] != seekProp2[a]) { + if (seekProp1[a] == null) + return 1; + if (seekProp2[a] == null) + return -1; + double diff = seekProp1[a] - seekProp2[a]; + if (diff != 0) + return diff > 0 ? 1 : -1; + } + if (seekProp1[b] != seekProp2[b]) { + if (seekProp1[b] == null) + return 1; + if (seekProp2[b] == null) + return -1; + double diff = seekProp1[b] - seekProp2[b]; + if (diff != 0) + return diff > 0 ? 1 : -1; + } + if (seekProp1[c] != seekProp2[c]) { + if (seekProp1[c] == null) + return 1; + if (seekProp2[c] == null) + return -1; + double diff = seekProp1[c] - seekProp2[c]; + if (diff != 0) + return diff > 0 ? 1 : -1; + } + return 0; + } + }; + + // ======================================== + public String toString () { + return getName (); + } + + // ======================================== + public Hashtable accCenter = new Hashtable (); + public Hashtable accSize = new Hashtable (); + public Point2D.Double getAccCenter (String accId) { + return accCenter.get (accId); + } + public DimensionDouble getAccSize (String accId) { + return accSize.get (accId); + } + abstract public void print (Graphics2D printGraphics, Workspace workspace, String plugId); + abstract public void print (Graphics2D printGraphics, Workspace workspace, Point2D pos, DimensionDouble size, double thetaDegree); + + // ======================================== +} diff --git a/src/java/adecWatt/model/LPColor.java b/src/java/adecWatt/model/LPColor.java new file mode 100644 index 0000000..ab57137 --- /dev/null +++ b/src/java/adecWatt/model/LPColor.java @@ -0,0 +1,406 @@ +package adecWatt.model; + +import java.awt.Color; +import java.lang.reflect.Field; +import java.util.Hashtable; + +public class LPColor { + + static public Hashtable leeFilterList = new Hashtable (); + + static public class LeeFilter { + String ref; + int value; + String comment; + + public LeeFilter (String ref, int value, String comment) { + this.ref = ref; + this.value = value; + this.comment = comment; + leeFilterList.put ("LF"+ref, this); + } + } + + static public Color getColor (String color) { + if (color == null || color.isEmpty ()) + return Color.gray; + LeeFilter leeFilter = leeFilterList.get (color.replaceAll ("\\s", "").toUpperCase ()); + if (leeFilter != null) + return new Color (leeFilter.value); + color = color.toLowerCase (); + try { + Field field = Class.forName ("java.awt.Color").getField (color); + return (Color) field.get (null); + } catch (Exception e) { + } + try { + return new Color (Integer.valueOf (color.substring (0, 2), 16), + Integer.valueOf (color.substring (2, 4), 16), + Integer.valueOf (color.substring (4, 6), 16)); + } catch (Exception e) { + } + return Color.black; + } + + static { + new LeeFilter ("002", 0xFF78DC, "Rose Pink"); + new LeeFilter ("003", 0xFAF0FA, "Lavender Tint"); + new LeeFilter ("004", 0xFFC8B4, "Medium Bastard Amber"); + new LeeFilter ("007", 0xFAFAD2, "Pale Yellow"); + new LeeFilter ("008", 0xFC9B80, "Dark Salmon"); + new LeeFilter ("009", 0xFCD7B3, "Pale Amber Gold"); + new LeeFilter ("010", 0xFFFF00, "Medium Yellow"); + new LeeFilter ("013", 0xFCD89B, "Straw Tint"); + new LeeFilter ("015", 0xFFCD00, "Deep Straw"); + new LeeFilter ("017", 0xE68C64, "Surprise Peach"); + new LeeFilter ("019", 0xFF4600, "Fire"); + new LeeFilter ("020", 0xFFBE55, "Medium Amber"); + new LeeFilter ("021", 0xFF8C32, "Gold Amber"); + new LeeFilter ("022", 0xFF6900, "Dark Amber"); + new LeeFilter ("024", 0xFF5A64, "Scarlet"); + new LeeFilter ("025", 0xFF6E46, "Sunset Red"); + new LeeFilter ("026", 0xE6003C, "Bright Red"); + new LeeFilter ("027", 0xC8003C, "Medium Red"); + new LeeFilter ("029", 0xE1003C, "Plasa Red"); + new LeeFilter ("035", 0xFFC8D2, "Light Pink"); + new LeeFilter ("036", 0xFFA0B9, "Medium Pink"); + new LeeFilter ("046", 0xDC005A, "Dark Magenta"); + new LeeFilter ("048", 0xE66EAF, "Rose Purple"); + new LeeFilter ("049", 0xBE0091, "Medium Purple"); + new LeeFilter ("052", 0xE6AAFA, "Light Lavender"); + new LeeFilter ("053", 0xE6E6FA, "Paler Lavender"); + new LeeFilter ("058", 0xB46EF0, "Lavender"); + new LeeFilter ("061", 0xDCF5FF, "Mist Blue"); + new LeeFilter ("063", 0xD2F5FF, "Pale Blue"); + new LeeFilter ("068", 0x46B4F0, "Sky Blue"); + new LeeFilter ("071", 0x0000B4, "Tokyo Blue"); + new LeeFilter ("075", 0x64A0F0, "Evening Blue"); + new LeeFilter ("079", 0x3C8CD2, "Just Blue"); + new LeeFilter ("085", 0x006EB9, "Deeper Blue"); + new LeeFilter ("088", 0xDCFF64, "Lime Green"); + new LeeFilter ("089", 0x5ADC5A, "Moss Green"); + new LeeFilter ("090", 0x00BE00, "Dark Yellow Green"); + new LeeFilter ("100", 0xF5FF00, "Spring Yellow"); + new LeeFilter ("101", 0xFFF500, "Yellow"); + new LeeFilter ("102", 0xFFDC5F, "Light Amber"); + new LeeFilter ("103", 0xFCEACC, "Straw"); + new LeeFilter ("104", 0xFFDC00, "Deep Amber"); + new LeeFilter ("105", 0xFFA000, "Orange"); + new LeeFilter ("106", 0xF00032, "Primary Red"); + new LeeFilter ("107", 0xFFA5AF, "Light Rose"); + new LeeFilter ("108", 0xFCBEA9, "English Rose"); + new LeeFilter ("109", 0xFFB2AF, "Light Salmon"); + new LeeFilter ("110", 0xFFB4C8, "Middle Rose"); + new LeeFilter ("111", 0xFF8CBE, "Dark Pink"); + new LeeFilter ("113", 0xFF0064, "Magenta"); + new LeeFilter ("115", 0x00EBC8, "Peacock Blue"); + new LeeFilter ("116", 0x00C8B9, "Medium Blue-Green"); + new LeeFilter ("117", 0xB4FAF5, "Steel Blue"); + new LeeFilter ("118", 0x00E1EB, "Light Blue"); + new LeeFilter ("119", 0x0078C8, "Dark Blue"); + new LeeFilter ("120", 0x005FBE, "Deep Blue"); + new LeeFilter ("121", 0xB4FF64, "LEE Green"); + new LeeFilter ("122", 0x78FA6E, "Fern Green"); + new LeeFilter ("124", 0x00DC78, "Dark Green"); + new LeeFilter ("126", 0xBE009B, "Mauve"); + new LeeFilter ("127", 0xE16273, "Smokey Pink"); + new LeeFilter ("128", 0xFF50B4, "Bright Pink"); + new LeeFilter ("129", 0xFFFFFF, "Heavy Frost"); + new LeeFilter ("130", 0xFFFFFF, "Clear"); + new LeeFilter ("131", 0x64FAD2, "Marine Blue"); + new LeeFilter ("132", 0x00A0DC, "Medium Blue"); + new LeeFilter ("134", 0xFAA873, "Golden Amber"); + new LeeFilter ("135", 0xFF5F00, "Deep Golden Amber"); + new LeeFilter ("136", 0xF0BEE6, "Pale Lavender"); + new LeeFilter ("137", 0xC8B4E6, "Special Lavender"); + new LeeFilter ("138", 0xDCFFA0, "Pale Green"); + new LeeFilter ("139", 0x4BC300, "Primary Green"); + new LeeFilter ("140", 0x87F0EB, "Summer Blue"); + new LeeFilter ("141", 0x00D2E6, "Bright Blue"); + new LeeFilter ("142", 0xAAAAF0, "Pale Violet"); + new LeeFilter ("143", 0x64BED2, "Pale Navy Blue"); + new LeeFilter ("144", 0x5AE1E6, "No Colour Blue"); + new LeeFilter ("147", 0xFCB98C, "Apricot"); + new LeeFilter ("148", 0xFF507D, "Bright Rose"); + new LeeFilter ("151", 0xFFCDC3, "Gold Tint"); + new LeeFilter ("152", 0xFFD2C1, "Pale Gold"); + new LeeFilter ("153", 0xFFC8C8, "Pale Salmon"); + new LeeFilter ("154", 0xFFD5CF, "Pale Rose"); + new LeeFilter ("156", 0xE1B48C, "Chocolate"); + new LeeFilter ("157", 0xFF92A3, "Pink"); + new LeeFilter ("158", 0xFF8700, "Deep Orange"); + new LeeFilter ("159", 0xFFFAEB, "No Colour Straw"); + new LeeFilter ("161", 0x7DD2F5, "Slate Blue"); + new LeeFilter ("162", 0xFCDED8, "Bastard Amber"); + new LeeFilter ("164", 0xFF3200, "Flame Red"); + new LeeFilter ("165", 0x5AC8EB, "Daylight Blue"); + new LeeFilter ("169", 0xFADCF0, "Lilac Tint"); + new LeeFilter ("170", 0xE6AADC, "Deep Lavender"); + new LeeFilter ("172", 0x00DCDC, "Lagoon Blue"); + new LeeFilter ("174", 0xAFE1FA, "Dark Steel Blue"); + new LeeFilter ("176", 0xFFAAA0, "Loving Amber"); + new LeeFilter ("179", 0xFFBE00, "Chrome Orange"); + new LeeFilter ("180", 0xA064E6, "Dark Lavender"); + new LeeFilter ("181", 0x5000AA, "Congo Blue"); + new LeeFilter ("182", 0xF50000, "Light Red"); + new LeeFilter ("183", 0x00D7E3, "Moonlight Blue"); + new LeeFilter ("184", 0xF0E1D7, "Cosmetic Peach"); + new LeeFilter ("186", 0xF8DCDD, "Cosmetic Silver Rose"); + new LeeFilter ("187", 0xF5E4D7, "Cosmetic Rouge"); + new LeeFilter ("188", 0xFFEBD7, "Cosmetic Highlight"); + new LeeFilter ("189", 0xEEEDD8, "Cosmetic Silver Moss"); + new LeeFilter ("191", 0xE9EEEE, "Cosmetic Aqua Blue"); + new LeeFilter ("192", 0xFF8CB4, "Flesh Pink"); + new LeeFilter ("194", 0xBE8CF0, "Surprise Pink"); + new LeeFilter ("195", 0x006ED2, "Zenith Blue"); + new LeeFilter ("196", 0x78D2E6, "True Blue"); + new LeeFilter ("197", 0x82AAE6, "Alice Blue"); + new LeeFilter ("198", 0x6478C8, "Palace Blue"); + new LeeFilter ("199", 0x6464E6, "Regal Blue"); + new LeeFilter ("200", 0x91BEF5, "Double C.T. Blue"); + new LeeFilter ("201", 0xC3E1FA, "Full C.T. Blue"); + new LeeFilter ("202", 0xD7F0FF, "Half C.T. Blue"); + new LeeFilter ("203", 0xEBFCFF, "Quarter C.T. Blue"); + new LeeFilter ("204", 0xFAC387, "Full C.T. Orange"); + new LeeFilter ("205", 0xFCD9B1, "Half C.T. Orange"); + new LeeFilter ("206", 0xFCEAD6, "Quarter C.T. Orange"); + new LeeFilter ("207", 0xF0B46B, "Full C.T. Orange + .3 ND"); + new LeeFilter ("208", 0xE6A550, "Full C.T. Orange + .6 ND"); + new LeeFilter ("209", 0xC8C8C8, "0.3 ND"); + new LeeFilter ("210", 0xA5A5A5, "0.6 ND"); + new LeeFilter ("211", 0x828282, "0.9 ND"); + new LeeFilter ("212", 0xFFFAD7, "L.C.T.Yellow (Y1)"); + new LeeFilter ("213", 0xE6FCDC, "White Flame Green"); + new LeeFilter ("214", 0xFFFFFF, "Full Tough Spun"); + new LeeFilter ("215", 0xFFFFFF, "Half Tough Spun"); + new LeeFilter ("216", 0xFFFFFF, "White Diffusion"); + new LeeFilter ("217", 0xF5FFFF, "Blue Diffusion"); + new LeeFilter ("218", 0xF5FFFF, "Eighth C.T. Blue"); + new LeeFilter ("219", 0x9BDCAF, "LEE Fluorescent Green"); + new LeeFilter ("220", 0xFFFFFF, "White Frost"); + new LeeFilter ("221", 0xF5FFFF, "Blue Frost"); + new LeeFilter ("223", 0xFFF3E8, "Eighth C.T. Orange"); + new LeeFilter ("224", 0x96A0BE, "Daylight Blue Frost"); + new LeeFilter ("225", 0x9EA0A2, "Neutral Density Frost"); + new LeeFilter ("226", 0xFFFFFA, "LEE U.V."); + new LeeFilter ("228", 0xFFFFFF, "Brushed Silk"); + new LeeFilter ("229", 0xFFFFFF, "Quarter Tough Spun"); + new LeeFilter ("230", 0xDCBE8C, "Super Correction L.C.T. Yellow"); + new LeeFilter ("232", 0xEDBE83, "Super Correction W.F. Green"); + new LeeFilter ("236", 0xFAC795, "H.M.I. (to Tungsten)"); + new LeeFilter ("237", 0xFCB292, "C.I.D. (to Tungsten)"); + new LeeFilter ("238", 0xF5B9AA, "C.S.I. (to Tungsten)"); + new LeeFilter ("239", 0xCDCDCD, "Polariser"); + new LeeFilter ("241", 0xAADCC3, "LEE Fluorescent 5700 Kelvin"); + new LeeFilter ("242", 0xB9E6B9, "LEE Fluorescent 4300 Kelvin"); + new LeeFilter ("243", 0xCDF5AF, "LEE Fluorescent 3600 Kelvin"); + new LeeFilter ("244", 0xE6FABE, "LEE Plus Green"); + new LeeFilter ("245", 0xF0FCD2, "Half Plus Green"); + new LeeFilter ("246", 0xF5FFE6, "Quarter Plus Green"); + new LeeFilter ("247", 0xFAC3D7, "LEE Minus Green"); + new LeeFilter ("248", 0xFFE2E4, "Half Minus Green"); + new LeeFilter ("249", 0xFFECF0, "Quarter Minus Green"); + new LeeFilter ("250", 0xFFFFFF, "Half White Diffusion"); + new LeeFilter ("251", 0xFFFFFF, "Quarter White Diffusion"); + new LeeFilter ("252", 0xFFFFFF, "Eighth White Diffusion"); + new LeeFilter ("253", 0xFFFFFF, "Hampshire Frost"); + new LeeFilter ("254", 0xFFFFFF, "New Hampshire Frost"); + new LeeFilter ("255", 0xFFFFFF, "Hollywood Frost"); + new LeeFilter ("256", 0xFFFFFF, "Half Hampshire Frost"); + new LeeFilter ("257", 0xFFFFFF, "Quarter Hampshire Frost"); + new LeeFilter ("258", 0xFFFFFF, "Eighth Hampshire Frost"); + new LeeFilter ("261", 0xFFFFFF, "Tough Spun FR - Full"); + new LeeFilter ("262", 0xFFFFFF, "Tough Spun FR - 3/4"); + new LeeFilter ("263", 0xFFFFFF, "Tough Spun FR - 1/2"); + new LeeFilter ("264", 0xFFFFFF, "Tough Spun FR - 3/8"); + new LeeFilter ("265", 0xFFFFFF, "Tough Spun FR - 1/4"); + new LeeFilter ("269", 0xFFFFFF, "LEE Heat Shield"); + new LeeFilter ("270", 0xBEBEBE, "LEE Scrim"); + new LeeFilter ("271", 0xF0F0F0, "Mirror Silver"); + new LeeFilter ("272", 0xF0DC96, "Soft Gold Reflector"); + new LeeFilter ("273", 0xF3F3F3, "Soft Silver Reflector"); + new LeeFilter ("274", 0xEBD791, "Mirror Gold"); + new LeeFilter ("275", 0xBEBEBE, "Black Scrim"); + new LeeFilter ("278", 0xF3FFF3, "Eighth Plus Green"); + new LeeFilter ("279", 0xFFF3F7, "Eighth Minus Green"); + new LeeFilter ("280", 0x000000, "Black Foil"); + new LeeFilter ("281", 0xCDE6FA, "Three Quarter C.T. Blue"); + new LeeFilter ("283", 0xAFD9F5, "One and a Half C.T. Blue"); + new LeeFilter ("285", 0xFCCD94, "Three Quarter C.T. Orange"); + new LeeFilter ("286", 0xFFB464, "One and a Half C.T. Orange"); + new LeeFilter ("287", 0xFFA055, "Double C.T. Orange"); + new LeeFilter ("298", 0xE6E6E6, "0.15 ND"); + new LeeFilter ("299", 0x5F5F5F, "1.2 ND"); + new LeeFilter ("322", 0x41F5BE, "Soft Green"); + new LeeFilter ("323", 0x00E1AA, "Jade"); + new LeeFilter ("327", 0x008C50, "Forest Green"); + new LeeFilter ("328", 0xFF64C8, "Follies Pink"); + new LeeFilter ("332", 0xFF3787, "Special Rose Pink"); + new LeeFilter ("343", 0x8C00D2, "Special Medium Lavender"); + new LeeFilter ("345", 0xCD6ED7, "Fuchsia Pink"); + new LeeFilter ("352", 0x5AC8E1, "Glacier Blue"); + new LeeFilter ("353", 0x61E8E3, "Lighter Blue"); + new LeeFilter ("354", 0x00F0D7, "Special Steel Blue"); + new LeeFilter ("363", 0x006EC3, "Special Medium Blue"); + new LeeFilter ("366", 0xAAD2F0, "Cornflower"); + new LeeFilter ("400", 0xFFFFFF, "LEELux"); + new LeeFilter ("402", 0xFFFFFF, "Soft Frost"); + new LeeFilter ("404", 0xFFFFFF, "Half Soft Frost"); + new LeeFilter ("410", 0xFFFFFF, "Opal Frost"); + new LeeFilter ("414", 0xFFFFFF, "Highlight"); + new LeeFilter ("416", 0xFFFFFF, "Three Quarter White Diffusion"); + new LeeFilter ("420", 0xFFFFFF, "Light Opal Frost"); + new LeeFilter ("429", 0xFFFFFF, "Quiet Frost"); + new LeeFilter ("430", 0xFFFFFF, "Grid Cloth"); + new LeeFilter ("432", 0xFFFFFF, "Light Grid Cloth"); + new LeeFilter ("434", 0xFFFFFF, "Quarter Grid Cloth"); + new LeeFilter ("439", 0xFFFFFF, "Heavy Quiet Frost"); + new LeeFilter ("441", 0xFAC084, "Full C.T. Straw"); + new LeeFilter ("442", 0xFCDCAD, "Half C.T. Straw"); + new LeeFilter ("443", 0xFCEFDB, "Quarter C.T. Straw"); + new LeeFilter ("444", 0xFAF3E8, "Eighth C.T. Straw"); + new LeeFilter ("450", 0xFFFFFF, "Three Eighth White Diffusion"); + new LeeFilter ("452", 0xFFFFFF, "Sixteenth White Diffusion"); + new LeeFilter ("460", 0xFFFFFF, "Quiet Grid Cloth"); + new LeeFilter ("462", 0xFFFFFF, "Quiet Light Grid Cloth"); + new LeeFilter ("464", 0xFFFFFF, "Quiet Quarter Grid Cloth"); + new LeeFilter ("500", 0xB4D2FF, "Double New Colour Blue"); + new LeeFilter ("501", 0xD7EBFA, "New Colour Blue (Robertson Blue)"); + new LeeFilter ("502", 0xE1F0FF, "Half New Colour Blue"); + new LeeFilter ("503", 0xF4FAFF, "Quarter New Colour Blue"); + new LeeFilter ("504", 0xD2F5DC, "Waterfront Green"); + new LeeFilter ("505", 0xE3FF5A, "Sally Green"); + new LeeFilter ("506", 0xFFDACE, "Marlene"); + new LeeFilter ("507", 0xF85000, "Madge"); + new LeeFilter ("508", 0x5A46C3, "Midnight Maya"); + new LeeFilter ("511", 0x963C00, "Bacon Brown"); + new LeeFilter ("512", 0xcc6100, "Amber Delight"); + new LeeFilter ("513", 0xf5ff7d, "Ice and a Slice"); + new LeeFilter ("514", 0xf5ff5a, "Double G&T"); + new LeeFilter ("525", 0x8EB4FA, "Argent Blue"); + new LeeFilter ("550", 0xe3ca3c, "ALD Gold"); + new LeeFilter ("600", 0x98a8aa, "Arctic White"); + new LeeFilter ("601", 0x90a0a0, "Silver"); + new LeeFilter ("602", 0xa5a5aa, "Platinum"); + new LeeFilter ("603", 0xc8cdcd, "Moonlight White"); + new LeeFilter ("604", 0xFFC295, "Full C.T. Eight Five"); + + new LeeFilter ("642", 0x968200, "Half Mustard Yellow"); + new LeeFilter ("643", 0xB4A000, "Quarter Mustard Yellow"); + new LeeFilter ("650", 0xC8A862, "Industry Sodium"); + new LeeFilter ("651", 0xFF9B5F, "HI Sodium"); + new LeeFilter ("652", 0xFF8246, "Urban Sodium"); + new LeeFilter ("653", 0x965500, "LO Sodium"); + new LeeFilter ("700", 0x7D00CD, "Perfect Lavender"); + new LeeFilter ("701", 0xB45ADC, "Provence"); + new LeeFilter ("702", 0xE6D2F0, "Special Pale Lavender"); + new LeeFilter ("703", 0xD282DC, "Cold Lavender"); + new LeeFilter ("704", 0xF0AAFA, "Lily"); + new LeeFilter ("705", 0xF0AAFA, "Lily Frost"); + new LeeFilter ("706", 0x6E46C8, "King Fals Lavender"); + new LeeFilter ("707", 0x6400B4, "Ultimate Violet"); + new LeeFilter ("708", 0xDCEBFA, "Cool Lavender"); + new LeeFilter ("709", 0xC8C8FA, "Electric Lilac"); + new LeeFilter ("710", 0x8CA0F0, "Spir Special Blue"); + new LeeFilter ("711", 0xAABEDC, "Cold Blue"); + new LeeFilter ("712", 0xA0BEF0, "Bedford Blue"); + new LeeFilter ("713", 0x003CA0, "J.Winter Blue"); + new LeeFilter ("714", 0x5A91D2, "Elysian Blue"); + new LeeFilter ("715", 0x3C6EDC, "Cabana Blue"); + new LeeFilter ("716", 0x0064D2, "Mikkel Blue"); + new LeeFilter ("717", 0xC3E1FA, "Shanklin Frost"); + new LeeFilter ("718", 0xD4EDFA, "Half Shanklin Frost"); + new LeeFilter ("719", 0x9BC3F0, "Colour Wash Blue"); + new LeeFilter ("720", 0xC3E1FA, "Durham Daylight Frost"); + new LeeFilter ("721", 0x0082E6, "Berry Blue"); + new LeeFilter ("722", 0x008CD2, "Bray Blue"); + new LeeFilter ("723", 0x5082DC, "Virgin Blue"); + new LeeFilter ("724", 0x69E1EB, "Ocean Blue"); + new LeeFilter ("725", 0xBEF2F3, "Old Steel Blue"); + new LeeFilter ("727", 0x00A5B4, "QFD Blue"); + new LeeFilter ("728", 0xC8EBD2, "Steel Green"); + new LeeFilter ("729", 0x00AFAA, "Scuba Blue"); + new LeeFilter ("730", 0xDCFFE6, "Liberty Green"); + new LeeFilter ("731", 0xE1FAD7, "Dirty Ice"); + new LeeFilter ("733", 0xEBF7CF, "Damp Squib"); + new LeeFilter ("735", 0x00BE78, "Velvet Green"); + new LeeFilter ("736", 0x00AA00, "Twickenham Green"); + new LeeFilter ("738", 0xAAFF00, "JAS Green"); + new LeeFilter ("740", 0x5A6E00, "Aurora Borealis Green"); + new LeeFilter ("741", 0x826400, "Mustard Yellow"); + new LeeFilter ("742", 0xE19B50, "Bram Brown"); + new LeeFilter ("744", 0xF8C882, "Dirty White"); + new LeeFilter ("746", 0x6E3C00, "Brown"); + new LeeFilter ("747", 0xF5B99F, "Easy White"); + new LeeFilter ("748", 0xE96785, "Seedy Pink"); + new LeeFilter ("749", 0xFCD3CD, "Hampshire Rose"); + new LeeFilter ("750", 0xFAF1FE, "Durham Frost"); + new LeeFilter ("763", 0xFCF0D2, "Wheat"); + new LeeFilter ("764", 0xFCE6B4, "Sun Colour Straw"); + new LeeFilter ("765", 0xFFE591, "LEE Yellow"); + new LeeFilter ("767", 0xFFE600, "Oklahoma Yellow"); + new LeeFilter ("768", 0xFFC600, "Egg Yolk Yellow"); + new LeeFilter ("770", 0xFFB400, "Burnt Yellow"); + new LeeFilter ("773", 0xFCC5B2, "Cardbox Amber"); + new LeeFilter ("774", 0xFCD2BE, "Soft Amber Key 1"); + new LeeFilter ("775", 0xFCC6A5, "Soft Amber Key 2"); + new LeeFilter ("776", 0xFCBE9B, "Nectarine"); + new LeeFilter ("777", 0xF58200, "Rust"); + new LeeFilter ("778", 0xFF7600, "Millennium Gold"); + new LeeFilter ("779", 0xFC9885, "Bastard Pink"); + new LeeFilter ("780", 0xFF6F00, "AS Golden Amber"); + new LeeFilter ("781", 0xFF5000, "Terry Red"); + new LeeFilter ("787", 0xB9003C, "Marius Red"); + new LeeFilter ("789", 0xAA3C32, "Blood Red"); + new LeeFilter ("790", 0xFFB4A5, "Moroccan Pink"); + new LeeFilter ("791", 0xF5B9AA, "Moroccan Frost"); + new LeeFilter ("793", 0xFF3CA0, "Vanity Fair"); + new LeeFilter ("794", 0xFFAFDC, "Pretty 'n Pink"); + new LeeFilter ("795", 0xFA46C8, "Magical Magenta"); + new LeeFilter ("797", 0xAF0096, "Deep Purple"); + new LeeFilter ("798", 0xA000BE, "Chrysalis Pink"); + new LeeFilter ("799", 0x3C00B4, "Special KH Lavender"); + + new LeeFilter ("CL104", 0xff9600, "Cool LED Deep Amber"); + new LeeFilter ("CL105", 0xff6e00, "Cool LED Orange"); + new LeeFilter ("CL106", 0xbe0032, "Cool LED Primary Red"); + new LeeFilter ("CL113", 0xc80050, "Cool LED Magenta"); + new LeeFilter ("CL115", 0x00ffa0, "Cool LED Peacock Blue"); + new LeeFilter ("CL116", 0x00aa82, "Cool LED Medium Blue-Green"); + new LeeFilter ("CL117", 0xebffa0, "Cool LED Steel Blue"); + new LeeFilter ("CL118", 0x00f5b4, "Cool LED Light Blue"); + new LeeFilter ("CL119", 0x0091a5, "Cool LED Dark Blue"); + new LeeFilter ("CL126", 0xaf0050, "Cool LED Mauve"); + new LeeFilter ("CL128", 0xff0069, "Cool LED Bright Pink"); + new LeeFilter ("CL132", 0x00c8c8, "Cool LED Medium Blue"); + new LeeFilter ("CL139", 0x4bc300, "Cool LED Primary Green"); + new LeeFilter ("CL147", 0xff7d46, "Cool LED Apricot"); + new LeeFilter ("CL158", 0xff6900, "Cool LED Deep Orange"); + new LeeFilter ("CL164", 0xff0000, "Cool LED Flame Red"); + new LeeFilter ("CL180", 0xeb78a0, "Cool LED Dark Lavender"); + new LeeFilter ("CL181", 0x960078, "Cool LED Congo Blue"); + new LeeFilter ("CL182", 0xdc0052, "Cool LED Light Red"); + + new LeeFilter ("414P", 0xFFFFFF, "Perforated Highlight"); + new LeeFilter ("439P", 0xFFFFFF, "Perforated Heavy Quiet Frost"); + new LeeFilter ("A205", 0xFAD7AF, "Half C.T.O. Acrylic Panel"); + new LeeFilter ("A207", 0xF3B76E, "Full C.T.O. + 0.3 ND Acrylic Panel"); + new LeeFilter ("A208", 0xE7A651, "Full C.T.O. + 0.6 ND Acrylic Panel"); + new LeeFilter ("A209", 0xCDCDCD, "0.3 ND Acrylic Panel"); + new LeeFilter ("A210", 0xAAAAAA, "0.6 ND Acrylic Panel"); + new LeeFilter ("A211", 0x878787, "0.9 ND Acrylic Panel"); + } + + // + // + // + // + // + // + // + // + // + // + // + // +} diff --git a/src/java/adecWatt/model/Patch.java b/src/java/adecWatt/model/Patch.java new file mode 100644 index 0000000..5a83ddf --- /dev/null +++ b/src/java/adecWatt/model/Patch.java @@ -0,0 +1,90 @@ +package adecWatt.model; + +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +public class Patch { + public TreeMap lineConsumption = new TreeMap (); + public TreeMap lineCircuit = new TreeMap (Circuits.lineComparator); + + public TreeMap circuitConsumption = new TreeMap (); + public TreeMap> circuitLines = new TreeMap > (Circuits.lineComparator); + public TreeSet circuitless = new TreeSet (); + public TreeSet unplug = new TreeSet (Circuits.lineComparator); + public TreeSet shortcut = new TreeSet (Circuits.lineComparator); + + private void addConsumption (TreeMap map, String name, int value) { + Integer oldValue = map.get (name); + map.put (name, oldValue == null ? value : oldValue+value); + } + + public Set getLineKeys () { + TreeSet result = new TreeSet (Circuits.lineComparator); + result.addAll (lineCircuit.keySet ()); + return result; + } + + public Set getCircuitKeys () { + TreeSet result = new TreeSet (Circuits.lineComparator); + result.addAll (circuitLines.keySet ()); + return result; + } + + public Patch (Circuits circuits) { + for (Comp lastComp : circuits.keySet ()) { + Circuits.Circuit circuit = circuits.get (lastComp); + String lineName = lastComp.getLine (); + if (lineName == null) + continue; + TreeSet circuitNames = circuit.names; + int consumption = circuit.consumption; + switch (circuitNames.size ()) { + case 0: + continue; + case 1: + String circuitName = circuitNames.first (); + addConsumption (lineConsumption, lineName, consumption); + lineCircuit.put (lineName, circuitName); + addConsumption (circuitConsumption, circuitName, consumption); + TreeSet otherLines = circuitLines.get (circuitName); + if (otherLines == null) + circuitLines.put (circuitName, otherLines = new TreeSet (Circuits.lineComparator)); + otherLines.add (lineName); + break; + default: + lineCircuit.put (lineName, Circuits.SHORTCUT); + for (String circuitName2 : circuitNames) + shortcut.add (circuitName2); + } + } + for (Comp beginComp : circuits.getPlugedComps ()) + accLoop : + for (Acc beginAcc : beginComp.allPlugs) { + String circuitName = beginAcc.getCircuit (beginComp); + String compName = beginComp.getName (); + if (circuits.inLoop (beginAcc)) { + if (circuitName != null) + unplug.add (circuitName); + else + circuitless.add (compName); + continue; + } + for (Comp lastComp : circuits.keySet ()) { + Circuits.Circuit circuit = circuits.get (lastComp); + if (!circuit.nodes.contains (beginAcc)) + continue; + if (lastComp.getLine () == null) + if (circuitName != null) + unplug.add (circuitName); + else + circuitless.add (compName); + continue accLoop; + } + if (circuitName != null) + unplug.add (circuitName); + else + circuitless.add (compName); + } + } +} diff --git a/src/java/adecWatt/model/Permanent.java b/src/java/adecWatt/model/Permanent.java new file mode 100644 index 0000000..b386e60 --- /dev/null +++ b/src/java/adecWatt/model/Permanent.java @@ -0,0 +1,162 @@ +package adecWatt.model; + +import java.util.Arrays; +import java.util.Collection; +import java.util.TreeSet; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.Bundle; +import adecWatt.model.xml.XmlPermanent; + +public abstract class Permanent

, T extends Enum, A extends Enum> { + // ======================================== + static public enum UnitTypeEnum { Furniture, Information, Line, Accessory, Building, Lightplot; }; + static public enum SegmTypeEnum { Segment; }; + static public enum CompTypeEnum { Component; }; + static public enum AccTypeEnum { Accessory; }; + // XXX type "Comp" pour référence ? + static public enum PropTypeEnum { Text, Article, Icon, Image, Preview, Enum, Building, City, Number, Square, Geo, Cube; }; + + static public enum UnitAttrEnum { Id, Name, Modifier, Parent, Author, Updated; }; + static public enum SegmAttrEnum { Name, Modifier, Model, Placeid; }; + static public enum CompAttrEnum { Name, Modifier, Model, Placeid, Available; }; + static public enum AccAttrEnum { Name, Modifier, Model, Placeid; }; + static public enum PropAttrEnum { Name, Modifier, Multilabel, Spin, Choice, Rank; }; + + // ======================================== + static public final String + Lock = "lock", + Mandatory = "mandatory", + Localized = "localized", + NoMouse = "nomouse", + Hidden = "hidden", + Sticky = "sticky", + Reserved = "reserved", + Direct = "direct"; + + static public final String + NoSpin = "none", + HorizontalSpin = "horizontal"; + + // ======================================== + static public final Collection UnitModifiersSet = Arrays.asList (Localized); + static public final Collection SegmModifiersSet = Arrays.asList (Sticky, Hidden); + static public final Collection CompModifiersSet = Arrays.asList (Sticky, Reserved, Hidden); + static public final Collection AccModifiersSet = Arrays.asList (); + static public final Collection PropModifiersSet = Arrays.asList (Lock, Mandatory, Localized, Hidden, NoMouse); + static public final Collection PropHiddenModifiersSet = Arrays.asList (Lock); + static public final Collection PropNotHiddenModifiersSet = Arrays.asList (Mandatory, Localized, Hidden, NoMouse); + + static public final Collection PropSpinSet = Arrays.asList (NoSpin, HorizontalSpin); + + // ======================================== + public abstract Collection getModifiersSet (); + public abstract T getTypeToken (); + public abstract A getNameToken (); + public abstract A getModifierToken (); + + protected P xmlPermanent; + protected String name; + protected Collection modifiers; + protected Collection unknownModifiers; + + // ======================================== + public String getName () { return name; } + public String getLocalName () { return isLocalized () ? Bundle.getUser (getName ()) : getName (); } + public Collection getModifiers () { return modifiers; } + + public String getModifiersString () { return getModifiersString (modifiers); } + public boolean isModifier (String modifierName) { return isModifier (modifierName, modifiers); } + public boolean isLocalized () { return isModifier (Localized); } + public boolean isLock () { return isModifier (Lock); } + public boolean isHidden () { return isModifier (Hidden); } + public boolean isMandatory () { return isModifier (Mandatory); } + public boolean isSticky () { return isModifier (Sticky); } + public boolean isReserved () { return isModifier (Reserved); } + public boolean isNoMouse () { return isModifier (NoMouse); } + public boolean isDirect () { return isModifier (Direct); } + + // ======================================== + protected Permanent () { + } + protected Permanent (P xmlPermanent) { + initXmlAvantOwnProp (xmlPermanent); + } + + protected void importFrom (Permanent from) { + if (unknownModifiers == null && from.unknownModifiers != null) + unknownModifiers = from.unknownModifiers; + if (from.modifiers != null) + if (modifiers != null) + modifiers.addAll (from.modifiers); + else + modifiers = new TreeSet (from.modifiers); + // XXX pb cause furniture à la place de composant dans un copier/coller + // if (xmlPermanent == null && from.xmlPermanent != null) + // xmlPermanent = from.xmlPermanent; + } + + protected void initXmlAvantOwnProp (P xmlPermanent) { + this.xmlPermanent = xmlPermanent; + name = xmlPermanent.getFacet (getNameToken ()); + try { + unknownModifiers = xmlPermanent.getSplitFacet (getModifierToken ()); + modifiers = null; // XXX pas utile + for (String token : unknownModifiers) + addModifier (token); + unknownModifiers.removeAll (modifiers); + if (unknownModifiers.size () < 1) + unknownModifiers = null; + } catch (Exception e) { + } + } + + // ======================================== + public void setModifiers (Collection modifiers) { + if (modifiers == null || modifiers.size () == 0) { + this.modifiers = null; + return; + } + this.modifiers = modifiers; + } + public void addModifier (String modifier) { + if (modifier == null || modifier.isEmpty ()) + return; + if (!getModifiersSet ().contains (modifier)) + return; + if (modifiers == null) + modifiers = new TreeSet (); + modifiers.add (modifier); + } + public void removeModifier (String modifier) { + if (modifiers == null || modifier == null || modifier.isEmpty ()) + return; + modifiers.remove (modifier); + if (modifiers.size () < 1) + modifiers = null; + } + static public boolean isModifier (String modifierName, Collection modifiers) { + return modifiers != null && modifiers.contains (modifierName); + } + static public String getModifiersString (Collection modifiers) { + if (modifiers == null) + return ""; + return String.join ("|", modifiers); + } + + // ======================================== + @SuppressWarnings ("unchecked") + public Element getXml (Node parent, Document document) { + Element child = xmlPermanent == null ? + document.createElement (getTypeToken ().toString ().toLowerCase ()) + : xmlPermanent.getXml (document); + parent.appendChild (child); + XmlPermanent.putFacet (child, getNameToken (), name); + XmlPermanent.putSplitFacet (child, getModifierToken (), modifiers, unknownModifiers); + return child; + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/PermanentDB.java b/src/java/adecWatt/model/PermanentDB.java new file mode 100644 index 0000000..aa96796 --- /dev/null +++ b/src/java/adecWatt/model/PermanentDB.java @@ -0,0 +1,478 @@ +package adecWatt.model; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Document; + +import misc.Config; +import misc.Log; +import misc.Util; +import static misc.Config.FS; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.unit.Building; +import adecWatt.model.xml.XmlUnit; + +public class PermanentDB { + + // ======================================== + static public final File dataDir = Config.findDataDir (); + static public enum UnitLocation { Server, Local, Zip }; + static public final String localToken = "local"; + static public final String serverToken = "server"; + static public final String cacheToken = "cache"; + static public final List localRemoteDir = Arrays.asList (localToken, serverToken); + static public final String lptExtention = "lpt"; + static public final String lpzExtention = "lpz"; + static public final String backExtention = "back"; + static public final String[] exportExtention = { lpzExtention }; + + // ======================================== + private AdecWatt adecWatt; + private ImageDB iconDB; + private ImageDB imageDB; + private String powerPlugId, powerSocketId; + + public String getPowerPlugId () { return powerPlugId; } + public String getPowerSocketId () { return powerSocketId; } + + public ArrayList getAllBuildings () { + ArrayList result = new ArrayList (); + for (Enumeration enumUnitNode = getRootByName (Prop.PropBuilding).getUnitNode ().breadthFirstEnumeration (); + enumUnitNode.hasMoreElements(); + ) { + Building building = (Building) ((UnitNode) enumUnitNode.nextElement ()).getUnit (); + if (building.isUncompleted (null)) + continue; + result.add (building); + } + return result; + } + + public PermanentDB (AdecWatt adecWatt) { + this.adecWatt = adecWatt; + iconDB = adecWatt.getIconDB (); + imageDB = adecWatt.getImageDB (); + } + + // ======================================== + // Unit + // ======================================== + HashSet> allUnit = new HashSet> (); + Hashtable> idUnit = new Hashtable> (); + Hashtable> namedRoots = new Hashtable> (); + + public boolean isReferedUnit (String unitId) { return idUnit.containsKey (unitId); } + public Unit getUnitById (String unitId) { return idUnit.get (unitId); } + public Unit getRootByName (String unitName) { return namedRoots.get (unitName); } + public Set getReferedIds () { return idUnit.keySet (); } + + public boolean isModifiedUnit () { + for (Unit unit : allUnit) + if (unit.story.isModified ()) + return true; + return false; + } + + // ======================================== + public void reload () { + powerSocketId = powerPlugId = null; + allUnit.clear (); + idUnit.clear (); + namedRoots.clear (); + for (String srcDir : localRemoteDir) + for (File file : getAllXmlFiles (srcDir)) + try { + if (file.length () == 0) + continue; + FileInputStream fileInputStream = new FileInputStream (file); + Unit unit = Unit.getInstanceFromStream (adecWatt, fileInputStream, file, + serverToken.equals (srcDir) ? UnitLocation.Server : UnitLocation.Local); + fileInputStream.close (); + if (isReferedUnit (unit.getId ())) { + System.err.println (unit.getName ()+" already recorded : skip "+file); + // ignore + continue; + } + add (unit); + } catch (Exception e) { + System.err.println ("XXX: "+file+" error: "+e); + e.printStackTrace (); + } + for (Unit unit : allUnit) + unit.updateXmlParent (); + } + + public void newNamePlan (TreeMap iconMap, TreeMap imageMap) { + HashSet> visited = new HashSet> (); + for (Unit unit : allUnit) + unit.newNamePlan (visited, iconMap, imageMap); + } + + public void add (Unit unit) { + String unitId = unit.getId (); + try { + allUnit.remove (idUnit.get (unitId)); + } catch (Exception e) { + } + allUnit.add (unit); + idUnit.put (unitId, unit); + adecWatt.getUser ().updateDataId (unitId); + if ("powerPlug".equals (unit.getName ())) + powerPlugId = unitId; + if ("powerSocket".equals (unit.getName ())) + powerSocketId = unitId; + unit.enableStory (); + } + public void forget (Unit unit) { + adecWatt.broadcastDisplay (AdecWattManager.actionClose, unit); + idUnit.remove (unit.getId ()); + allUnit.remove (unit); + unit.disableStory (); + // XXX et si "powerPlug" ou "powerSocket" ? + } + public Unit reload (Unit unit) { + for (String srcDir : localRemoteDir) { + try { + File file = getXmlFile (new File (dataDir, srcDir), unit.getFileName ()); + FileInputStream fileInputStream = new FileInputStream (file); + Unit newUnit = Unit.getInstanceFromStream (adecWatt, fileInputStream, file, + serverToken.equals (srcDir) ? UnitLocation.Server : UnitLocation.Local); + fileInputStream.close (); + return newUnit; + } catch (Exception e) { + } + } + return null; + } + public void remove (Unit unit) { + if (unit.file != null) + Util.backup (unit.file, Util.getExtention (unit.file), backExtention); + forget (unit); + } + public void renameVisitor (HashSet> units) { + TreeMap translateMap = new TreeMap (); + String pattern = String.format ("%03d-", User.visitorId); + User user = adecWatt.getUser (); + for (Unit unit : units) { + String unitId = unit.getId (); + if (!unitId.startsWith (pattern)) + continue; + translateMap.put (unitId, user.getDataId ()); + } + if (translateMap.size () < 1) + return; + for (String unitId : translateMap.keySet ()) { + Unit unit = idUnit.get (unitId); + if (unit.file != null) + Util.backup (unit.file, Util.getExtention (unit.file), backExtention); + idUnit.remove (unitId); + String newUnitId = translateMap.get (unitId); + unit.changeId (newUnitId); + idUnit.put (newUnitId, unit); + } + for (Unit unit : allUnit) + if (unit.renameUnits (translateMap)) + // YYY voir save ? + unit.story.markNotSaved (); + } + public void promote (HashSet> units) { + if (units.size () == 0) + return; + for (Unit unit : units) + unit.promote (); + adecWatt.broadcastUpdate (AdecWatt.BroadcastUnitRoots); + } + public void renameImages (TreeMap translateMap) { + for (Unit unit : allUnit) + if (unit.renameImages (translateMap)) + // YYY voir save ? + unit.story.markNotSaved (); + } + + // ======================================== + static public final File getXmlFile (String name) { + for (String srcDir : localRemoteDir) + try { + File file = getXmlFile (new File (dataDir, srcDir), name); + if (file != null) + return file; + } catch (Exception e) { + } + return null; + } + + static public final File getXmlFile (File dir, String name) { + File test = new File (dir, name); + if (test.exists ()) + return test; + for (File subDir : getSubDirs (dir)) { + test = getXmlFile (subDir, name); + if (test != null) + return test; + + } + return null; + } + + static public final File[] getXmlFiles (File dir) { + return dir.listFiles (new FileFilter () { + public boolean accept (File file) { + return file.isFile () && !file.isHidden () && + lptExtention.equals (Util.getExtention (file)); + } + }); + } + static public final File[] getSubDirs (File dir) { + return dir.listFiles (new FileFilter () { + public boolean accept (File file) { + return file.isDirectory () && ! file.isHidden (); + } + }); + } + public boolean isFileNameExists (String baseName) { + for (String srcDir : localRemoteDir) + try { + if (isFileExists (new File (dataDir, srcDir), baseName)) + return true; + } catch (Exception e) { + } + return false; + } + public boolean isFileExists (File dir, String baseName) { + for (File file : getXmlFiles (dir)) { + String fileName = file.getName (); + if (fileName.startsWith (baseName) && + lptExtention.equals (fileName.substring (1+baseName.length ()))) + return true; + } + for (File subDir : getSubDirs (dir)) + if (isFileExists (subDir, baseName)) + return true; + return false; + } + + // ======================================== + static public ArrayList getAllXmlFiles (String srcDir) { + ArrayList result = new ArrayList (); + try { + getAllXmlFiles (new File (dataDir, srcDir), result); + } catch (Exception e) { + } + return result; + } + static public void getAllXmlFiles (File dir, ArrayList result) { + for (File file : getXmlFiles (dir)) + result.add (file); + for (File subDir : getSubDirs (dir)) + getAllXmlFiles (subDir, result); + } + + // ======================================== + static public File getInputFile (String name) { + for (String srcDir : localRemoteDir) { + File file = new File (dataDir, srcDir+FS+name); + if (file.exists () && file.isFile ()) + return file; + } + throw new IllegalArgumentException ("Can't find input "+name+"!"); + } + + // ======================================== + static public File getLocalFile (String name) { + File file = (new File (dataDir, localToken+FS+name)); + file.getParentFile ().mkdirs (); + return file; + } + static public File getRemoteFile (String name) { + File file = (new File (dataDir, serverToken+FS+name)); + file.getParentFile ().mkdirs (); + return file; + } + + // ======================================== + static public XmlUnit readXmlUnit (InputStream stream) { + try { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder (); + Document document = documentBuilder.parse (stream); + document.normalizeDocument (); + return new XmlUnit (document.getFirstChild ()); + } catch (Exception e) { + Log.keepLastException ("PermanentDB::readDocument", e); + throw new IllegalArgumentException ("Not XML file input."); + } + } + + // ======================================== + static public Document newDocument () { + try { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder (); + Document document = documentBuilder.newDocument (); + document.setXmlStandalone (true); + return document; + } catch (Exception e) { + return null; + } + } + + // ======================================== + static public void writeUnit (Unit unit, File file) { + try { + FileOutputStream fileOutputStream = new FileOutputStream (file); + writeUnit (unit, fileOutputStream); + fileOutputStream.close (); + } catch (Exception e) { + Log.keepLastException ("PermanentDB::writeDocument", e); + } + } + + static public void writeUnit (Unit unit, OutputStream stream) + throws IOException, TransformerException { + Document document = newDocument (); + unit.getXml (document, document); + Source source = new DOMSource (document); + Result result = new StreamResult (stream); + Transformer xformer = TransformerFactory.newInstance ().newTransformer (); + xformer.setOutputProperty (OutputKeys.INDENT, "yes"); + xformer.setOutputProperty ("{http://xml.apache.org/xslt}indent-amount", "2"); + xformer.transform (source, result); + stream.flush (); + } + + public void addUnitZip (ZipOutputStream out, Unit unit) + throws IOException, TransformerException { + if (unit == null) + return; + ZipEntry ze = new ZipEntry (unit.getSaveDir ()+"/"+unit.getFileName ()); + out.putNextEntry (ze); + ByteArrayOutputStream stream = new ByteArrayOutputStream (); + writeUnit (unit, stream); + out.write (stream.toByteArray ()); + out.closeEntry(); + out.flush (); + } + + public File getLastExport () { return Config.getFile ("LastExport"); } + + public File checkExportExtention (File file) { + if (Util.getExtention (file) != null) + return file; + return new File (file.getParentFile (), Util.changeExtention (file.getName (), lpzExtention)); + } + + public void exportFile (Unit unit, File file) { + if (file == null) + return; + try { + file = checkExportExtention (file); + HashSet> unitLinks = new HashSet> (); + TreeSet iconsLinks = new TreeSet (); + TreeSet imagesLinks = new TreeSet (); + unitLinks.add (unit); + unit.getLocalLink (new HashSet> (), unitLinks, iconsLinks, imagesLinks); + FileOutputStream fileOutputStream = new FileOutputStream (file); + ZipOutputStream out = new ZipOutputStream (fileOutputStream); + for (Unit unit2 : unitLinks) + addUnitZip (out, unit2); + // XXX prendre aussi les étiquettes dans icon/"user".lpi filté avec "^imageName^:.*" dans iconsLinks + for (String iconName : iconsLinks) + iconDB.addImageZip (out, iconName); + // XXX prendre aussi les étiquettes dans image/"user".lpi filté avec "^imageName^:.*" dans imagesLinks + for (String imageName : imagesLinks) + imageDB.addImageZip (out, imageName); + out.close(); + fileOutputStream.close (); + Config.setFile ("LastExport", file); + } catch (Exception e) { + e.printStackTrace (); + } + } + + public void importFile (File file) { + if (file == null) + return; + try { + file = checkExportExtention (file); + ArrayList> newUnit = new ArrayList> (); + byte[] tmp = new byte[1024*1024]; + FileInputStream fileInputStream = new FileInputStream (file); + ZipInputStream in = new ZipInputStream (fileInputStream); + for (;;) { + ZipEntry ze = in.getNextEntry (); + if (ze == null) + break; + ByteArrayOutputStream out = new ByteArrayOutputStream (); + for (;;) { + int nb = in.read (tmp, 0, tmp.length); + if (nb < 0) + break; + out.write (tmp, 0, nb); + } + out.flush (); + in.closeEntry (); + String[] path = ze.getName ().split ("/"); + String dirName = path[0]; + String fileName = path [1]; + String fileExtention = Util.getExtention (fileName); + ByteArrayInputStream dataIn = new ByteArrayInputStream (out.toByteArray ()); + if (!iconDB.importFile (dirName, fileName, dataIn) && + !imageDB.importFile (dirName, fileName, dataIn)) { + if (lptExtention.equals (fileExtention)) + newUnit.add (Unit.getInstanceFromStream (adecWatt, dataIn, null, UnitLocation.Zip)); + else + System.err.println ("XXX pb: "+fileName); + } + } + fileInputStream.close (); + for (Unit unit : newUnit) { + String unitId = unit.getId (); + if (isReferedUnit (unitId)) { + Unit oldUnit = idUnit.get (unitId); + forget (oldUnit); + oldUnit.replace (unit); + continue; + } + add (unit); + } + for (Unit unit : newUnit) { + unit.updateXmlParent (); + unit.story.markNotSaved (); + } + adecWatt.broadcastUpdate (AdecWatt.BroadcastUnitRoots); + Config.setFile ("LastExport", file); + } catch (Exception e) { + e.printStackTrace (); + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/PreviewCache.java b/src/java/adecWatt/model/PreviewCache.java new file mode 100644 index 0000000..4130252 --- /dev/null +++ b/src/java/adecWatt/model/PreviewCache.java @@ -0,0 +1,111 @@ +package adecWatt.model; + +import java.awt.Dimension; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileFilter; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +import misc.Util; + +public class PreviewCache { + static { + ImageIO.setUseCache (false); + } + + static public final String[] imageExtentions = { "gif", "jpg", "jpeg", "png", "tif", "tiff", "bmp" }; + static public final List imageExtentionsList = Arrays.asList (imageExtentions); + static public final FileFilter fileImageFilter = new FileFilter () { + public boolean accept (File file) { + try { + return file.isFile () && !file.isHidden () && + imageExtentionsList.contains (Util.getExtention (file).toLowerCase ()); + } catch (Exception e) { + return false; + } + } + }; + + static public int thumbSide = 40; // XXX + static public Dimension thumbDim = new Dimension (thumbSide, thumbSide); // XXX + static public final long maxSize = 1024*1024; // XXX int MAX_FILE_PREVIEW + + private File dir; + + public PreviewCache (File dir) { + this.dir = dir; + } + + private Hashtable toCleanList = new Hashtable (); + public synchronized void prepareClean () { + try { + toCleanList.clear (); + for (File file : dir.listFiles (fileImageFilter)) + toCleanList.put (file, true); + } catch (Exception e) { + } + } + public synchronized void clean () { + for (File file : toCleanList.keySet ()) + if (toCleanList.get (file)) + file.delete (); + toCleanList.clear (); + } + public synchronized void clean (String imageName) { + (new File (dir, Util.getBase (imageName)+".png")).delete (); // XXX YYY + + } + public synchronized ImageIcon getIcon (File file) { + if (file == null || (maxSize > 0 && file.length () > maxSize)) + return null; + File cacheFile = new File (dir, Util.getBase (file)+".png"); // XXX YYY + if (cacheFile.exists () && cacheFile.lastModified () > file.lastModified ()) { + toCleanList.put (cacheFile, false); + return new ImageIcon (cacheFile.getPath ()); + } + try { + BufferedImage bufferedImage = ImageIO.read (file); + if (bufferedImage == null) + return null; + int width = bufferedImage.getWidth (); + int height = bufferedImage.getHeight (); + if (width == 0 || height == 0) + return null; + Image image = null; + if (width > height) { + if (width > thumbSide) { + height = Math.max (1, (height*thumbSide)/width); + width = thumbSide; + image = bufferedImage.getScaledInstance (width, height, Image.SCALE_DEFAULT); + } + } else { + if (height > thumbSide) { + width = Math.max (1, (width*thumbSide)/height); + height = thumbSide; + image = bufferedImage.getScaledInstance (width, height, Image.SCALE_DEFAULT); + } + } + if (image != null) { + bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); + bufferedImage.createGraphics ().drawImage (image, 0, 0, null); + } + try { + dir.mkdirs (); + ImageIO.write (bufferedImage, "png", cacheFile); + toCleanList.put (cacheFile, false); + } catch (Exception e) { + e.printStackTrace (); + } + return new ImageIcon (bufferedImage); + } catch (Exception e) { + e.printStackTrace (); + return null; + } + } + +} diff --git a/src/java/adecWatt/model/Prop.java b/src/java/adecWatt/model/Prop.java new file mode 100644 index 0000000..e8d6bbb --- /dev/null +++ b/src/java/adecWatt/model/Prop.java @@ -0,0 +1,432 @@ +package adecWatt.model; + +import java.awt.geom.Point2D; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.TreeSet; +import java.util.Vector; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.DimensionDouble; +import misc.Util; + +import adecWatt.model.xml.XmlProp; + +public class Prop extends Permanent { + // ======================================== + static public PropTypeEnum toPropTypeEnum (String val) { return PropTypeEnum.valueOf (PropTypeEnum.class, Util.toCapital (val)); } + + static public final String + PropAngle = "angle", + PropBegin = "begin", + PropBlueprint = "blueprint", + PropBlueprintPos = "blueprintPos", + PropBlueprintSize = "blueprintSize", + PropBlueprintVisibility = "blueprintVisibility", + PropBuilding = "building", + PropCircuit = "circuit", + PropColor = "color", + PropConnectedOn = "connectedOn", + PropConnectedTo = "connectedTo", + PropEnd = "end", + PropIcon = "icon", + PropLabelColor = "labelColor", + PropLabelProp = "labelProp", + PropLabelSize = "labelSize", + PropLength = "length", + PropLine = "line", + PropLowIcon = "lowIcon", + PropPos = "pos", + PropPoster = "poster", + PropRot = "rot", + PropSize = "size", + PropStyle = "style", + PropTileSize = "tileSize", + PropWatt = "watt", + PropWidth = "width"; + + static public final String PropMix = "MIX"; + static public final Double DoubleMix = Double.NaN; + + static public NumberFormat numberFormat = NumberFormat.getInstance (Locale.ENGLISH); + static public NumberFormat geoFormat = NumberFormat.getInstance (Locale.ENGLISH); + static { + numberFormat.setMinimumFractionDigits (0); + numberFormat.setGroupingUsed (false); + geoFormat.setMinimumFractionDigits (6); + geoFormat.setGroupingUsed (false); + } + + // ======================================== + private PropTypeEnum type; + public Integer rank; + public String sValue; + public Collection enumChoice; + public List multiLabel; + public boolean horizontalSpin; + public Collection unknownSpin; + public int nbVal; + public Double[] values; + + // ======================================== + public Collection getModifiersSet () { return PropModifiersSet; } + public PropTypeEnum getTypeToken () { return type; } + public PropAttrEnum getNameToken () { return PropAttrEnum.Name; } + public PropAttrEnum getModifierToken () { return PropAttrEnum.Modifier; } + + public void setType (PropTypeEnum type) { + this.type = type; + switch (type) { + case Icon: + case Image: + case Enum: + case Building: + case Text: + case Article: + case City: + nbVal = 0; + break; + case Number: + nbVal = 1; + break; + case Geo: + case Square: + nbVal = 2; + break; + case Cube: + nbVal = 3; + break; + default: + System.err.println("coucou unknowed type:"+type); + break; + } + } + public String getEnumString () { + if (enumChoice == null) + return ""; + return String.join ("|", enumChoice); + } + public String getLabelString () { + if (multiLabel == null) + return ""; + return String.join ("|", multiLabel); + } + static public boolean isSValue (Prop prop) { + return prop != null && prop.sValue != null && !prop.sValue.isEmpty (); + } + + // ======================================== + public Prop (XmlProp xmlProp) { + super (xmlProp); + if (name == null) + throw new IllegalArgumentException ("Unknown XML unit has no name ("+xmlPermanent+")."); + setType (xmlProp.type); + try { + rank = new Integer (Integer.parseInt (xmlProp.getFacet (PropAttrEnum.Rank))); + } catch (Exception e) { + } + try { + unknownSpin = xmlProp.getSplitFacet (PropAttrEnum.Spin); + if (unknownSpin != null) { + if (unknownSpin.contains (Permanent.HorizontalSpin)) { + horizontalSpin = true; + unknownSpin.remove (Permanent.HorizontalSpin); + } + if (unknownSpin.contains (Permanent.NoSpin)) { + horizontalSpin = false; + unknownSpin.remove (Permanent.NoSpin); + } + if (unknownSpin.size () < 1) + unknownSpin = null; + } + enumChoice = xmlProp.getSplitFacet (PropAttrEnum.Choice); + multiLabel = xmlProp.getOrderedSplitFacet (PropAttrEnum.Multilabel); + setValue (xmlProp.getValue ()); + } catch (Exception e) { + System.err.println ("XXX: "+getTypeToken ()+":"+name+":"+sValue); + e.printStackTrace (); + } + } + + public Prop (String name, PropTypeEnum type) { + this (name, type, null, new TreeSet (), null, null); + } + + public Prop (String name, PropTypeEnum type, boolean horizontalSpin) { + this (name, type); + this.horizontalSpin = horizontalSpin; + } + + public Prop (String name, PropTypeEnum type, Integer rank, Collection modifiers, Collection enumChoice, List multiLabel) { + this.name = name; + setType (type); + if (modifiers != null && modifiers.size () > 0) + this.modifiers = modifiers; + this.rank = rank; + this.enumChoice = enumChoice; + this.multiLabel = multiLabel; + } + + public Prop clone (boolean horizontalSpin) { + Prop prop = clone (); + prop.horizontalSpin = horizontalSpin; + return prop; + } + public Prop clone (String sValue) { + Prop prop = clone (); + prop.setValue (sValue); + return prop; + } + public Prop clone () { + Prop result = new Prop (name, type); + result.importFrom (this); + return result; + } + protected void importFrom (Prop from) { + super.importFrom (from); + if (from.rank != null) + rank = from.rank; + horizontalSpin = from.horizontalSpin; + if (from.unknownSpin != null) + unknownSpin = from.unknownSpin; + if (from.enumChoice != null && from.enumChoice.size () > 0) + enumChoice = new TreeSet (from.enumChoice); + if (from.multiLabel != null && from.multiLabel.size () > 0) + multiLabel = new Vector (from.multiLabel); + sValue = from.sValue; + if (from.values != null) + values = Arrays.copyOf (from.values, from.values.length); + } + + // ======================================== + static public Comparator propComparator = + new Comparator () { + public int compare (Prop o1, Prop o2) { + if (o1 == o2) + return 0; + if (o1.rank != null && o2.rank != null) + return o1.rank - o2.rank; + if (o1.rank == null && o2.rank == null) + return o1.name.compareTo (o2.name); + return o1.rank == null ? 1 : -1; + } + }; + + static public ArrayList getOrderedProps (Collection props) { + ArrayList result = new ArrayList (props); + result.sort (propComparator); + return result; + } + + // ======================================== + @SuppressWarnings ("unchecked") + public Element getXml (Node parent, Document document) { + Element child = super.getXml (parent, document); + if (rank != null) + XmlProp.putFacet (child, PropAttrEnum.Rank, ""+rank); + TreeSet spin = horizontalSpin ? new TreeSet () : null; + if (horizontalSpin) + spin.add (Permanent.HorizontalSpin); + XmlProp.putSplitFacet (child, PropAttrEnum.Spin, spin, unknownSpin); + XmlProp.putSplitFacet (child, PropAttrEnum.Choice, enumChoice); + XmlProp.putSplitFacet (child, PropAttrEnum.Multilabel, multiLabel); + if (values != null) + // XXX devrait toujours êter synchrone + valuesChange (); + XmlProp.putValue (child, sValue); + return child; + } + public void valuesChange () { + sValue = tab2string (values, nbVal); + } + public void sValueChange () { + values = string2tab (sValue, nbVal); + } + public Prop getApplyMixProp (Prop src, Prop parent) { + if (nbVal == 0 || sValue == null || sValue == PropMix || sValue.isEmpty () ) + return this; + Double[] tmp = new Double [nbVal]; + boolean noChange = true; + for (int i = 0; i < nbVal; i++) { + if (values[i] == null) + continue; + if (values[i] == DoubleMix) { + noChange = false; + if (src == null || src.values == null || src.values [i] == null || + (parent != null && parent.values != null && src.values [i] == parent.values [i])) + continue; + tmp[i] = src.values [i]; + continue; + } + if (parent != null && values [i] == parent.values [i]) { + noChange = values [i] == null; + continue; + } + tmp [i] = values [i]; + } + boolean nullValue = true; + for (int i = 0; i < nbVal; i++) + nullValue &= values[i] == null; + if (nullValue) + return clone (null); + if (noChange) + return this; + return clone (tab2string (tmp, nbVal)); + } + public final String tab2string (Double[] values, int nbVal) { + String result = "", sep = ""; + if (values == null || nbVal < 1 || values == null) + return null; + if (values.length != nbVal) { + System.err.println ("coucou problème de métamorphose : "+values.length+" != "+nbVal+"\n"); + // XXX exception ? + } + boolean noVal = true; + NumberFormat nf = type == PropTypeEnum.Geo ? geoFormat : numberFormat; + for (Double val : values) { + result += sep; + if (val != null) { + result += nf.format (val).replace (",", "."); + noVal = false; + } + sep = "|"; + } + if (noVal) + return null; + return result; + } + static public final Double[] string2tab (String sValue, int nbVal) { + if (nbVal < 1 || sValue == null || sValue == PropMix || sValue.isEmpty ()) + return null; + String[] tmp = sValue.split ("\\|"); + if (tmp.length < 1) + return null; + if (tmp.length > nbVal) { + System.err.println ("coucou problème de métamorphose : "+tmp.length+" != "+nbVal+"\n"); + // XXX exception ? + } + Double [] values = new Double [nbVal]; + for (int i = 0; i < nbVal && i < tmp.length; i++) { + if ("?".equals (tmp[i])) { + values[i] = DoubleMix; + continue; + } + if (tmp [i] != null && !tmp [i].isEmpty ()) + values[i] = Double.parseDouble (tmp [i].replace (",", ".")); + } + return values; + } + + // ======================================== + public void setValue (String value) { + if (value == null || value.isEmpty ()) + value = null; + sValue = value; + switch (getTypeToken ()) { + case Icon: + case Image: + // XXX charger l'image ? + case Enum: + // XXX test dans l'ensemble des valeurs ? + case Building: + // XXX test dans l'ensemble des valeurs ? + case Text: + case Article: + case City: + break; + case Number: + case Geo: + case Square: + case Cube: + sValueChange (); + break; + default: + System.err.println ("coucou unknowed type:"+getTypeToken ()); + break; + } + } + + public void setThetaDegree (double thetaDegree) { + if (nbVal != 3) { + System.err.println ("coucou Prop.setThetaDegree: not cube!"); + // XXX exception ? + } + if (thetaDegree > 360 || thetaDegree < -360) + thetaDegree = thetaDegree - (((long)thetaDegree)/360)*360; + try { + values [2] = thetaDegree; + } catch (Exception e) { + values = new Double[] { null, null, thetaDegree }; // XXX + } + valuesChange (); + } + public void setAngle (double angle) { + if (nbVal != 1) { + System.err.println ("coucou Prop.setAngle: not number!"); + // XXX exception ? + } + try { + values [0] = angle; + } catch (Exception e) { + values = new Double[] { angle }; // XXX + } + valuesChange (); + } + public void setLength (double length) { + try { + values [0] = length; + } catch (Exception e) { + values = new Double[] { length }; // XXX + } + valuesChange (); + } + + // public double getLevel () { + // if (nbVal != 3) { + // System.err.println ("coucou Prop.getLevel: not cube!"); + // // XXX exception ? + // } + // return values [2]; + // } + + public void setSize (DimensionDouble size) { + if (nbVal != 3) { + System.err.println ("coucou Prop.setSize: not cube!"); + // XXX exception ? + } + try { + values [0] = size.getWidth (); + values [1] = size.getHeight (); + } catch (Exception e) { + values = new Double[]{ size.getWidth (), size.getHeight (), null }; // XXX + } + valuesChange (); + } + public void setPosition (Point2D pos) { + if (nbVal != 3) { + System.err.println ("coucou Prop.setPosition: not cube!"); + // XXX exception ? + } + try { + values [0] = pos.getX (); + values [1] = pos.getY (); + } catch (Exception e) { + values = new Double[]{ pos.getX (), pos.getY (), null }; // XXX + } + valuesChange (); + } + + // ======================================== + public String toString () { + return type+" "+name+" "+sValue+" "+rank; + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/Segm.java b/src/java/adecWatt/model/Segm.java new file mode 100644 index 0000000..731ba30 --- /dev/null +++ b/src/java/adecWatt/model/Segm.java @@ -0,0 +1,159 @@ +package adecWatt.model; + +import java.awt.BasicStroke; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Collection; +import misc.DimensionDouble; +import adecWatt.model.unit.NonWorkspace; +import adecWatt.model.unit.Workspace; +import adecWatt.model.xml.XmlSegm; + +public class Segm extends Item { + // ======================================== + public Collection getModifiersSet () { return SegmModifiersSet; } + public SegmTypeEnum getTypeToken () { return SegmTypeEnum.Segment; } + public SegmAttrEnum getNameToken () { return SegmAttrEnum.Name; } + public SegmAttrEnum getModifierToken () { return SegmAttrEnum.Modifier; } + public SegmAttrEnum getPlaceIdToken () { return SegmAttrEnum.Placeid; } + public SegmAttrEnum getModelToken () { return SegmAttrEnum.Model; } + public Workspace getStoryUnit () { return container; } + + public Segm getLink (Editable workspace) { return new Segm (name, placeId, (Workspace) workspace, model); } + + // ======================================== + public Segm (Workspace workspace, XmlSegm xmlSegm) { + super (workspace, xmlSegm); + // XXX collectEmbedded (); + } + public Segm (String name, String placeName, Workspace workspace, NonWorkspace model) { + super (name, placeName, workspace, model); + } + public Segm (Workspace workspace, NonWorkspace model) { + super (null, null, workspace, model); + } + public Segm clone (Workspace workspace) { + Segm result = new Segm (workspace, model); + result.importFrom (this); + return result; + } + + // ======================================== + public DimensionDouble getSize () { + return new DimensionDouble (getLength (), Math.max (getWidth (), getLabelSize ())); + } + public double getThetaDegree () { + return getAngle (); + } + public void changeThetaDegree (double thetaDegree) { + if (isSticky ()) + return; + getLocalProp (Prop.PropAngle, Prop.PropTypeEnum.Number).setAngle (thetaDegree); + } + public void changeSize (DimensionDouble size) { + if (isSticky ()) + return; + getLocalProp (Prop.PropLength, Prop.PropTypeEnum.Number).setLength (size.width); + } + + // ======================================== + public void print (Graphics2D printGraphics, Workspace workspace, String plugId) { + print (printGraphics, workspace, getPos (), new DimensionDouble (getLength (), getWidth ()), getAngle ()); + } + + public void print (Graphics2D printGraphics, Workspace workspace, Point2D pos, DimensionDouble size, double thetaDegree) { + double length = size.width; + float width = (float) getWidth (); // size.height; // XXX force + Paint color = getColor (); + Workspace.printLine (printGraphics, color, createStroke (getStyle (), width), pos, length, thetaDegree, + createArrowStroke (width), createEnd (getBegin (), width), createEnd (getEnd (), width)); + Workspace.printText (printGraphics, getLabel (), getLabelColor (), pos, getSize (), thetaDegree); + } + + // ======================================== + static public float [] + plain = null, + dot = {1f, 1f}, + dash = {3f, 3f}, + dashdot = {3f, 4f, 1f, 4f}, + dashdotdot = {3f, 4f, 1f, 1f, 1f, 4f}; + static public float [] createScaleStyle (float [] tab, double width) { + if (tab == null || width == 1) + return tab; + float [] result = new float [tab.length]; + for (int i = 0; i < tab.length; i++) + result[i] = (float) (tab [i]*width); + return result; + } + static public float [] createStyleStroke (String style, double width) { + try { + switch (style) { + case "dot" : return createScaleStyle (dot, width); + case "dash" : return createScaleStyle (dash, width); + case "dashdot" : return createScaleStyle (dashdot, width); + case "dashdotdot" : return createScaleStyle (dashdotdot, width); + } + } catch (Exception e) { + } + return null; + } + static public Stroke createStroke (String style, float width) { + return new BasicStroke (width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1f, createStyleStroke (style, width), 0); + } + static public Shape createEnd (String style, float width) { + try { + switch (style) { + case "arrow" : return createArrow (width); + case "dot" : return createDot (width); + case "square" : return createSquare (width); + case "stop" : return createStop (width); + } + } catch (Exception e) { + } + return null; + } + static public Stroke createArrowStroke (float width) { + return new BasicStroke (width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER); + } + static public Shape createArrow (double width) { + double barb = 4*width; + double angle = Math.toRadians (20); + Path2D.Double path = new Path2D.Double (); + + double x = -barb*Math.cos (angle); + double y = barb*Math.sin (angle); + path.moveTo (0, 0); + path.lineTo (x, y); + path.lineTo (-3*width, 0); + x = -barb*Math.cos (-angle); + y = barb*Math.sin (-angle); + path.lineTo (x, y); + path.closePath(); + return path; + } + static public Shape createStop (double width) { + double barb = 3*width; + Path2D.Double path = new Path2D.Double (); + path.moveTo (0, barb); + path.lineTo (0, -barb); + return path; + } + + static public Shape createDot (double width) { + double barb = 2*width; + return new Ellipse2D.Double (-width, -width, barb, barb); + } + + static public Shape createSquare (double width) { + double barb = 2*width; + return new Rectangle2D.Double (-width, -width, barb, barb); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/TagDB.java b/src/java/adecWatt/model/TagDB.java new file mode 100644 index 0000000..97c6b3b --- /dev/null +++ b/src/java/adecWatt/model/TagDB.java @@ -0,0 +1,310 @@ +package adecWatt.model; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Collection; +import java.util.TreeMap; +import java.util.TreeSet; + +import misc.Log; +import misc.Util; +import static misc.Config.FS; + +import static adecWatt.model.PermanentDB.backExtention; +import static adecWatt.model.PermanentDB.dataDir; +import static adecWatt.model.PermanentDB.localRemoteDir; +import static adecWatt.model.PermanentDB.localToken; +import static adecWatt.model.PermanentDB.serverToken; + +public class TagDB { + + // ======================================== + static public final String lpiExtention = "lpi"; + static public final File[] getLpiFiles (File dir) { + return dir.listFiles (new FileFilter () { + public boolean accept (File file) { + try { + return file.isFile () && !file.isHidden () && lpiExtention.equals (Util.getExtention (file).toLowerCase ()); + } catch (Exception e) { + return false; + } + } + }); + } + + // ======================================== + private TreeSet words = new TreeSet (); + private String dir; + public ImgTag imgTag = new ImgTag (); + protected ImgTag [] localRemoteTag = { + new ImgTag (), + new ImgTag () + }; + + // ======================================== + public TagDB (String dir) { + this.dir = dir; + } + public void reload () { + words.clear (); + imgTag.clear (); + try { + for (int i = 0; i < localRemoteDir.size (); i++) { + localRemoteTag [i].clear (); + File tmpDir = new File (dataDir, localRemoteDir.get (i)+FS+dir); + if (!tmpDir.isDirectory ()) + continue; + for (File file : getLpiFiles (tmpDir)) + localRemoteTag[i].readLpi (file); + } + localRemoteTag[0].clean (localRemoteTag[1]); + imgTag.merge (localRemoteTag[1]); + imgTag.merge (localRemoteTag[0]); + } catch (Exception e) { + Log.keepLastException ("ImageDB::reload", e); + } + } + + // ======================================== + public Collection getTags (String imageName) { + return imgTag.getTags (imageName); + } + + public void putTags (String imageName, Collection imageTags) { + if (!imgTag.addTags (imageName, imageTags)) + return; + try { + if ((new TreeSet (imageTags)).equals (localRemoteTag[1].getTags (imageName))) + localRemoteTag [0].addTags (imageName, null); + else + localRemoteTag [0].addTags (imageName, imageTags); + localRemoteTag [0].writeLpi (localToken, User.splitId (imageName)[0]); + } catch (Exception e) { + Log.keepLastException ("ImageDB::putTags", e); + } + } + + public void promote (Collection imageNames) { + if (imageNames == null) + return; + TreeSet ownerIds = new TreeSet (); + for (String imageName : imageNames) { + Collection imageTags = localRemoteTag [0].getTags (imageName); + if (imageTags == null) + continue; + localRemoteTag [1].addTags (imageName, imageTags); + localRemoteTag [0].addTags (imageName, null); + ownerIds.add (User.splitId (imageName)[0]); + } + for (int ownerId : ownerIds) { + localRemoteTag [1].writeLpi (serverToken, ownerId); + localRemoteTag [0].writeLpi (localToken, ownerId); + } + } + + public void renameImages (TreeMap translateMap) { + for (int i = 0; i < localRemoteDir.size (); i++) { + TreeSet ownerIds = new TreeSet (); + for (String oldImageName : translateMap.keySet ()) { + Collection imageTags = localRemoteTag [i].getTags (oldImageName); + if (imageTags == null) + continue; + String newImageName = translateMap.get (oldImageName); + localRemoteTag [i].addTags (newImageName, imageTags); + localRemoteTag [i].addTags (oldImageName, null); + ownerIds.add (User.splitId (oldImageName)[0]); + ownerIds.add (User.splitId (newImageName)[0]); + } + for (int ownerId : ownerIds) + localRemoteTag [i].writeLpi (localRemoteDir.get (i), ownerId); + } + } + + // ======================================== + public TreeSet cloneImageTags (Collection imageTags) { + TreeSet result = new TreeSet (); + for (String word : imageTags) + result.add (getWord (word)); + return result; + } + public String getWord (String word) { + if (word == null) + return null; + word = word.toLowerCase (); + String floor = words.floor (word); + if (floor != null && floor.equals (word)) + return floor; + words.add (word); + return word; + } + + // ======================================== + public class ImgTag { + // ---------------------------------------- + TreeMap>> ids = new TreeMap>> (); + + // ---------------------------------------- + public int size () { return ids.size (); } + + public void clear () { + ids.clear (); + } + + // ---------------------------------------- + public void merge (ImgTag others) { + for (int ownerId : others.ids.keySet ()) { + TreeMap> refImg = others.ids.get (ownerId); + TreeMap> idsImg = ids.get (ownerId); + if (idsImg == null) + ids.put (ownerId, idsImg = new TreeMap> ()); + for (int imageId : refImg.keySet ()) + idsImg.put (imageId, cloneImageTags (refImg.get (imageId))); + } + } + + // ---------------------------------------- + public void clean (ImgTag ref) { + for (int ownerId : ids.keySet ()) { + TreeMap> refImg = ref.get (ownerId); + if (refImg == null) + continue; + TreeMap> idsImg = ids.get (ownerId); + TreeSet imgToRemove = new TreeSet (); + for (int imageName : idsImg.keySet ()) { + TreeSet refNames = refImg.get (imageName); + if (refNames == null) + continue; + if (refNames.equals (idsImg.get (imageName))) + imgToRemove.add (imageName); + } + if (imgToRemove.size () > 0) { + for (int imageName : imgToRemove) + idsImg.remove (imageName); + writeLpi (localToken, ownerId); + } + } + } + + // ---------------------------------------- + public void addTags (String line) { + if (line == null || line.startsWith ("#") || line.isEmpty ()) + return; + int sepIdx = line.indexOf (":"); + String imageName = line.substring (0, sepIdx); + String[] arg = line.substring (sepIdx+1).split (":"); + addTags (imageName, Arrays.asList (arg)); + } + + // ---------------------------------------- + public boolean addTags (String imageName, Collection imageTags) { + int [] w = User.splitId (imageName); + int ownerId = w[0]; + int imgId = w[1]; + TreeSet oldValues = null; + try { + oldValues = ids.get (ownerId).get (imgId); + } catch (Exception e) { + } + if (imageTags == null || imageTags.size () == 0) { + if (oldValues == null || oldValues.size () == 0) + return false; + TreeMap> custumBD = ids.get (ownerId); + custumBD.remove (imgId); + if (custumBD.size () == 0) + ids.remove (ownerId); + return true; + } + if (imageTags.equals (oldValues)) + return false; + TreeMap> custumBD = ids.get (ownerId); + if (custumBD == null) + ids.put (ownerId, custumBD = new TreeMap> ()); + custumBD.put (imgId, cloneImageTags (imageTags)); + return true; + } + + // ---------------------------------------- + public TreeMap> get (int ownerId) { + try { + return ids.get (ownerId); + } catch (Exception e) { + return null; + } + } + + // ---------------------------------------- + public Collection getTags (String imageName) { + try { + int [] w = User.splitId (imageName); + return ids.get (w[0]).get (w[1]); + } catch (Exception e) { + return null; + } + } + + // ---------------------------------------- + public void readLpi (File file) { + int lineNb = 0; + String line = null; + BufferedReader in = null; + try { + in = new BufferedReader (new InputStreamReader (new FileInputStream (file))); + for (;;) { + lineNb++; + line = in.readLine (); + if (line == null) + break; + addTags (line); + } + } catch (Exception e) { + Log.keepLastException ("ImageDB::readLpi: "+file+":"+lineNb+" <"+line+">", e); + } finally { + try { + in.close (); + } catch (Exception e) { + } + } + } + + // ---------------------------------------- + public void writeLpi (String placeToken, int ownerId) { + File file = new File (dataDir, String.format ("%s%03d.%s", placeToken+FS+dir+FS, ownerId, lpiExtention)); + Util.backup (file, lpiExtention, backExtention); + TreeMap> custumBD = get (ownerId); + if (custumBD == null || custumBD.size () < 1) + return; + file.getParentFile ().mkdirs (); + file.setExecutable (false); + PrintWriter out = null; + try { + out = new PrintWriter (new FileWriter (file)); + for (int imageId : custumBD.keySet ()) { + TreeSet imageTags = custumBD.get (imageId); + if (imageTags.size () < 1) + continue; + out.print (User.getDataId (ownerId, imageId)); + for (String tag : imageTags) + out.print (":"+tag); + out.println (); + } + } catch (Exception e) { + Log.keepLastException ("ImageDB::writeLpi", e); + } finally { + try { + out.close (); + } catch (Exception e) { + } + } + } + + // ---------------------------------------- + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/Unit.java b/src/java/adecWatt/model/Unit.java new file mode 100644 index 0000000..9bb685d --- /dev/null +++ b/src/java/adecWatt/model/Unit.java @@ -0,0 +1,374 @@ +package adecWatt.model; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.TreeSet; +import javax.swing.tree.TreePath; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.Bundle; +import misc.StateNotifier; +import misc.Story; +import misc.Util; +import static misc.Config.FS; + +import adecWatt.model.xml.XmlUnit; +import adecWatt.model.unit.*; + +@SuppressWarnings ({"unchecked"}) +public abstract class Unit> + extends Editable { + + static public final String + BroadcastChangeBuilding = "ChangeBuilding", + BroadcastChangePos = "ChangePos", + BroadcastChangeRot = "ChangeRot", + BroadcastChangeRotSize = "ChangeRotSize", + BroadcastConnection = "Connection", + BroadcastNewItem = "NewItem", + BroadcastRemoveItem = "RemoveItem", + BroadcastSetSelectionItems = "SetSelectionItems", + BroadcastUpdateItem = "UpdateItem", + BroadcastUpdatePermItem = "UpdatePermItem"; + + // ======================================== + PermanentDB.UnitLocation location; + protected String id; + protected File file; + protected AdecWatt adecWatt; + protected UnitNode unitNode; + + private UnitTypeEnum type; + + public StateNotifier stateNotifier = new StateNotifier (); + public Story story = new Story (stateNotifier); + + // ======================================== + public Collection getModifiersSet () { return UnitModifiersSet; } + public UnitTypeEnum getTypeToken () { return type; } + static public UnitAttrEnum getIdToken () { return UnitAttrEnum.Id; } + public UnitAttrEnum getNameToken () { return UnitAttrEnum.Name; } + public UnitAttrEnum getModifierToken () { return UnitAttrEnum.Modifier; } + + public String getId () { return id; } + public String getFileName () { return id+"."+PermanentDB.lptExtention; } + public String getSaveDir () { return getClass ().getSimpleName ().toLowerCase (); } + public PermanentDB.UnitLocation getLocation () { return location; } + public boolean getRemote () { return location == PermanentDB.UnitLocation.Server; } + + public AdecWatt getAdecWatt () { return adecWatt; } + public Unit getUnitRoot () { return ((UnitNode) unitNode.getRoot ()).getUnit (); } + public UnitNode getUnitNode () { return unitNode; } + public Unit getDirectUnit () { return this; } + public Unit getParentUnit () { return getParent (); } + public Unit getStoryUnit () { return this; } + public Editable getModel () { return null; } + + // ======================================== + public Unit getParent () { + UnitNode parentNode = (UnitNode) unitNode.getParent (); + return parentNode == null ? null : parentNode.getUnit (); + } + + // public boolean hasChild (String childName) { + // for (Enumeration e = unitNode.children (); e.hasMoreElements (); ) + // if (((UnitNode) e.nextElement ()).getUnit ().getName ().equals (childName)) + // return true; + // return false; + // } + + public ArrayList> getChildren () { + ArrayList> result = new ArrayList> (); + for (Enumeration e = unitNode.children (); e.hasMoreElements (); ) + result.add (((UnitNode) e.nextElement ()).getUnit ()); + return result; + } + + public boolean isDescendingFrom (String unitId) { + if (unitId == null || unitId.isEmpty ()) + return false; + for (Unit current = this; ; ) { + if (unitId.equals (current.getId ())) + return true; + UnitNode parent = (UnitNode) current.unitNode.getParent (); + if (parent == null) + return false; + current = parent.getUnit (); + } + } + + public ArrayList> getAvailablePermanents (boolean isEmbedded, Editable editable) { + ArrayList> result = new ArrayList> (); + for (Enumeration e = ((UnitNode) unitNode.getRoot ()).breadthFirstEnumeration (); e.hasMoreElements (); ) { + Unit unit = ((UnitNode) e.nextElement ()).getUnit (); + if (isEmbedded) { + if (unit.isUncompleted (editable)) + continue; + } else { + if (unit.getUnitNode ().isNodeAncestor (unitNode) || unit == editable) + continue; + } + result.add (unit); + } + return result; + } + + public boolean isUncompleted (Editable editable) { + for (String propName : getOrderedPropsName ()) { + if (!Permanent.isModifier (Permanent.Mandatory, getPropModifiers (propName))) + continue; + if (getPropVal (propName) != null) + continue; + if (editable == null) + return true; + Prop prop = editable.getOwnProp (propName); + if (prop != null && prop.sValue != null) + continue; + return true; + } + return false; + } + + // ======================================== + static final Unit getInstanceFromStream (AdecWatt adecWatt, InputStream dataIn, File file, PermanentDB.UnitLocation location) { + XmlUnit xmlUnit = PermanentDB.readXmlUnit (dataIn); + String id = xmlUnit.getFacet (getIdToken ()); + adecWatt.getUser ().updateDataId (id); + Unit result = getInstance (adecWatt, xmlUnit.type, id); + result.location = location; + result.file = file; + result.initXml (xmlUnit); + return result; + } + public void getCopy (String name) { + if (getParent () == null) + return; + Unit result = (Unit) getInstance (adecWatt, xmlPermanent.type, null); + result.name = name; + result.importFrom (this); + adecWatt.getPermanentDB ().add (result); + adecWatt.broadcastDisplay (AdecWatt.BroadcastUpdateUnitTree, result.getParent ()); + } + public void getNewChild (String name) { + Unit result = (Unit) getInstance (adecWatt, type, null); + result.initChild (this, name); + adecWatt.getPermanentDB ().add (result); + updateTree (); + } + + private static final Unit getInstance (AdecWatt adecWatt, UnitTypeEnum type, String id) { + switch (type) { + case Furniture: + return new Furniture (adecWatt, id); + case Information: + return new Information (adecWatt, id); + case Line: + return new Line (adecWatt, id); + case Accessory: + return new Accessory (adecWatt, id); + case Building: + return new Building (adecWatt, id); + case Lightplot: + return new Lightplot (adecWatt, id); + } + throw new IllegalArgumentException ("Can't find constructor for type ("+type+")."); + } + + // ======================================== + protected Unit (AdecWatt adecWatt, String id) { + this.adecWatt = adecWatt; + if (id == null) + id = adecWatt.getUser ().getDataId (); + this.id = id; + unitNode = new UnitNode (this); + Bundle.addBundleObserver (this); + } + + protected void initXml (XmlUnit xmlUnit) { + super.initXml (xmlUnit); + if (name == null) + // XXX c'est plus un gros problème + throw new IllegalArgumentException ("Unknown XML unit has no name ("+xmlPermanent+")."); + type = xmlUnit.type; + } + protected void importFrom (Unit from) { + super.importFrom (from); + location = PermanentDB.UnitLocation.Local; + type = from.type; + story.markNotSaved (); + Unit parent = from.getParent (); + if (parent != null) + parent.unitNode.add (unitNode); + } + protected void initChild (Unit unit, String name) { + location = PermanentDB.UnitLocation.Local; + type = unit.type; + modifiers = unit.modifiers == null || unit.modifiers.size () < 1 ? null : new TreeSet (unit.modifiers); + this.name = name; + story.markNotSaved (); + unit.unitNode.add (unitNode); + } + + public void updateXmlParent () { + if (getParent () != null) + return; + String parentId = xmlPermanent.getFacet (UnitAttrEnum.Parent); + if (parentId == null) { + adecWatt.getPermanentDB ().namedRoots.put (getName (), this); + return; + } + Unit parent = adecWatt.getPermanentDB ().getUnitById (parentId); + if (parent == null) { + System.err.println ("XXX Unit:updateXmlParent: "+parentId+" not loaded !"); + return; + } + parent.unitNode.add (unitNode); + collectEmbedded (); + } + + // ======================================== + public TreePath getPath () { + ArrayList> path = new ArrayList> (); + for (Unit unit = this; unit != null; unit = unit.getParent ()) + path.add (0, unit.unitNode); + return new TreePath (path.toArray ()); + } + + public ArrayList> search (String text) { + ArrayList> result = new ArrayList> (); + for (Enumeration e = ((UnitNode) unitNode.getRoot ()).breadthFirstEnumeration (); e.hasMoreElements (); ) { + Unit unit = ((UnitNode) e.nextElement ()).getUnit (); + if (unit.match (text)) + result.add (unit); + } + return result; + } + + // ======================================== + public void enableStory () { + stateNotifier.addUpdateObserver (adecWatt, AdecWatt.BroadcastStory); + } + public void disableStory () { + stateNotifier.removeObserver (adecWatt); + } + public void replace (Unit newUnit) { + Unit parent = getParent (); + adecWatt.getPermanentDB ().add (newUnit); + if (parent != null) + parent.unitNode.remove (unitNode); + for (Unit child : getChildren ()) + newUnit.unitNode.add (child.unitNode); + adecWatt.broadcastDisplay (AdecWatt.BroadcastUnitStory, newUnit); + } + public void findPromote (HashSet> unitLinks, TreeSet iconsLinks, TreeSet imagesLinks) { + unitLinks.add (this); + getLocalLink (new HashSet> (), unitLinks, iconsLinks, imagesLinks); + } + public void changeId (String newId) { + id = newId; + story.markNotSaved (); + } + + public void remove () { + PermanentDB permanentDB = adecWatt.getPermanentDB (); + Unit newUnit = null; + Unit parent = getParent (); + switch (location) { + case Server: + return; + case Local: + permanentDB.remove (this); + break; + case Zip: + permanentDB.forget (this); + break; + } + newUnit = permanentDB.reload (this); + if (newUnit != null) { + replace (newUnit); + newUnit.updateXmlParent (); + if (parent != null) + adecWatt.broadcastDisplay (AdecWatt.BroadcastUpdateUnitTree, parent); + else + adecWatt.broadcastUpdate (AdecWatt.BroadcastUnitRoots); + updateView (); + return; + } + parent.unitNode.remove (unitNode); + adecWatt.broadcastDisplay (AdecWatt.BroadcastUpdateUnitTree, parent); + } + + // ======================================== + public void updateBundle () { + //XXX setUserObject (getLocalName ()); + } + + // ======================================== + public void getLocalLink (HashSet> visited, HashSet> unitLinks, TreeSet iconsLinks, TreeSet imagesLinks) { + if (visited.contains (this)) + return; + super.getLocalLink (visited, unitLinks, iconsLinks, imagesLinks); + if (!getRemote () || story.isModified ()) + unitLinks.add (this); + Unit parent = getParent (); + if (parent == null) + return; + parent.getLocalLink (visited, unitLinks, iconsLinks, imagesLinks); + } + + public void save () { + File file = PermanentDB.getLocalFile (getSaveDir ()+FS+getFileName ()); + PermanentDB.writeUnit (this, file); + location = PermanentDB.UnitLocation.Local; + this.file = file; + story.markSaved (); + } + + public void promote () { + String fileName = getSaveDir ()+FS+getFileName (); + Util.backup (PermanentDB.getLocalFile (fileName), PermanentDB.lptExtention, PermanentDB.backExtention); + File remotefile = PermanentDB.getRemoteFile (fileName); + PermanentDB.writeUnit (this, remotefile); + this.file = remotefile; + location = PermanentDB.UnitLocation.Server; + story.markSaved (); + } + + public Element getXml (Node parentXml, Document document) { + Element child = super.getXml (parentXml, document); + XmlUnit.putFacet (child, UnitAttrEnum.Id, id); + Unit parent = getParent (); + if (parent != null) + XmlUnit.putFacet (child, UnitAttrEnum.Parent, parent.id); + return child; + } + + // ======================================== + public void setParentUnit (Unit parent) { + UnitNode oldParentNode = (UnitNode) unitNode.getParent (); + if (oldParentNode == null || parent == null || oldParentNode == parent.unitNode) + return; + oldParentNode.remove (unitNode); + ((Unit)parent).unitNode.add (unitNode); + } + public void updateTree () { + adecWatt.broadcastDisplay (AdecWatt.BroadcastUpdateUnitTree, this); + } + public void storyChange (Story.Commands commands, ArrayList changeProps) { + storyChange (commands, false, ownProps, changeProps); + } + public void storyTransform (Story.Commands commands, Collection modifiers, Unit parent, String newName, ArrayList transProps) { + storyTransform (commands, newName, modifiers, parent, ownProps, transProps); + } + public String toString () { + return getLocalName (); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/UnitNode.java b/src/java/adecWatt/model/UnitNode.java new file mode 100644 index 0000000..bbf858b --- /dev/null +++ b/src/java/adecWatt/model/UnitNode.java @@ -0,0 +1,54 @@ +package adecWatt.model; + +import java.util.Collections; +import java.util.Comparator; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; + +@SuppressWarnings ("serial") public class UnitNode> extends DefaultMutableTreeNode { + // ======================================== + public UnitNode (Unit unit) { + super (unit); + } + + @SuppressWarnings ("unchecked") + public Unit getUnit () { + return (Unit) getUserObject (); + } + + // ======================================== + @SuppressWarnings("unchecked") + public void insert (MutableTreeNode newChild, int childIndex) { + if (children == null) { + super.insert (newChild, childIndex); + return; + } + int index = Collections.binarySearch (children, newChild, nodeComparator); + if (index < 0) + super.insert (newChild, -index-1); + } + protected Comparator nodeComparator = + new Comparator () { + @Override public int compare (TreeNode o1, TreeNode o2) { + int result = o1.toString ().compareToIgnoreCase (o2.toString()); + if (result != 0) + return result; + // XXX + return ((UnitNode) o1).getUnit ().getId ().compareToIgnoreCase (((UnitNode) o2).getUnit ().getId ().toString()); + } + @Override + public boolean equals (Object obj) { + return false; + } + @Override public int hashCode() { + int hash = 7; + return hash; + } + }; + // ======================================== + public String toString () { + return getUnit ().getLocalName (); + } + // ======================================== +} diff --git a/src/java/adecWatt/model/User.java b/src/java/adecWatt/model/User.java new file mode 100644 index 0000000..eb148cd --- /dev/null +++ b/src/java/adecWatt/model/User.java @@ -0,0 +1,187 @@ +package adecWatt.model; + +import java.util.HashSet; +import java.util.Hashtable; + +import misc.Config; +import misc.StateNotifier; +import misc.Util; + +public class User extends StateNotifier { + + // ======================================== + static public final int serverId = 0; + static public final int visitorId = 1; + static public final String + BroadcastUserChangeProfil = "UserChangeProfil"; + + static public enum Role { + // import/export/print + Visitor, // afficher + StageManager, // créer/modifier/organiser des plans de feu + Architect, // créer/modifier/organiser des leux/salles + FurnitureManager, // créer/modifier/organiser des mobilier accessoires et des informations + Linguist, // traduction des formulaires (tout voir avec affiche) + DataStructuresManager, // ajout de champs et métamorphose + DataManager, // transfert sur le serveur + Yoda; // depasé les bornes, il n'y a plus de limite + } + + // ======================================== + public boolean connected = false; + private String login, password; + private int currentId; + private int userId; + private Hashtable maxIds = new Hashtable<> (); + private HashSet roles = new HashSet (); + + static public int updateRoles (HashSet roles, String rolesLine) { + roles.clear (); + roles.add (Role.Visitor); + try { + String[] tokens = rolesLine.split ("\\|"); + String id = tokens [0]; + tokens = tokens[1].split (","); + for (String token : tokens) + try { + roles.add (Role.valueOf (Role.class, token)); + } catch (Exception e) { + e.printStackTrace (); + } + return Integer.parseInt (id); + } catch (Exception e) { + return visitorId; + } + } + public HashSet getRoles () { return new HashSet (roles); } + public String getLogin () { return login; } + public String getPassword () { return password; } + public int getUserId () { return userId; } + public boolean isVisitorId () { return userId == 1; } + + // ======================================== + public boolean hasRole (Role... someRoles) { + for (Role role : someRoles) + if (roles.contains (role)) + return true; + return false; + } + public boolean isAdmin () { return hasRole (Role.Yoda); } + public boolean isLinguist () { return hasRole (Role.Linguist) || isAdmin (); } + public boolean isDataStructuresManager () { return hasRole (Role.DataStructuresManager) || isAdmin (); } + public boolean isDataManager () { return hasRole (Role.DataManager) || isAdmin (); } + public boolean isEditor () { + return + hasRole (Role.StageManager) || + hasRole (Role.Architect) || + hasRole (Role.FurnitureManager) || isAdmin (); + } + public boolean isEditor (Unit unit) { + try { + if (isAdmin ()) + return true; + switch (Permanent.UnitTypeEnum.valueOf (Permanent.UnitTypeEnum.class, Util.toCapital (unit.getUnitRoot ().getName ()))) { + case Lightplot: + return hasRole (Role.StageManager); + case Furniture: + case Information: + case Line: + case Accessory: + return hasRole (Role.FurnitureManager); + case Building: + return hasRole (Role.Architect); + } + } catch (Exception e) { + } + return false; + } + + // ======================================== + private void getConfig (Role role) { + if (Config.getBoolean ("Role"+role, false)) + roles.add (role); + } + private void setConfig (Role role) { + Config.setBoolean ("Role"+role, roles.contains (role)); + } + + // ======================================== + public User () { + currentId = userId = Config.getInt ("UserId", visitorId); + login = Config.getString ("Login", ""); + roles.add (Role.Visitor); + getConfig (Role.StageManager); + getConfig (Role.Architect); + getConfig (Role.FurnitureManager); + } + + // ======================================== + public void setLogin (String login) { + Config.setString ("Login", this.login = login); + } + public void setPassword (String password) { + this.password = password; + } + + // ======================================== + public void setRoles (HashSet roles) { + this.roles = new HashSet (roles); + this.roles.add (Role.Visitor); + currentId = isDataManager () ? serverId : userId; + setConfig (Role.StageManager); + setConfig (Role.Architect); + setConfig (Role.FurnitureManager); + broadcastUpdate (BroadcastUserChangeProfil); + } + public void setUserId (int userId) { + this.userId = userId; + Config.setInt ("UserId", userId); + currentId = isDataManager () ? serverId : userId; + } + + // ======================================== + static public String getDataId (int ownerId, int serialId) { + return String.format ("%03d-%04d", ownerId, serialId); + } + static public int[] splitId (String id) { + try { + if (id == null) + return null; + int sepIdx = id.indexOf ("-"); + int ownerId = Integer.parseInt (id.substring (0, sepIdx)); + int extIdx = id.indexOf (".", sepIdx); + int value = Integer.parseInt (extIdx > 0 ? id.substring (sepIdx+1, extIdx) : id.substring (sepIdx+1)); + return new int [] {ownerId, value}; + } catch (Exception e) { + } + return null; + } + + // ======================================== + public String getDataId () { + int maxId = 0; + try { + maxId = maxIds.get (currentId); + } catch (Exception e) { + } + maxId++; + maxIds.put (currentId, maxId); + return getDataId (currentId, maxId); + } + public void updateDataId (String id) { + int [] ids = splitId (id); + if (ids == null) + return; + int ownerId = ids[0]; + int value = ids[1]; + int maxId = 0; + try { + maxId = maxIds.get (ownerId); + } catch (Exception e) { + } + if (value > maxId) + maxIds.put (ownerId, value); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/compile b/src/java/adecWatt/model/compile new file mode 100644 index 0000000..001fd23 --- /dev/null +++ b/src/java/adecWatt/model/compile @@ -0,0 +1,782 @@ +-*- mode: compilation; default-directory: "~/perso/adecWatt56/src/java/adecWatt/model/" -*- +Compilation started at Sun Feb 4 19:00:19 + +ant -emacs -f /home/felix/perso/adecWatt56/ant/build.xml run +Buildfile: /home/felix/perso/adecWatt56/ant/build.xml + +init: +Created dir: /home/felix/perso/adecWatt56/build/api +Created dir: /home/felix/perso/adecWatt56/build/class +Created dir: /home/felix/perso/adecWatt56/data/log +Copying 31 files to /home/felix/perso/adecWatt56/build/class/data/config + +compile: +Compiling 94 source files to /home/felix/perso/adecWatt56/build/class +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:359: warning: [rawtypes] found raw type: Item + Vector clip = new Vector (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:359: warning: [rawtypes] found raw type: Item + Vector clip = new Vector (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:435: warning: [rawtypes] found raw type: Item + Vector items = jWorkspaceView.getSelectedItems (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:449: warning: [rawtypes] found raw type: Item + Vector items = jWorkspaceView.getSelectedItems (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:634: warning: [rawtypes] found raw type: Item + List selectedItems = (List) objects[1]; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:634: warning: [rawtypes] found raw type: Item + List selectedItems = (List) objects[1]; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:644: warning: [rawtypes] found raw type: Item + List selectedItems = (List) objects[1]; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:644: warning: [rawtypes] found raw type: Item + List selectedItems = (List) objects[1]; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:651: warning: [rawtypes] found raw type: Item + List selectedItems = (List) objects[1]; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:651: warning: [rawtypes] found raw type: Item + List selectedItems = (List) objects[1]; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/control/AdecWattManager.java:657: warning: [rawtypes] found raw type: Item + jAdecWatt.getJWorkspace ((Workspace) objects[0]).setSelectedItems ((List) objects[1]); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:68: warning: [rawtypes] found raw type: Item + ArrayList items = new ArrayList (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:68: warning: [rawtypes] found raw type: Item + ArrayList items = new ArrayList (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:73: warning: [rawtypes] found raw type: Item + for (Item item : items) + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:85: warning: [rawtypes] found raw type: Item + public void updateSelection (List items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:90: warning: [rawtypes] found raw type: Item + public Story.Command getDoSelection (Item item) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:93: warning: [rawtypes] found raw type: Item + public Story.Command getDoSelection (List items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:99: warning: [rawtypes] found raw type: Item + public Story.Command getUndoSelection (Item item) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:102: warning: [rawtypes] found raw type: Item + public Story.Command getUndoSelection (List items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:122: warning: [rawtypes] found raw type: Item + public void storyAddItem (Item item, Point2D.Double pos) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:125: warning: [rawtypes] found raw type: Item + commands.add (getUndoSelection ((List) null)); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:130: warning: [rawtypes] found raw type: Item + public void storyCloneItem (Item ref, Point2D.Double pos) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:133: warning: [rawtypes] found raw type: Item + Item item = ref.clone (this); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:141: warning: [rawtypes] found raw type: Item + public void storyPasteItem (Vector sItem) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:144: warning: [rawtypes] found raw type: Item + Vector preSelection = new Vector (sItem.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:144: warning: [rawtypes] found raw type: Item + Vector preSelection = new Vector (sItem.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:145: warning: [rawtypes] found raw type: Item + for (Item ref : sItem) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:154: warning: [rawtypes] found raw type: Item + Vector postSelection = new Vector (preSelection.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:154: warning: [rawtypes] found raw type: Item + Vector postSelection = new Vector (preSelection.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:156: warning: [rawtypes] found raw type: Item + for (Item ref : preSelection) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:157: warning: [rawtypes] found raw type: Item + Item item = ref.clone (this); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:168: warning: [rawtypes] found raw type: Item + public Item storyGetCloseItem (Story.Commands commands, Item item) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:168: warning: [rawtypes] found raw type: Item + public Item storyGetCloseItem (Story.Commands commands, Item item) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:169: warning: [rawtypes] found raw type: Item + Item closeItem = getLocalEmbedded (item.getId ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:176: warning: [rawtypes] found raw type: Item + public void storyHideShowItem (List sItem, boolean hidden) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:180: warning: [rawtypes] found raw type: Item + Vector toHideShow = new Vector (sItem.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:180: warning: [rawtypes] found raw type: Item + Vector toHideShow = new Vector (sItem.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:181: warning: [rawtypes] found raw type: Item + for (Item ref : sItem) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:189: warning: [rawtypes] found raw type: Item + for (Item item : toHideShow) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:196: warning: [rawtypes] found raw type: Item + commands.add (getDoSelection ((List) null)); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:199: warning: [rawtypes] found raw type: Item + public void storyRemoveItems (List sItem) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:202: warning: [rawtypes] found raw type: Item + Vector toRemove = new Vector (sItem.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:202: warning: [rawtypes] found raw type: Item + Vector toRemove = new Vector (sItem.size ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:203: warning: [rawtypes] found raw type: Item + for (Item ref : sItem) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:204: warning: [rawtypes] found raw type: Item + Item localItem = getLocalEmbedded (ref.getId ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:213: warning: [rawtypes] found raw type: Item + for (Item item : toRemove) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:221: warning: [rawtypes] found raw type: Item + commands.add (getDoSelection ((List) null)); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:224: warning: [rawtypes] found raw type: Item + public Acc storyGetCloseAcc (Story.Commands commands, Item item, Accessory accessory) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:225: warning: [unchecked] unchecked call to findEmbeddedRootOf(Unit) as a member of the raw type Editable + Acc acc = (Acc) item.findEmbeddedRootOf (accessory); + ^ + where E is a type-variable: + E extends Embedded declared in class Editable +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:231: warning: [unchecked] unchecked call to getCloseEmbedded(E) as a member of the raw type Editable + closeAcc = (Acc) item.getCloseEmbedded (acc); + ^ + where E is a type-variable: + E extends Embedded declared in class Editable +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:235: warning: [rawtypes] found raw type: Item + public void storyAddAcc (Item item, Accessory accessory) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:237: warning: [rawtypes] found raw type: Item + Item localItem = storyGetCloseItem (commands, item); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:257: warning: [rawtypes] found raw type: Item + Item localItem = getLocalEmbedded (acc.getContainer ().getId ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:264: warning: [unchecked] unchecked call to removeEmbedded(E) as a member of the raw type Editable + public void exec () { localItem.removeEmbedded (oldAcc); } + ^ + where E is a type-variable: + E extends Embedded declared in class Editable +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:265: warning: [unchecked] unchecked call to addEmbedded(E) as a member of the raw type Editable + public void undo () { localItem.addEmbedded (oldAcc); } + ^ + where E is a type-variable: + E extends Embedded declared in class Editable +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:305: warning: [rawtypes] found raw type: Item + public void storyRotItem (Vector sItem, Vector thetas) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:310: warning: [rawtypes] found raw type: Item + Item item = sItem.get (i); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:315: warning: [rawtypes] found raw type: Item + Item localItem = storyGetCloseItem (commands, item); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:321: warning: [static] static method should be qualified by type name, Item, instead of by an expression + localItem.changePos (item.getPosInside (size, pos, item.getThetaDegree (), item.getSize ())); + ^ +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:338: warning: [rawtypes] found raw type: Item + public void storyMoveItem (Vector sItem, Vector poss) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:343: warning: [rawtypes] found raw type: Item + Item item = sItem.get (i); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:344: warning: [static] static method should be qualified by type name, Item, instead of by an expression + Point2D.Double insidePos = item.getPosInside (size, poss.get (i), item.getThetaDegree (), item.getSize ()); + ^ +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:350: warning: [rawtypes] found raw type: Item + Item localItem = storyGetCloseItem (commands, item); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:359: warning: [rawtypes] found raw type: Item + public void storyRotResize (Item sItem, Point2D.Double sPos, double sThetaDegree, DimensionDouble sSize) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:361: warning: [rawtypes] found raw type: Item + Item localItem = storyGetCloseItem (commands, sItem); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:366: warning: [static] static method should be qualified by type name, Item, instead of by an expression + Point2D.Double insidePos = localItem.getPosInside (size, sPos, sThetaDegree, sSize); + ^ +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:376: warning: [rawtypes] found raw type: Item + public void storySpaceItem (Vector items, boolean isHorizontal, Double spaceRequest) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:392: warning: [rawtypes] found raw type: Item + public void storyDistributeItem (Vector items, boolean isHorizontal, Double distribRequest) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:413: warning: [rawtypes] found raw type: Item + public void storyAlignItem (Vector items, Alignment alignment) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:427: warning: [rawtypes] found raw type: Item + for (Item item : items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:429: warning: [static] static method should be qualified by type name, Item, instead of by an expression + DimensionDouble size = item.getRotSize (item.getThetaDegree (), item.getSize ()); + ^ +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:459: warning: [rawtypes] found raw type: Item + for (Item item : items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:461: warning: [static] static method should be qualified by type name, Item, instead of by an expression + DimensionDouble size = item.getRotSize (item.getThetaDegree (), item.getSize ()); + ^ +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:485: warning: [rawtypes] found raw type: Item + public double[][] getAxesValues (Vector items, boolean isHorizontal) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:489: warning: [rawtypes] found raw type: Item + for (Item item : items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:491: warning: [static] static method should be qualified by type name, Item, instead of by an expression + DimensionDouble size = item.getRotSize (item.getThetaDegree (), item.getSize ()); + ^ +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:503: warning: [rawtypes] found raw type: Item + public Vector getPos (Vector items, boolean isHorizontal, double[] poss) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:506: warning: [rawtypes] found raw type: Item + for (Item item : items) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:549: warning: [rawtypes] found raw type: Item + protected Hashtable namedItems = new Hashtable (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:549: warning: [rawtypes] found raw type: Item + protected Hashtable namedItems = new Hashtable (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:550: warning: [rawtypes] found raw type: Item + protected Vector allItems; + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:552: warning: [rawtypes] found raw type: Item + public Vector getAllItems () { return allItems; } + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:564: warning: [rawtypes] found raw type: Item + for (Item item : getInheritedEmbeddedValues ()) + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:570: warning: [rawtypes] found raw type: Item + for (Item item : buildingItems) + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:573: warning: [rawtypes] found raw type: Item + allItems = new Vector (namedItems.values ()); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:575: warning: [rawtypes] found raw type: Item + Vector itemsUsed = new Vector (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:575: warning: [rawtypes] found raw type: Item + Vector itemsUsed = new Vector (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:576: warning: [rawtypes] found raw type: Item + for (Item item : allItems) + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:577: warning: [unchecked] unchecked cast + for (String accId : (TreeSet) item.getEmbeddedIds ()) + ^ + required: TreeSet + found: TreeSet +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:583: warning: [rawtypes] found raw type: Item + for (Item item : allItems) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:650: warning: [rawtypes] found raw type: Item + public ArrayList findItems (Point2D.Double realPos, double close) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:651: warning: [rawtypes] found raw type: Item + ArrayList result = new ArrayList (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:651: warning: [rawtypes] found raw type: Item + ArrayList result = new ArrayList (); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/unit/Workspace.java:653: warning: [rawtypes] found raw type: Item + for (Item item : namedItems.values ()) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/Item.java:48: warning: [rawtypes] found raw type: Item + abstract public Item clone (Workspace workspace); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/Item.java:245: warning: [rawtypes] found raw type: Item + static public Comparator xPosComparator = new AxeItemComparator (0, 1, 2); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/Item.java:246: warning: [rawtypes] found raw type: Item + static public Comparator yPosComparator = new AxeItemComparator (1, 0, 2); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/Item.java:247: warning: [rawtypes] found raw type: Item + static public Comparator zPosComparator = new AxeItemComparator (2, 0, 1); + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/Item.java:249: warning: [rawtypes] found raw type: Item + static class AxeItemComparator implements Comparator { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +/home/felix/perso/adecWatt56/src/java/adecWatt/model/Item.java:256: warning: [rawtypes] found raw type: Item + public int compare (Item o1, Item o2) { + ^ + missing type arguments for generic class Item + where P,T,A are type-variables: + P extends XmlPermanent declared in class Item + T extends Enum declared in class Item + A extends Enum declared in class Item +Note: Some input files additionally use unchecked or unsafe operations. +100 warnings +Creating empty /home/felix/perso/adecWatt56/build/class/adecWatt/model/package-info.class +Creating empty /home/felix/perso/adecWatt56/build/class/adecWatt/view/jProp/package-info.class +Creating empty /home/felix/perso/adecWatt56/build/class/adecWatt/view/package-info.class +Creating empty /home/felix/perso/adecWatt56/build/class/adecWatt/model/xml/package-info.class + +run: + +BUILD SUCCESSFUL +Total time: 75 minutes 48 seconds + +Compilation finished at Sun Feb 4 20:16:08 diff --git a/src/java/adecWatt/model/package-info.java b/src/java/adecWatt/model/package-info.java new file mode 100644 index 0000000..fad6358 --- /dev/null +++ b/src/java/adecWatt/model/package-info.java @@ -0,0 +1,27 @@ +/** + * Architecture des classes + * + * AdecWatt = appli + * PermanentDB + * UnitNode + * + * Permanent + * Prop (property) + * Editable : prop[] (Container) + * Embedded + * Item (contient des accessoires) + * Segm : information avec 2 extrémintés + * Comp : NonWorkspace (container d'Acc) + * Acc : Comp + * Unit + * NonWorkspace (container d'Acc) + * Accessory + * Furniture + * Line + * Information + * Workspace : comp[] (container de comp) + * Building + * Lightplot : Building + * + */ +package adecWatt.model; diff --git a/src/java/adecWatt/model/unit/Accessory.java b/src/java/adecWatt/model/unit/Accessory.java new file mode 100644 index 0000000..7fafae3 --- /dev/null +++ b/src/java/adecWatt/model/unit/Accessory.java @@ -0,0 +1,10 @@ +package adecWatt.model.unit; + +import adecWatt.model.AdecWatt; + +public class Accessory extends NonWorkspace { + + public Accessory (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } +} diff --git a/src/java/adecWatt/model/unit/Building.java b/src/java/adecWatt/model/unit/Building.java new file mode 100644 index 0000000..5219607 --- /dev/null +++ b/src/java/adecWatt/model/unit/Building.java @@ -0,0 +1,28 @@ +package adecWatt.model.unit; + +import java.util.Enumeration; + +import adecWatt.model.AdecWatt; +import adecWatt.model.UnitNode; + +public class Building extends Workspace { + + // ======================================== + static public final String[] workspacesRoot = { "lightplot" }; + + public Building (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } + + // ======================================== + public void updateView () { + super.updateView (); + for (String workspaceRoot : workspacesRoot) + for (Enumeration enumUnitNode = adecWatt.getPermanentDB ().getRootByName (workspaceRoot).getUnitNode ().breadthFirstEnumeration (); + enumUnitNode.hasMoreElements (); + ) + adecWatt.broadcastDisplay (AdecWatt.BroadcastUpdateWorkspace, (Lightplot) ((UnitNode) enumUnitNode.nextElement ()).getUnit ()); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/unit/Furniture.java b/src/java/adecWatt/model/unit/Furniture.java new file mode 100644 index 0000000..ea0e6fa --- /dev/null +++ b/src/java/adecWatt/model/unit/Furniture.java @@ -0,0 +1,10 @@ +package adecWatt.model.unit; + +import adecWatt.model.AdecWatt; + +public class Furniture extends NonWorkspace { + + public Furniture (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } +} diff --git a/src/java/adecWatt/model/unit/Information.java b/src/java/adecWatt/model/unit/Information.java new file mode 100644 index 0000000..418dcd3 --- /dev/null +++ b/src/java/adecWatt/model/unit/Information.java @@ -0,0 +1,10 @@ +package adecWatt.model.unit; + +import adecWatt.model.AdecWatt; + +public class Information extends NonWorkspace { + + public Information (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } +} diff --git a/src/java/adecWatt/model/unit/Lightplot.java b/src/java/adecWatt/model/unit/Lightplot.java new file mode 100644 index 0000000..830fbf7 --- /dev/null +++ b/src/java/adecWatt/model/unit/Lightplot.java @@ -0,0 +1,75 @@ +package adecWatt.model.unit; + +import java.awt.geom.Point2D; +import java.util.Collection; +import java.util.Hashtable; + +import misc.DimensionDouble; +import misc.ScaledImage; + +import adecWatt.model.AdecWatt; +import adecWatt.model.Item; +import adecWatt.model.Prop; + +@SuppressWarnings ("serial") +public class Lightplot extends Workspace { + + // ======================================== + public Building getPattern () { return getBuilding (); } + public DimensionDouble getRealSize () { return getBuilding ().getSize (); } + public ScaledImage getBlueprint () { return getBuilding ().getBlueprint (); } + public DimensionDouble getBlueprintSize () { return getBuilding ().getBlueprintSize (); } + public Point2D.Double getBlueprintPos () { return getBuilding ().getBlueprintPos (); } + public Double getBlueprintVisibility () { return getBuilding ().getBlueprintVisibility (); } + + public Lightplot (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } + + // ======================================== + public void storyChangeBuilding (final Building building) { + final Building oldBuilding = getBuilding (); + if (oldBuilding == building) + return; + final Hashtable oldPos = getOutsideItem (building); + final Hashtable newPos = getMoveInsideItem (building, oldPos); + story.add (story.new Command (StoryChangeBuilding) { + public void exec () { moveItem (newPos); changeBuilding (building); } + public void undo () { changeBuilding (oldBuilding); moveItem (oldPos); } + public void display () { + stateNotifier.broadcastUpdate (BroadcastChangeBuilding); + stateNotifier.broadcastDisplay (BroadcastChangePos, oldPos.keySet ().toArray ()); + } + }); + } + + // ======================================== + private void changeBuilding (Building building) { + // XXX localProp ? + getProp (Prop.PropBuilding).setValue (building.getId ()); + } + private void moveItem (Hashtable items) { + for (Item item : items.keySet ()) + item.changePos (items.get (item)); + } + + // ======================================== + public Hashtable getOutsideItem (Building building) { + Hashtable result = new Hashtable (); + DimensionDouble size = building.getRealSize (); + for (Item item : getInheritedEmbeddedValues ()) + if (item.isPosOutside (size)) + result.put (item, item.getPos ()); + return result; + } + + public Hashtable getMoveInsideItem (Building building, Hashtable oldPos) { + Hashtable result = new Hashtable (); + DimensionDouble size = building.getRealSize (); + for (Item item : oldPos.keySet ()) + result.put (item, Item.getPosInside (size, oldPos.get (item), item.getThetaDegree (), item.getSize ())); + return result; + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/unit/Line.java b/src/java/adecWatt/model/unit/Line.java new file mode 100644 index 0000000..7304ad2 --- /dev/null +++ b/src/java/adecWatt/model/unit/Line.java @@ -0,0 +1,10 @@ +package adecWatt.model.unit; + +import adecWatt.model.AdecWatt; + +public class Line extends NonWorkspace { + + public Line (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } +} diff --git a/src/java/adecWatt/model/unit/NonWorkspace.java b/src/java/adecWatt/model/unit/NonWorkspace.java new file mode 100644 index 0000000..3d41503 --- /dev/null +++ b/src/java/adecWatt/model/unit/NonWorkspace.java @@ -0,0 +1,29 @@ +package adecWatt.model.unit; + +import java.util.Enumeration; + +import adecWatt.model.Acc; +import adecWatt.model.AdecWatt; +import adecWatt.model.Prop; +import adecWatt.model.Unit; +import adecWatt.model.UnitNode; + +public abstract class NonWorkspace extends Unit { + // ======================================== + static public final String[] workspacesRoot = { Prop.PropBuilding, "lightplot" }; + + public NonWorkspace (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } + + // ======================================== + public void updateView () { + for (String workspaceRoot : workspacesRoot) + for (Enumeration enumUnitNode = adecWatt.getPermanentDB ().getRootByName (workspaceRoot).getUnitNode ().breadthFirstEnumeration (); + enumUnitNode.hasMoreElements (); + ) + ((Workspace) ((UnitNode) enumUnitNode.nextElement ()).getUnit ()). + stateNotifier.broadcastDisplay (BroadcastUpdatePermItem, this); + } + // ======================================== +} diff --git a/src/java/adecWatt/model/unit/Workspace.java b/src/java/adecWatt/model/unit/Workspace.java new file mode 100644 index 0000000..099bb65 --- /dev/null +++ b/src/java/adecWatt/model/unit/Workspace.java @@ -0,0 +1,857 @@ +package adecWatt.model.unit; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Dimension2D; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.TreeSet; +import java.util.Vector; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import misc.DimensionDouble; +import misc.ScaledImage; +import misc.Story; +import static misc.ScaledImage.ONE_TILE; + +import adecWatt.model.Acc; +import adecWatt.model.AdecWatt; +import adecWatt.model.Circuits; +import adecWatt.model.Comp; +import adecWatt.model.Editable; +import adecWatt.model.Item; +import adecWatt.model.Patch; +import adecWatt.model.Prop; +import adecWatt.model.Segm; +import adecWatt.model.Unit; +import adecWatt.model.xml.XmlComp; +import adecWatt.model.xml.XmlSegm; + +@SuppressWarnings ("serial") +public abstract class Workspace extends Unit> { + + private float buildingOpacity = .5F; + private float hiddenOpacity = .15F; + public void setOpacity (float buildingOpacity) { this.buildingOpacity = buildingOpacity; } // XXX update GUI + public float getOpacity () { return buildingOpacity; } + + public Workspace (AdecWatt adecWatt, String id) { + super (adecWatt, id); + } + + // ======================================== + @SuppressWarnings ("unchecked") + public void collectEmbedded () { + if (xmlPermanent == null) + return; + super.collectEmbedded (); + ArrayList items = new ArrayList (); + for (XmlSegm xmlSegm : xmlPermanent.getSegms ()) + items.add (new Segm (this, xmlSegm)); + for (XmlComp xmlComp : xmlPermanent.getComps ()) + items.add (new Comp (this, xmlComp)); + for (Item item : items) + item.fixName (true); + } + + // ======================================== + public void updateView () { + adecWatt.broadcastDisplay (AdecWatt.BroadcastUpdateWorkspace, this); + updateTree (); + } + public void updateConnection () { + adecWatt.broadcastDisplay (BroadcastConnection, this); + } + public void updateSelection (List items) { + adecWatt.broadcastDisplay (BroadcastSetSelectionItems, this, items); + } + + // ======================================== + public Story.Command getDoSelection (Item item) { + return getDoSelection (Arrays.asList (item)); + } + public Story.Command getDoSelection (final List items) { + return story.new Command (StorySelectItem) { + public void exec () { updateSelection (items); } + public void undo () { } + }; + } + public Story.Command getUndoSelection (Item item) { + return getUndoSelection (Arrays.asList (item)); + } + public Story.Command getUndoSelection (final List items) { + return story.new Command (StorySelectItem) { + public void exec () { } + public void undo () { updateSelection (items); } + }; + } + + // ======================================== + public void storyAddComp (NonWorkspace model, Point2D.Double pos) { + Comp comp = new Comp (this, model); + if (comp.isSticky ()) + return; + storyAddItem (comp, pos); + } + public void storyAddSegm (NonWorkspace model, Point2D.Double pos) { + Segm segm = new Segm (this, model); + if (segm.isSticky ()) + return; + storyAddItem (segm, pos); + } + public void storyAddItem (Item item, Point2D.Double pos) { + item.changePos (pos); + Story.Commands commands = story.new Commands (StoryAddItem) {}; + commands.add (getUndoSelection ((List) null)); + item.validateContainer (commands, StoryAddItem); + commands.add (getDoSelection (item)); + story.add (commands); + } + public void storyCloneItem (Item ref, Point2D.Double pos) { + if (ref.isSticky ()) + return; + Item item = ref.clone (this); + item.changePos (pos); + Story.Commands commands = story.new Commands (StoryCloneItem) {}; + commands.add (getUndoSelection (ref)); + item.validateContainer (commands, StoryCloneItem); + commands.add (getDoSelection (item)); + story.add (commands); + } + public void storyPasteItem (Vector sItem) { + if (sItem == null) + return; + Vector preSelection = new Vector (sItem.size ()); + for (Item ref : sItem) { + if (ref.isSticky ()) + continue; + preSelection.add (ref); + } + if (preSelection.size () < 1) + return; + DimensionDouble size = getRealSize (); + Story.Commands commands = story.new Commands (StoryPasteItem) {}; + Vector postSelection = new Vector (preSelection.size ()); + commands.add (getUndoSelection (preSelection)); + for (Item ref : preSelection) { + Item item = ref.clone (this); + Point2D.Double pos = item.getPos (); + // XXX si objet à la même place + //pos.x += .5; pos.y += .5; + item.changePos (Item.getPosInside (size, pos, item.getThetaDegree (), item.getSize ())); + postSelection.add (item); + item.validateContainer (commands, StoryPasteItem); + } + commands.add (getDoSelection (postSelection)); + story.add (commands); + } + public Item storyGetCloseItem (Story.Commands commands, Item item) { + Item closeItem = getLocalEmbedded (item.getId ()); + if (closeItem != null) + return closeItem; + closeItem = getCloseEmbedded (item); + closeItem.validateContainer (commands, StoryLinkItem); + return closeItem; + } + public void storyHideShowItem (List sItem, final boolean hidden) { + if (sItem == null) + return; + Story.Commands commands = story.new Commands (StoryHideItem) {}; + Vector toHideShow = new Vector (sItem.size ()); + for (Item ref : sItem) { + if (ref.isHidden () == hidden) + continue; + toHideShow.add (storyGetCloseItem (commands, ref)); + } + if (toHideShow.size () < 1) + return; + commands.add (getUndoSelection (toHideShow)); + for (final Item item : toHideShow) { + commands.add (story.new Command (StoryHideItem) { + public void exec () { if (hidden) item.addModifier (Hidden); else item.removeModifier (Hidden); } + public void undo () { if (hidden) item.removeModifier (Hidden); else item.addModifier (Hidden); } + public void display () { item.updateView (); } // XXX utile ? + }); + } + commands.add (getDoSelection ((List) null)); + story.add (commands); + } + public void storyRemoveItems (List sItem) { + if (sItem == null) + return; + Vector toRemove = new Vector (sItem.size ()); + for (Item ref : sItem) { + Item localItem = getLocalEmbedded (ref.getId ()); + if (localItem == null || localItem.isSticky ()) + continue; + toRemove.add (localItem); + } + if (toRemove.size () < 1) + return; + Story.Commands commands = story.new Commands (StoryRemoveItem) {}; + commands.add (getUndoSelection (toRemove)); + for (final Item item : toRemove) { + commands.add (story.new Command (StoryRemoveItem) { + public void exec () { removeEmbedded (item); } + public void undo () { addEmbedded (item); } + public void displayExec () { item.updateView (BroadcastRemoveItem); } + public void displayUndo () { item.updateView (BroadcastNewItem); } + }); + } + commands.add (getDoSelection ((List) null)); + story.add (commands); + } + public Acc storyGetCloseAcc (Story.Commands commands, Item item, Accessory accessory) { + Acc acc = (Acc) item.findEmbeddedRootOf (accessory); + if (acc == null) + return null; + Acc closeAcc = (Acc) item.getLocalEmbedded (acc.getId ()); + if (closeAcc != null) + return closeAcc; + closeAcc = (Acc) item.getCloseEmbedded (acc); + closeAcc.validateContainer (commands, StoryLinkAcc); + return closeAcc; + } + public void storyAddAcc (Item item, final Accessory accessory) { + Story.Commands commands = story.new Commands (StoryAddAcc) {}; + final Item localItem = storyGetCloseItem (commands, item); + final Acc localAcc = storyGetCloseAcc (commands, localItem, accessory); + if (localAcc == null) + return; + final NonWorkspace oldAccessoryModel = localAcc.getModel (); + if (accessory != oldAccessoryModel) + commands.add (story.new Command (StoryAddAcc) { + public void exec () { + localAcc.setModel (accessory); + } + public void undo () { + localAcc.setModel (oldAccessoryModel); + } + public void display () { + localItem.updateView (); + } + }); + story.add (commands); + } + public void storyRemoveAcc (Acc acc) { + final Item localItem = getLocalEmbedded (acc.getContainer ().getId ()); + if (localItem == null) + return; + final Acc oldAcc = (Acc) localItem.getLocalEmbedded (acc.getId ()); + if (oldAcc == null) + return; + story.add (story.new Command (StoryRemoveAcc) { + public void exec () { localItem.removeEmbedded (oldAcc); } + public void undo () { localItem.addEmbedded (oldAcc); } + public void display () { localItem.updateView (); } + }); + } + public void storyConnect (Comp srcComp, Acc srcAcc, final String dstCompName, final String dstAccName) { + Comp localComp = (Comp) getCloseEmbedded (srcComp); + final Acc localAcc = localComp.getCloseEmbedded (srcAcc); + Story.Commands commands = story.new Commands (StoryConnectAcc) {}; + localAcc.validateContainer (commands, StoryLinkAcc); + + final String oldConnectedTo = localAcc.getConnectedTo (); + final Prop oldConnectedToProp = localAcc.getPropVal (Prop.PropConnectedTo); + final String oldConnectedOn = localAcc.getConnectedOn (); + final Prop oldConnectedOnProp = localAcc.getPropVal (Prop.PropConnectedOn); + // XXX if (dstCompName == null) => remove + // XXX if (dstAccName == null) => remove + + commands.add (story.new Command (StoryConnectAcc) { + public void exec () { + localAcc.changeConnectedTo (dstCompName); + localAcc.changeConnectedOn (dstAccName); + } + public void undo () { + if (oldConnectedToProp == null) + localAcc.removeOwnProp (Prop.PropConnectedTo); + else + localAcc.changeConnectedTo (oldConnectedTo); + if (oldConnectedOnProp == null) + localAcc.removeOwnProp (Prop.PropConnectedOn); + else + localAcc.changeConnectedOn (oldConnectedOn); + } + public void display () { + localAcc.updateView (); + updateConnection (); + } + }); + story.add (commands); + } + + public void storyRotItem (Vector sItem, Vector thetas) { + Story.Commands commands = story.new Commands (StoryRotItem) {}; + final DimensionDouble size = getRealSize (); + int nbSelected = sItem.size (); + for (int i = 0; i < nbSelected; i++) { + final Item item = sItem.get (i); + final double thetaDegree = thetas.get (i); + final double oldThetaDegree = item.getThetaDegree (); + if (thetaDegree == oldThetaDegree) + continue; + final Item localItem = storyGetCloseItem (commands, item); + final Prop oldProp = item.getOwnProp (Prop.PropRot); + final Point2D.Double pos = item.getPos (); + commands.add (story.new Command (StoryRotItem) { + public void exec () { + localItem.changeThetaDegree (thetaDegree); + localItem.changePos (Item.getPosInside (size, pos, item.getThetaDegree (), item.getSize ())); + } + public void undo () { + if (oldProp == null) + localItem.removeOwnProp (Prop.PropRot); + else + localItem.changeThetaDegree (oldThetaDegree); + localItem.changePos (pos); + } + public void display () { + localItem.updateView (BroadcastChangePos); + localItem.updateView (BroadcastChangeRot); + } + }); + } + story.add (commands); + } + + public void storyMoveItem (Vector sItem, Vector poss) { + Story.Commands commands = story.new Commands (StoryMoveItem) {}; + DimensionDouble size = getRealSize (); + int nbSelected = sItem.size (); + for (int i = 0; i < nbSelected; i++) { + Item item = sItem.get (i); + final Point2D.Double insidePos = Item.getPosInside (size, poss.get (i), item.getThetaDegree (), item.getSize ()); + final Point2D.Double old = item.getPos (); + if (insidePos.equals (old)) { + item.updateView (BroadcastChangePos); + continue; + } + final Item localItem = storyGetCloseItem (commands, item); + commands.add (story.new Command (StoryMoveItem) { + public void exec () { localItem.changePos (insidePos); } + public void undo () { localItem.changePos (old); } + public void display () { localItem.updateView (BroadcastChangePos); } + }); + } + story.add (commands); + } + + public void storyRotResize (Item sItem, Point2D.Double sPos, final double sThetaDegree, final DimensionDouble sSize) { + Story.Commands commands = story.new Commands (StoryRotResizeItem) {}; + final Item localItem = storyGetCloseItem (commands, sItem); + DimensionDouble size = getRealSize (); + final Point2D.Double oldPos = localItem.getPos (); + final DimensionDouble oldSize = localItem.getSize (); + final double oldThetaDegree = localItem.getThetaDegree (); + final Point2D.Double insidePos = Item.getPosInside (size, sPos, sThetaDegree, sSize); + commands.add (story.new Command (StoryRotResizeItem) { + public void exec () { localItem.changeRotSize (insidePos, sThetaDegree, sSize); } + public void undo () { localItem.changeRotSize (oldPos, oldThetaDegree, oldSize); } + public void display () { localItem.updateView (BroadcastChangeRotSize); } + }); + story.add (commands); + } + + // ======================================== + public Line2D.Double getMagnetPoint (Point2D.Double pos, Point2D.Double onGrid, double close) { + double minD = close; + Point2D.Double minPos = new Point2D.Double (); + if (adecWatt.getHandleGlue ()) { + Point2D.Double closeHandle = (Point2D.Double) pos.clone (); + for (double[] bounds : allBounds) + minD = Item.getCloseBound (bounds, pos, minD, closeHandle); + if (minD < close) { + pos.x = closeHandle.x; + pos.y = closeHandle.y; + return new Line2D.Double (pos, pos); + } + } + if (adecWatt.getGridGlue ()) + if (onGrid.distance (pos) < close) { + pos.x = onGrid.x; + pos.y = onGrid.y; + } + if (adecWatt.getBoundGlue ()) { + boolean inSegment = adecWatt.getInSegmentGlue (); + double minL = close; + // XXX si croissement + //Vector lines = new Vector (); + Line2D.Double minLine = null; + for (double[] bounds : allBounds) { + // XXX nombres magiques + double oldX = bounds [6], oldY = bounds [7]; + for (int x = 0, y = 1; x < 8; x+=2, y+=2) { + Line2D.Double line = new Line2D.Double (oldX, oldY, oldX = bounds[x], oldY = bounds[y]); + // XXX si line=point null ? + double d = inSegment ? line.ptSegDist (pos) : line.ptLineDist (pos); + if (d < minL) { + //lines.add (line); + minLine = line; + minL = d; + } + } + } + // XXX et rester sur la grille ? + // if (lines.size () > 0) { + // for (Line2D.Double line : lines) { + if (minLine != null) { + double xDelta = minLine.x2 - minLine.x1; + double yDelta = minLine.y2 - minLine.y1; + if ((xDelta == 0) && (yDelta == 0)) + // XXX vérif ci-dessus si line=point + return null; + double u = ((pos.x - minLine.x1) * xDelta + (pos.y - minLine.y1) * yDelta) / (xDelta * xDelta + yDelta * yDelta); + if (inSegment) + u = Math.min (1, Math.max (0, u)); + Point2D.Double result = new Point2D.Double (minLine.x1 + u*xDelta, minLine.y1 + u*yDelta); + pos.x = result.x; + pos.y = result.y; + return minLine; + } + } + return null; + } + + public void storySpaceItem (Vector items, boolean isHorizontal, Double spaceRequest) { + if (items == null || items.size () < 2) + return; + items.sort (isHorizontal ? Item.xPosComparator : Item.yPosComparator); + double[][] axesValues = getAxesValues (items, isHorizontal); + double minSpace = getMinSpace (axesValues[1]); + int nbItems = items.size (); + double space = spaceRequest != null ? + spaceRequest : + (axesValues[0][nbItems-1]-axesValues[0][0] - minSpace)/(nbItems-1); + if (space < 0) + space = 0; + for (int i = 1; i < nbItems; i++) + axesValues[0][i] = space+axesValues[0][i-1]+(axesValues[1][i-1]+axesValues[1][i])/2; + storyMoveItem (items, getPos (items, isHorizontal, axesValues[0])); + } + public void storyDistributeItem (Vector items, boolean isHorizontal, Double distribRequest) { + if (items == null || items.size () < 2) + return; + items.sort (isHorizontal ? Item.xPosComparator : Item.yPosComparator); + double[][] axesValues = getAxesValues (items, isHorizontal); + int nbItems = items.size (); + double distrib = distribRequest != null ? + distribRequest : + (axesValues[0][nbItems-1]-axesValues[0][0])/(nbItems-1); + double minDistrib = getMinDistribution (axesValues[1]); + if (distrib < minDistrib) + distrib = minDistrib; + for (int i = 1; i < nbItems; i++) + axesValues[0][i] = axesValues[0][i-1]+distrib; + storyMoveItem (items, getPos (items, isHorizontal, axesValues[0])); + } + + static public enum Alignment { + LEFT, CENTER, RIGHT, TOP, MIDDLE, BOTTOM; + } + + public void storyAlignItem (Vector items, Alignment alignment) { + if (items == null || items.size () < 2) + return; + int nbItems = items.size (); + Vector poss = new Vector (nbItems); + double x = 0, y = 0; + switch (alignment) { + case LEFT: + x = items.get (0).getPos ().x; + break; + case TOP: + y = items.get (0).getPos ().y; + break; + } + for (Item item : items) { + Point2D.Double pos = item.getPos (); + DimensionDouble size = Item.getRotSize (item.getSize (), item.getThetaDegree ()); + switch (alignment) { + case LEFT: + x = Math.min (x, pos.x-size.width/2); + break; + case CENTER: + x += pos.x; + break; + case RIGHT: + x = Math.max (x, pos.x+size.width/2); + break; + case TOP: + y = Math.min (y, pos.y-size.height/2); + break; + case MIDDLE: + y += pos.y; + break; + case BOTTOM: + y = Math.max (y, pos.y+size.height/2); + break; + } + } + switch (alignment) { + case CENTER: + x /= nbItems; + break; + case MIDDLE: + y /= nbItems; + break; + } + for (Item item : items) { + Point2D.Double pos = item.getPos (); + DimensionDouble size = Item.getRotSize (item.getSize (), item.getThetaDegree ()); + switch (alignment) { + case LEFT: + poss.add (new Point2D.Double (x+size.width/2, pos.y)); + break; + case CENTER: + poss.add (new Point2D.Double (x, pos.y)); + break; + case RIGHT: + poss.add (new Point2D.Double (x-size.width/2, pos.y)); + break; + case TOP: + poss.add (new Point2D.Double (pos.x, y+size.height/2)); + break; + case MIDDLE: + poss.add (new Point2D.Double (pos.x, y)); + break; + case BOTTOM: + poss.add (new Point2D.Double (pos.x, y-size.height/2)); + break; + } + } + storyMoveItem (items, poss); + } + public double[][] getAxesValues (Vector items, boolean isHorizontal) { + int nbItems = items.size (); + double[][] result = new double [2][nbItems]; + int i = 0; + for (Item item : items) { + Point2D.Double pos = item.getPos (); + DimensionDouble size = Item.getRotSize (item.getSize (), item.getThetaDegree ()); + if (isHorizontal) { + result[0][i] = pos.x; + result[1][i] = size.width; + } else { + result[0][i] = pos.y; + result[1][i] = size.height; + } + i++; + } + return result; + } + public Vector getPos (Vector items, boolean isHorizontal, double[] poss) { + Vector result = new Vector (); + int i = 0; + for (Item item : items) { + Point2D.Double pos = item.getPos (); + result.add (isHorizontal ? + new Point2D.Double (poss[i], pos.y) : + new Point2D.Double (pos.x, poss[i])); + i++; + } + return result; + } + + public double getMinDistribution (double [] widths) { + double result = 0; + for (int i = 1; i < widths.length; i++) + result = Math.max (result, widths[i-1]+widths[i]); + return result/2; + } + public double getMinSpace (double [] widths) { + double result = 0; + for (int i = 0; i < widths.length; i++) + result += widths[i]; + result -= (widths[0]+widths[widths.length-1])/2; + return result; + } + + // ======================================== + public Element getXml (Node parent, Document document) { + Element child = super.getXml (parent, document); + return child; + } + + // ======================================== + public Patch getPatch () { + try { + Circuits circuits = Circuits.getCircuits (this, getAdecWatt ().getPermanentDB ().getPowerPlugId ()); + return new Patch (circuits); + } catch (Exception e) { + return null; + } + } + + // public boolean match (String text) { + // try { + // if (super.match (text)) + // return true; + // for (Item item : getAllItems ()) + // if (item.match (text)) + // // if (item.getName ().toLowerCase ().indexOf (text) >= 0 || + // // item.getLocalName ().toLowerCase ().indexOf (text) >= 0 || + // // item.getId ().indexOf (text) >= 0) + // return true; + // } catch (Exception e) { + // } + // return false; + // } + + // ======================================== + // XXX cache revoir acces + protected HashSet plugedComps = new HashSet (); + protected Hashtable namedItems = new Hashtable (); + protected Vector allItems; + protected Vector allBounds; + + public Vector getAllItems () { return allItems; } + public void addPlugedComps (Comp comp) { plugedComps.add (comp); } + public boolean containsItem (String itemId) { return namedItems.containsKey (itemId) || embedded.containsKey (itemId); } + + public void print (Graphics2D printGraphics, double lineWidth, Collection itemsNotToPrint, boolean printCircuit) { + Composite defaultComposit = printGraphics.getComposite (); + Composite buildingComposit = ((AlphaComposite) defaultComposit).derive (buildingOpacity); + Composite hiddenBuildingComposit = ((AlphaComposite) defaultComposit).derive (buildingOpacity*hiddenOpacity); + Composite hiddenComposit = ((AlphaComposite) defaultComposit).derive (hiddenOpacity); + printBlueprint (printGraphics); + namedItems.clear (); + plugedComps.clear (); + for (Item item : getInheritedEmbeddedValues ()) + namedItems.put (item.getId (), item); + Building building = getBuilding (); + Collection> buildingItems = null; + if (building != null) { + buildingItems = building.getInheritedEmbeddedValues (); + for (Item item : buildingItems) + namedItems.putIfAbsent (item.getId (), item); + } + allItems = new Vector (namedItems.values ()); + allItems.sort (Item.zPosComparator); + Vector itemsUsed = new Vector (); + for (Item item : allItems) + for (String accId : (TreeSet) item.getEmbeddedIds ()) + try { + itemsUsed.add (namedItems.get (item.findEmbedded (accId).getConnectedTo ())); + } catch (Exception e) { + } + String plugId = adecWatt.getPermanentDB ().getPowerPlugId (); + allBounds = new Vector (namedItems.size ()); + for (Item item : allItems) { + if (item.isReserved () || (itemsNotToPrint != null && itemsNotToPrint.contains (item.getId ()))) + continue; + boolean isBuilding = buildingItems != null && buildingItems.contains (item); + boolean isHidden = item.isHidden (); + if (!itemsUsed.contains (item)) { + if (isHidden) + printGraphics.setComposite (isBuilding ? hiddenBuildingComposit : hiddenComposit); + else if (isBuilding) + printGraphics.setComposite (buildingComposit); + } + try { + allBounds.add (item.getBounds ()); + item.print (printGraphics, this, plugId); + } catch (Exception e) { + System.err.println ("Can't print <"+item.getId ()+"> ("+item.getModel ()+")"); + // XXX supprimé dans l'héritage + continue; + } + if (isBuilding||isHidden) + printGraphics.setComposite (defaultComposit); + } + if (!printCircuit) + return; + HashMap linked = new HashMap (); + for (Comp beginComp : plugedComps) + for (Acc beginAcc : beginComp.allPlugs) + try { + Comp endComp = (Comp) namedItems.get (beginAcc.getConnectedTo ()); + if (endComp == null) + continue; + linked.put (beginAcc, endComp); + Acc.printConnection (printGraphics, lineWidth, + beginComp.getAccCenter (beginAcc.getId ()), + endComp.getAccCenter (beginAcc.getConnectedOn ())); + } catch (Exception e) { + //e.printStackTrace (); + } + Circuits circuits = new Circuits (linked, plugedComps); + for (Comp plugedComp : plugedComps) + for (Acc acc : plugedComp.allPlugs) { + Circuits.CircuitState circuitState = circuits.getState (plugedComp, acc); + if (circuitState == null) + continue; + Acc.printCircuit (printGraphics, lineWidth, plugedComp.getAccCenter (acc.getId ()), circuitState); + } + } + + public void printBlueprint (Graphics2D printGraphics) { + ScaledImage scaledBlueprint = getBlueprint (); + if (scaledBlueprint == null) + return; + Double visible = getBlueprintVisibility (); + if (visible != null && visible <= 0) + return; + DimensionDouble blueprintSize = getBlueprintSize (); + if (blueprintSize == null) + blueprintSize = getRealSize (); + Point2D.Double blueprintPos = null; + try { + blueprintPos = getBlueprintPos (); + } catch (Exception e) { + } + if (blueprintPos == null) + blueprintPos = new Point2D.Double (); + printImage (printGraphics, scaledBlueprint, blueprintPos, blueprintSize, 0., null); + } + + public ArrayList findItems (Point2D.Double realPos, double close) { + ArrayList result = new ArrayList (); + double [] coord = new double [] {realPos.x, realPos.y}; + for (Item item : namedItems.values ()) { + coord[0] = realPos.x; + coord[1] = realPos.y; + if (item.containsClose (coord, close)) + result.add (item); + } + return result; + } + + // ======================================== + static public void printImage (Graphics2D printGraphics, ScaledImage scaledImage, + Point2D realPos, DimensionDouble realSize, double thetaDegree, Double[] tileSize) { + Point2D pos = new Point2D.Double (realPos.getX (), realPos.getY ()); + DimensionDouble size = new DimensionDouble (realSize.getWidth (), realSize.getHeight ()); + double theta = Math.toRadians (thetaDegree); + Dimension tile = Item.getTile (tileSize, realSize); + ScaledImage.ImageInfo imageInfo = scaledImage.newInfo2 (size, theta); + BufferedImage reference = scaledImage.reference; + 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./tile.width, scaleY = 1./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); + } + + static public void printText (Graphics2D printGraphics, String label, Color color, Point2D realPos, DimensionDouble realSize) { + double minSide = Math.min (realSize.width, realSize.height); + printText (printGraphics, label, color, realPos, new DimensionDouble (minSide, minSide), 0); + } + static public void printText (Graphics2D printGraphics, String label, Color color, Point2D realPos, DimensionDouble realSize, double thetaDegree) { + if (label == null || "".equals (label)) + return; + AffineTransform af = printGraphics.getTransform (); + + Font labelFont = getLabelFont (label, printGraphics.getFont (), realSize, printGraphics); + printGraphics.setFont (labelFont); + Rectangle2D bounds = labelFont.getStringBounds (label, printGraphics.getFontRenderContext ()); + // XXX bug Java + // FontMetrics fontMetrics = printGraphics.getFontMetrics (labelFont); + // int ascent = fontMetrics.getMaxAscent (); + // int descent = fontMetrics.getMaxDescent (); + // double bottom = descent*bounds.getHeight ()/(ascent+descent); + // System.err.println ("coucou font "+ascent+" "+descent+" =? "+bounds.getHeight ()+" "+bounds.getWidth ()); + double bottom = labelFont.getSize2D ()*0.201298701299; + Point2D.Double pos = new Point2D.Double (realPos.getX (), //-bounds.getWidth ()/2, + realPos.getY ()); //-bounds.getHeight ()/2); //+labelFont.getSize2D ()/2-bottom);bounds + printGraphics.translate (pos.getX (), pos.getY ()); + printGraphics.rotate (Math.toRadians (thetaDegree)); + printGraphics.setColor (new Color (1f, 1f, 1f, .8f)); + printGraphics.draw (new Rectangle2D.Double (bounds.getX () - bounds.getWidth ()/2, bounds.getY (), + bounds.getWidth (), bounds.getHeight ())); + printGraphics.setColor (color); + printGraphics.drawString (label, (float) (-bounds.getWidth ()/2), (float) (labelFont.getSize2D ()/2-bottom)); + printGraphics.setTransform (af); + } + + static public Font getLabelFont (String labelText, Font labelFont, Dimension2D size, Graphics2D printGraphics) { + if (labelText == null || labelText.isEmpty () || printGraphics == null) + return labelFont; + float height = (float) size.getHeight ();//-labelSpace; + labelFont = labelFont.deriveFont (height); + int stringWidth = printGraphics.getFontMetrics (labelFont).stringWidth (labelText); + float width = (float) size.getWidth ();//-labelSpace; + float newFontSize = height * width / stringWidth; + if (newFontSize < height) + labelFont = labelFont.deriveFont (newFontSize); + return labelFont; + } + + static public void printLine (Graphics2D printGraphics, Paint paint, Stroke stroke, + Point2D realPos, double length, double thetaDegree, + Stroke arrowStroke, Shape arrowStart, Shape arrowEnd) { + Paint prevPaint = printGraphics.getPaint (); + AffineTransform af = printGraphics.getTransform (); + //Stroke prevStroke = printGraphics.getStroke (); + + Line2D line = new Line2D.Double (-length/2, 0, length/2, 0); + printGraphics.setStroke (stroke); + printGraphics.setPaint (paint); + printGraphics.translate (realPos.getX (), realPos.getY ()); + printGraphics.rotate (Math.toRadians (thetaDegree)); + printGraphics.draw (line); + printGraphics.setStroke (arrowStroke); + //printGraphics.setPaint (java.awt.Color.blue); + if (arrowStart != null) { + printGraphics.setTransform (af); + printGraphics.translate (realPos.getX (), realPos.getY ()); + printGraphics.rotate (Math.toRadians (thetaDegree)); + printGraphics.translate (-length/2, 0); + printGraphics.rotate (Math.toRadians (180)); + printGraphics.fill (arrowStart); + printGraphics.draw (arrowStart); + } + //printGraphics.setPaint (java.awt.Color.red); + if (arrowEnd != null) { + printGraphics.setTransform (af); + printGraphics.translate (realPos.getX (), realPos.getY ()); + printGraphics.rotate (Math.toRadians (thetaDegree)); + printGraphics.translate (length/2, 0); + printGraphics.fill (arrowEnd); + printGraphics.draw (arrowEnd); + } + + printGraphics.setTransform (af); + printGraphics.setPaint (prevPaint); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/XmlAcc.java b/src/java/adecWatt/model/xml/XmlAcc.java new file mode 100644 index 0000000..b143121 --- /dev/null +++ b/src/java/adecWatt/model/xml/XmlAcc.java @@ -0,0 +1,16 @@ +package adecWatt.model.xml; + +import org.w3c.dom.Node; + +import adecWatt.model.Acc; +import adecWatt.model.Permanent; + +public class XmlAcc extends XmlPermanent { + + // ======================================== + public XmlAcc (Node node) { + parseNode (node, Acc.AccTypeEnum.class, Acc.AccAttrEnum.class); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/XmlComp.java b/src/java/adecWatt/model/xml/XmlComp.java new file mode 100644 index 0000000..a8abcf9 --- /dev/null +++ b/src/java/adecWatt/model/xml/XmlComp.java @@ -0,0 +1,16 @@ +package adecWatt.model.xml; + +import org.w3c.dom.Node; + +import adecWatt.model.Comp; +import adecWatt.model.Permanent; + +public class XmlComp extends XmlPermanent { + + // ======================================== + public XmlComp (Node node) { + parseNode (node, Comp.CompTypeEnum.class, Comp.CompAttrEnum.class); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/XmlPermanent.java b/src/java/adecWatt/model/xml/XmlPermanent.java new file mode 100644 index 0000000..0989529 --- /dev/null +++ b/src/java/adecWatt/model/xml/XmlPermanent.java @@ -0,0 +1,201 @@ +package adecWatt.model.xml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import misc.Util; + +public class XmlPermanent, A extends Enum> { + + // ======================================== + public T type; + private Hashtable facets = new Hashtable (); + private String value; + + ArrayList unknownAttr = new ArrayList (); + ArrayList unknownNodes = new ArrayList (); + + // ======================================== + @SuppressWarnings ({"unchecked", "rawtypes"}) + public void parseNode (Node node, Class nodeEnum, Class attrEnum) { + if (Node.ELEMENT_NODE != node.getNodeType ()) + throw new IllegalArgumentException ("XML unit not a node ("+node+")."); + type = (T) Enum.valueOf ((Class)nodeEnum, Util.toCapital (node.getNodeName ())); + NamedNodeMap allFacets = node.getAttributes (); + for (int i = 0; i < allFacets.getLength (); i++) { + Node facetNode = allFacets.item (i); + try { + if (facetNode.getNodeValue ().isEmpty ()) + continue; + facets.put ((A) Enum.valueOf ((Class)attrEnum, Util.toCapital (facetNode.getNodeName ())), facetNode.getNodeValue ()); + } catch (Exception e) { + unknownAttr.add (facetNode); + } + } + NodeList childrens = node.getChildNodes (); + for (int i = 0; i < childrens.getLength (); i++) { + Node child = childrens.item (i); + if (isEmpty (child)) + continue; + if (isText (child)) { + String val = child.getNodeValue ().trim (); + if (value != null) + value += " "+val; + else + value = val; + continue; + } + unknownNodes.add (child); + } + } + + // ======================================== + static public boolean isEmpty (Node node) { + return + Node.TEXT_NODE == node.getNodeType () && + 0 == node.getChildNodes ().getLength () && + 0 == node.getNodeValue ().trim ().length () && + (null == node.getAttributes () || 0 == node.getAttributes ().getLength ()); + } + + static public boolean isText (Node node) { + return + Node.TEXT_NODE == node.getNodeType () && + 0 == node.getChildNodes ().getLength () && + (null == node.getAttributes () || 0 == node.getAttributes ().getLength ()); + } + + // ======================================== + public String getValue () { + String result = value; + value = null; + return result; + } + + public String getFacet (A a) { + return facets.remove (a); + } + + public Collection getSplitFacet (A a) { + String result = facets.remove (a); + if (result == null) + return null; + return new TreeSet (Arrays.asList (result.toLowerCase ().split ("\\|"))); + } + public List getOrderedSplitFacet (A a) { + String result = facets.remove (a); + if (result == null) + return null; + return Arrays.asList (result.toLowerCase ().split ("\\|")); + } + + // ======================================== + public ArrayList getProps () { + ArrayList xmlProps = new ArrayList (); + for (Iterator it = unknownNodes.iterator (); it.hasNext (); ) { + Node node = it.next (); + try { + xmlProps.add (new XmlProp (node)); + it.remove (); + } catch (Exception e) { + } + } + return xmlProps; + } + public ArrayList getSegms () { + ArrayList xmlSegms = new ArrayList (); + for (Iterator it = unknownNodes.iterator (); it.hasNext (); ) { + Node node = it.next (); + try { + xmlSegms.add (new XmlSegm (node)); + it.remove (); + } catch (Exception e) { + } + } + return xmlSegms; + } + public ArrayList getComps () { + ArrayList xmlComps = new ArrayList (); + for (Iterator it = unknownNodes.iterator (); it.hasNext (); ) { + Node node = it.next (); + try { + xmlComps.add (new XmlComp (node)); + it.remove (); + } catch (Exception e) { + } + } + return xmlComps; + } + public ArrayList getAccs () { + ArrayList xmlAccs = new ArrayList (); + for (Iterator it = unknownNodes.iterator (); it.hasNext (); ) { + Node node = it.next (); + try { + xmlAccs.add (new XmlAcc (node)); + it.remove (); + } catch (Exception e) { + } + } + return xmlAccs; + } + + public Element getXml (Document document) { + Element element = document.createElement (type.toString ().toLowerCase ()); + if (value != null) + element.appendChild (document.createTextNode (value)); + for (A facet : facets.keySet ()) + element.setAttribute (facet.toString ().toLowerCase (), facets.get (facet)); + for (Node subNode : unknownAttr) + element.setAttributeNode ((Attr) (document.importNode (subNode, true))); + for (Node subNode : unknownNodes) + element.appendChild (document.importNode (subNode, true)); + return element; + } + + // ======================================== + static public void putValue (Element element, String value) { + if (value == null || value.isEmpty ()) + return; + element.appendChild (element.getOwnerDocument ().createTextNode (value)); + } + + static public void putFacet (Element element, Enum a, String value) { + if (value == null || value.isEmpty ()) + return; + element.setAttribute (a.toString ().toLowerCase (), value); + } + @SuppressWarnings ("unchecked") + static public void putSplitFacet (Element element, Enum a, Collection... tValues) { + String result = ""; + String sep = ""; + for (Collection values : tValues) { + if (values == null || values.size () == 0) + continue; + result += sep + String.join ("|", values); + sep = "|"; + } + putFacet (element, a, result); + } + + // ======================================== + // XXX a supprimer + // public String toString () { + // String result = type.toString ().toLowerCase ()+":"; + // for (A facet : facets.keySet ()) + // result+= " "+facet.toString ().toLowerCase ()+"="+facets.get (facet); + // return result; + // } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/XmlProp.java b/src/java/adecWatt/model/xml/XmlProp.java new file mode 100644 index 0000000..381ce95 --- /dev/null +++ b/src/java/adecWatt/model/xml/XmlProp.java @@ -0,0 +1,19 @@ +package adecWatt.model.xml; + +import org.w3c.dom.Node; + +import adecWatt.model.Permanent; +import adecWatt.model.Prop; + +/** + text|icon|image|enum|number|geo|square|cube|article +*/ +public class XmlProp extends XmlPermanent { + + // ======================================== + public XmlProp (Node node) { + parseNode (node, Prop.PropTypeEnum.class, Prop.PropAttrEnum.class); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/XmlSegm.java b/src/java/adecWatt/model/xml/XmlSegm.java new file mode 100644 index 0000000..adede9d --- /dev/null +++ b/src/java/adecWatt/model/xml/XmlSegm.java @@ -0,0 +1,16 @@ +package adecWatt.model.xml; + +import org.w3c.dom.Node; + +import adecWatt.model.Segm; +import adecWatt.model.Permanent; + +public class XmlSegm extends XmlPermanent { + + // ======================================== + public XmlSegm (Node node) { + parseNode (node, Segm.SegmTypeEnum.class, Segm.SegmAttrEnum.class); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/XmlUnit.java b/src/java/adecWatt/model/xml/XmlUnit.java new file mode 100644 index 0000000..15d3c74 --- /dev/null +++ b/src/java/adecWatt/model/xml/XmlUnit.java @@ -0,0 +1,26 @@ +package adecWatt.model.xml; + +import java.util.ArrayList; +import org.w3c.dom.Node; + +import adecWatt.model.Permanent; +import adecWatt.model.Unit; + +/** + */ +public class XmlUnit extends XmlPermanent { + + // ======================================== + //public Unit unit; + + public ArrayList comps = new ArrayList (); + public ArrayList attributes = new ArrayList (); + + // ======================================== + + public XmlUnit (Node xmlUnitNode) { + parseNode (xmlUnitNode, Unit.UnitTypeEnum.class, Unit.UnitAttrEnum.class); + } + + // ======================================== +} diff --git a/src/java/adecWatt/model/xml/package-info.java b/src/java/adecWatt/model/xml/package-info.java new file mode 100644 index 0000000..0a95a8b --- /dev/null +++ b/src/java/adecWatt/model/xml/package-info.java @@ -0,0 +1,10 @@ +/** + * Architecture des classes + * + * XmlPermanent + * XmlProp + * XmlComp + * XmlUnit + * + */ +package adecWatt.model.xml; diff --git a/src/java/adecWatt/view/JAcc.java b/src/java/adecWatt/view/JAcc.java new file mode 100644 index 0000000..36fcfb1 --- /dev/null +++ b/src/java/adecWatt/view/JAcc.java @@ -0,0 +1,123 @@ +package adecWatt.view; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JLabel; +import adecWatt.model.Acc; +import adecWatt.model.Item; + +@SuppressWarnings ("serial") +public class JAcc extends JLabel { + + // ======================================== + protected JWorkspaceView jWorkspaceView; + private Item item; + private Acc acc; + + public Acc getAcc () { return acc; } + public Item getItem () { return item; } + + // ======================================== + public JAcc (JWorkspaceView jWorkspaceView, Item item, Acc acc) { + this.jWorkspaceView = jWorkspaceView; + this.item = item; + this.acc = acc; + setIcon (acc.getModel ().getIcon (16)); + setSize (getPreferredSize ()); + setPos (); + AccMouseAdapter accMouseAdapter = new AccMouseAdapter (); + addMouseListener (accMouseAdapter); + addMouseMotionListener (accMouseAdapter); + } + public void setPos () { + setPos (jWorkspaceView.scaleModelToView (item.getAccCenter (acc.getId ()))); + } + public void setPos (Point pos) { + pos.x -= getWidth ()/2; + pos.y -= getHeight ()/2; + setLocation (pos); + } + + public void setScale () { + // center = new double [] {accPos.x, accPos.y}; + // jComp.getAT ().transform (center, 0, center, 0, 1); + // setLocation ((int) (center[0]+(jComp.getWidth ()-getWidth ())/2), (int) (center[1]+(jComp.getHeight ()-getHeight ())/2)); + // String accConnectedTo = acc.getConnectedTo (); + // if (accConnectedTo != null) + // jComp.addConnectedAcc (acc); + } + + // ======================================== + public class AccMouseAdapter extends MouseAdapter { + public void mousePressed (MouseEvent e) { + jWorkspaceView.mousePressed (e); + } + public void mouseReleased (MouseEvent e) { + jWorkspaceView.mouseReleased (e); + } + public void mouseDragged (MouseEvent e) { + jWorkspaceView.mouseDragged (e); + } + } + + // ======================================== + // JDragUnit selectedJDragAcc; + // Point mousePosOnJDragUnit; + + // public void startDrag (MouseEvent e) { + // JRootPane jRootPane = getRootPane (); + // JLayeredPane jLayeredPane = jRootPane.getLayeredPane (); + // if (selectedJDragAcc != null) + // jLayeredPane.remove (selectedJDragAcc); + // selectedJDragAcc = new JDragUnit (acc.getModel ()); + // mousePosOnJDragUnit = e.getPoint (); + // Point absPos = jRootPane.getMousePosition (true); + // selectedJDragAcc.setLocation (absPos.x-mousePosOnJDragUnit.x, absPos.y-mousePosOnJDragUnit.y); + // jLayeredPane.add (selectedJDragAcc); + // jLayeredPane.setLayer (selectedJDragAcc, JLayeredPane.DRAG_LAYER.intValue ()); + // //repaint (); + // } + + // public void stopDrag (MouseEvent e) { + // if (selectedJDragAcc == null) + // return; + // selectedJDragAcc.setVisible (false); + // selectedJDragAcc.getParent ().remove (selectedJDragAcc); + // // XXX recherche comp et acc + // try { + // AdecWatt adecWatt = jWorkspaceView.getJAdecWatt ().getAdecWatt (); + // // XXX Il peut y en avoir plusieurs + // ArrayList dstComps = jWorkspaceView.findComps (SwingUtilities.convertPoint (this, e.getPoint (), jWorkspaceView)); + // if (dstComps.size () < 1) { + // adecWatt.broadcastDisplay (AdecWattManager.actionRemoveAcc, jWorkspaceView, acc); + // return; + // } + // // XXX + // // PermanentDB permanentDB = adecWatt.getPermanentDB (); + // // JAcc dstJAcc = dstJComp.getJAcc (SwingUtilities.convertPoint (this, e.getPoint (), dstJComp)); + // // if (acc.getDirectUnit ().isDescendingFrom (permanentDB.getPowerPlugId ())) + // // jWorkspaceView.storyConnect (jComp, this, dstJComp, dstJAcc, permanentDB.getPowerSocketId ()); + // } catch (Exception e2) { + // e2.printStackTrace (); + // } + // } + // public void drag (MouseEvent e) { + // if (selectedJDragAcc == null) + // return; + // Point absPos = getRootPane ().getMousePosition (true); + // try { + // selectedJDragAcc.setLocation (absPos.x-mousePosOnJDragUnit.x, absPos.y-mousePosOnJDragUnit.y); + // } catch (Exception e2) { + // } + // } + + // ======================================== + public void dragAcc (Dimension delta) { + Point oldUnitPos = getLocation (); + setLocation (oldUnitPos.x+delta.width, oldUnitPos.y+delta.height); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JAccPopup.java b/src/java/adecWatt/view/JAccPopup.java new file mode 100644 index 0000000..948d4eb --- /dev/null +++ b/src/java/adecWatt/view/JAccPopup.java @@ -0,0 +1,67 @@ +package adecWatt.view; + +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.swing.JPopupMenu; + +import misc.Util; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.Acc; +import adecWatt.model.Item; +import adecWatt.model.AdecWatt; +import adecWatt.model.User; + +@SuppressWarnings ("serial") public class JAccPopup extends JPopupMenu { + + private Acc getLocal (JWorkspaceView jWorkspaceView, Item item, Acc acc) { + // return acc; + item = jWorkspaceView.workspace.getCloseEmbedded (item); + return (Acc) item.getCloseEmbedded (acc); + } + private List getLocal2 (JWorkspaceView jWorkspaceView, Item item, Acc acc) { + ArrayList localSelectedAccs = new ArrayList (1); + localSelectedAccs.add (jWorkspaceView.workspace.getCloseEmbedded (item).getCloseEmbedded (acc)); + return localSelectedAccs; + } + + // ======================================== + public JAccPopup (final JWorkspaceView jWorkspaceView, final Item item, final Acc acc, Point pos) { + final AdecWatt adecWatt = jWorkspaceView.getAdecWatt (); + //Item localItem = jWorkspaceView.workspace.getLocalEmbedded (item.getId ()); + User user = adecWatt.getUser (); + boolean editor = user.isEditor (jWorkspaceView.getWorkspace ()); + final List selectedAccs = Arrays.asList (acc); + + Util.addMenuItem (AdecWattManager.actionDisplayAcc, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionDisplayAcc, selectedAccs); + } + }, this); + if (editor) { + Util.addMenuItem (AdecWattManager.actionModifyAcc, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionModifyAcc, getLocal2 (jWorkspaceView, item, acc)); + } + }, this); + Util.addMenuItem (AdecWattManager.actionTransformAcc, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionTransformAcc, getLocal (jWorkspaceView, item, acc)); + } + }, this); + // if (item != null && item.getLocalEmbedded (acc.getId ()) != null) + // Util.addMenuItem (AdecWattManager.actionRemoveAcc, new ActionListener () { + // public void actionPerformed (ActionEvent e) { + // adecWatt.broadcastDisplay (AdecWattManager.actionRemoveAcc, jWorkspaceView, acc); + // } + // }, this); + } + show (jWorkspaceView, pos.x, pos.y); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JAdecWatt.java b/src/java/adecWatt/view/JAdecWatt.java new file mode 100644 index 0000000..6c0f356 --- /dev/null +++ b/src/java/adecWatt/view/JAdecWatt.java @@ -0,0 +1,510 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.TreeMap; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.JTree; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; + +import misc.Config; +import misc.EasterEgg; +import misc.StateNotifier; +import misc.Util; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.AdecWatt; +import adecWatt.model.ImageDB; +import adecWatt.model.PermanentDB; +import adecWatt.model.Prop; +import adecWatt.model.Unit; +import adecWatt.model.UnitNode; +import adecWatt.model.User; +import adecWatt.model.unit.Accessory; +import adecWatt.model.unit.Building; +import adecWatt.model.unit.Lightplot; +import adecWatt.model.unit.NonWorkspace; +import adecWatt.model.unit.Workspace; +import adecWatt.model.xml.XmlUnit; + +@SuppressWarnings ("serial") public class JAdecWatt extends JPanel { + + static public final int space = 10; + static public final String + BroadcastChangeScale = "ChangeScale", + // BroadcastEditableSelection = "EditableSelection", + BroadcastSelection = "Selection", + BroadcastUnitStory = AdecWatt.BroadcastUnitStory, + BroadcastWorkspace = "Workspace"; + + // ======================================== + public StateNotifier stateNotifier = new StateNotifier (); + private AdecWatt adecWatt; + public final Dimension screenSize = Toolkit.getDefaultToolkit ().getScreenSize (); + + private JTabbedPane jTPStorage = new JTabbedPane (); + private JLabel background = new JLabel ("", SwingConstants.CENTER); + private JTabbedPane jTPWorkspace = new JTabbedPane (); + private JTextArea jConsole = new JTextArea (); + private Workspace currentWorkspace; + private Font localFont, normalFont, modifiedFont; + + public AdecWatt getAdecWatt () { return adecWatt; } + + public JWorkspaceView getCurrentJWorkspace () { + try { + return ((JScrollPaneWorkspace) jTPWorkspace.getComponentAt (jTPWorkspace.getSelectedIndex ())).getJWorkspaceView (); + } catch (Exception e) { + return null; + } + } + public JWorkspaceView getJWorkspace (Workspace workspace) { + try { + return (JWorkspaceView) getJScrollPaneWorkspace (workspace).getJWorkspaceView (); + } catch (Exception e) { + return null; + } + } + public Workspace getCurrentWorkspace () { + return currentWorkspace; + } + public void setCurrentWorkspace (Workspace workspace) { + currentWorkspace = workspace; + stateNotifier.broadcastUpdate (BroadcastWorkspace); + adecWatt.broadcastUpdate (AdecWatt.BroadcastTitle); + } + + // ======================================== + public JAdecWatt (AdecWatt adecWatt) { + super (new BorderLayout ()); + this.adecWatt = adecWatt; + normalFont = getFont (); + modifiedFont = normalFont.deriveFont (Font.BOLD, normalFont.getSize ()); + localFont = normalFont.deriveFont (Font.ITALIC, normalFont.getSize ()); + try { + EasterEgg easterEgg = new EasterEgg ("images/adecWatt-anim.gif"); + easterEgg.addPeriode ("1220", "1231", "images/adecWatt-anim-noel.gif"); + easterEgg.addPeriode ("0101", "0115", "images/adecWatt-anim-noel.gif"); + easterEgg.addPeriode ("0517", "0527", "images/2017-festival-adec56.png"); + easterEgg.addPeriode ("0505", "0516", "images/2017-festival-adec56.gif"); + background.setIcon (Util.loadImageIcon (Config.dataDirname, easterEgg.getValue ())); + } catch (Exception e) { + } + background.setLayout (new BorderLayout ()); + background.add (jTPWorkspace, BorderLayout.CENTER); + jConsole.setPreferredSize (new Dimension (400, 50)); + JSplitPane tmp = Util.getJSplitPane (JSplitPane.VERTICAL_SPLIT, background, Util.getJScrollPane (jConsole)); + tmp.setResizeWeight (1); + add (Util.getJSplitPane (JSplitPane.HORIZONTAL_SPLIT, jTPStorage, tmp), BorderLayout.CENTER); + adecWatt.addUpdateObserver (this, AdecWatt.BroadcastUnitRoots); + adecWatt.addMsgObserver (this, AdecWatt.BroadcastConsole, AdecWatt.BroadcastUpdateWorkspace, AdecWatt.BroadcastUpdateUnitTree); + updateUnitRoots (); + + jTPWorkspace.addChangeListener (new ChangeListener () { + public void stateChanged (ChangeEvent e) { + try { + setCurrentWorkspace (((JScrollPaneWorkspace) jTPWorkspace.getSelectedComponent ()).getWorkspace ()); + } catch (Exception e2) { + } + } + }); + + jTPWorkspace.addMouseListener (new MouseAdapter () { + public void mousePressed (MouseEvent e) { + int idx = jTPWorkspace.indexAtLocation (e.getX (), e.getY ()); + if (idx < 0) { + stateNotifier.broadcastDisplay (BroadcastUnitStory, currentWorkspace); + return; + } + stateNotifier.broadcastDisplay (BroadcastUnitStory, ((JScrollPaneWorkspace) jTPWorkspace.getComponentAt (idx)).getWorkspace ()); + // if (idx < 0 || !SwingUtilities.isRightMouseButton (e)) + // return; + // JPopupMenu jPopupMenu = new JPopupMenu (); + // Util.addMenuItem ("CloseWorkspace", jPopupMenu, new ActionListener () { + // public void actionPerformed (ActionEvent e) { + // jTPWorkspace.remove (idx); + // } + // }); + // jPopupMenu.show (jTPWorkspace, e.getX (), e.getY ()); + } + }); + } + + // ======================================== + public void closeWorkspaces () { + jTPWorkspace.removeAll (); + stateNotifier.broadcastUpdate (BroadcastWorkspace); + } + public void closeWorkspace (Workspace workspace) { + JScrollPaneWorkspace jScrollPaneWorkspace = getJScrollPaneWorkspace (workspace); + if (jScrollPaneWorkspace == null) + return; + jTPWorkspace.remove (jScrollPaneWorkspace); + stateNotifier.broadcastUpdate (BroadcastWorkspace); + } + public void closeCurrentWorkspace () { + jTPWorkspace.remove (jTPWorkspace.getSelectedComponent()); + stateNotifier.broadcastUpdate (BroadcastWorkspace); + } + + public void searchUnit (String text) { + for (Unit rootUnit : allJTree.keySet ()) { + JTree jTree = allJTree.get (rootUnit); + jTree.clearSelection (); + if (text == null || text.isEmpty ()) { + for (int row = jTree.getRowCount ()-1; row > 0; row--) + jTree.collapseRow (row); + jTree.expandRow (0); + jTree.scrollPathToVisible (rootUnit.getPath ()); + continue; + } + for (int row = jTree.getRowCount ()-1; row > 0; row--) + jTree.collapseRow (row); + for (Unit unit : rootUnit.search (text)) { + TreePath path = unit.getPath (); + jTree.expandPath (path); + jTree.addSelectionPath (path); + jTree.scrollPathToVisible (path); + } + } + } + + public void searchComp (String text) { + for (int i = 0; i < jTPWorkspace.getTabCount (); i++) + ((JScrollPaneWorkspace) jTPWorkspace.getComponentAt (i)).getJWorkspaceView ().setSelectedItemsBySearch (text); + } + + // ======================================== + public void displayOrModify (Unit unit) { + adecWatt.broadcastDisplay (adecWatt.getUser ().isEditor (unit) ? AdecWattManager.actionModifyUnit : AdecWattManager.actionDisplayUnit, + Arrays.asList (unit)); + } + Hashtable, JTree> allJTree = new Hashtable, JTree> (); + public void updateUnitRoots () { + closeWorkspaces (); + jTPStorage.removeAll (); + allJTree.clear (); + Hashtable> namedRoots = adecWatt.getNamedRoots (); + TreeMap> sortedRoots = new TreeMap> (); + JScrollPane selectedStorage = null; + for (Unit unit : namedRoots.values ()) + sortedRoots.put (unit.getLocalName (), unit); + for (String localName : sortedRoots.descendingKeySet ()) { + Unit unit = sortedRoots.get (localName); + final JTree jTree = new JTree (unit.getUnitNode (), false); + allJTree.put (unit, jTree); + jTree.setCellRenderer (xmlTreeRenderer); + jTree.setToggleClickCount (0); + jTree.setFocusable (false); + JScrollPane currentStorage = Util.getJScrollPane (jTree); + jTPStorage.add (localName, currentStorage); + if (Prop.PropBuilding.equals (unit.getName ())) + selectedStorage = currentStorage; + jTree.addMouseListener (new MouseAdapter () { + public void mousePressed (MouseEvent e) { + int selRow = jTree.getRowForLocation (e.getX (), e.getY ()); + if (selRow < 0) { + // stateNotifier.broadcastDisplay (BroadcastEditableSelection, (Unit) null); + return; + } + TreePath selPath = jTree.getPathForLocation (e.getX (), e.getY ()); + Unit unit = ((UnitNode) selPath.getLastPathComponent ()).getUnit (); + // stateNotifier.broadcastDisplay (BroadcastEditableSelection, unit); + stateNotifier.broadcastDisplay (BroadcastUnitStory, unit); + if (e.getClickCount() == 2) { + e.consume (); + switch (unit.getTypeToken ()) { + case Furniture: + case Information: + case Line: + case Accessory: + displayOrModify (unit); + return; + default: + break; + } + if (unit.isUncompleted (null) || isWorkspaceContains (unit, true)) { + displayOrModify (unit); + return; + } + addWorkspace ((Workspace) unit); + return; + } + if (SwingUtilities.isRightMouseButton (e)) { + new JUnitPopup (adecWatt, jTree, unit, e.getPoint ()); + return; + } + Point rowLocation = jTree.getRowBounds (selRow).getLocation (); + //e.consume (); + User user = adecWatt.getUser (); + if (!(user.isDataStructuresManager () || user.isEditor (unit)) && unit.isUncompleted (null)) + return; + startDragJDragUnit (new JDragUnit (unit), e, rowLocation); + } + public void mouseReleased (MouseEvent e) { + stopJDragUnit (e); + } + }); + jTree.addMouseMotionListener (new MouseAdapter () { + public void mouseDragged (MouseEvent e) { + dragJDragUnit (e); + } + }); + } + try { + jTPStorage.setSelectedComponent (selectedStorage); + } catch (Exception e) { + } + } + + // ======================================== + DefaultTreeCellRenderer xmlTreeRenderer = new DefaultTreeCellRenderer () { + public Component getTreeCellRendererComponent (JTree tree, Object value, + boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent (tree, value, selected, expanded, leaf, row, hasFocus); + Unit unit = ((UnitNode) value).getUnit (); + setFont (unit.story.isModified () ? modifiedFont : (unit.getRemote () ? normalFont : localFont)); + setText (unit.getLocalName ()); + setIcon (unit.getIcon (16)); + return this; + } + }; + + public void updateUnit (Unit unit, boolean structChange) { + try { + DefaultTreeModel model = (DefaultTreeModel) allJTree.get (unit.getUnitRoot ()).getModel(); + if (structChange) + model.nodeStructureChanged (unit.getUnitNode ()); + else + model.nodeChanged (unit.getUnitNode ()); + } catch (Exception e) { + } + } + + + // ======================================== + public void addWorkspace (Workspace workspace) { + if (isWorkspaceContains (workspace, true)) + return; + JScrollPaneWorkspace jScrollPaneWorkspace = new JScrollPaneWorkspace (JWorkspaceView.getInstance (this, workspace)); + jTPWorkspace.addTab (workspace.toString (), workspace.getIcon (16), jScrollPaneWorkspace); + jTPWorkspace.setSelectedComponent (jScrollPaneWorkspace); + stateNotifier.broadcastUpdate (BroadcastWorkspace); + } + public boolean hasWorkspace () { + return jTPWorkspace.getTabCount () > 0; + } + public JScrollPaneWorkspace getJScrollPaneWorkspace (Unit unit) { + for (int i = 0; i < jTPWorkspace.getTabCount (); i++) { + JScrollPaneWorkspace jScrollPaneWorkspace = (JScrollPaneWorkspace) jTPWorkspace.getComponentAt (i); + if (jScrollPaneWorkspace.getWorkspace () == unit) + return jScrollPaneWorkspace; + } + return null; + } + public boolean isWorkspaceContains (Unit unit, boolean select) { + JScrollPaneWorkspace jScrollPaneWorkspace = getJScrollPaneWorkspace (unit); + if (jScrollPaneWorkspace == null) + return false; + if (select) + jTPWorkspace.setSelectedComponent (jScrollPaneWorkspace); + return true; + } + + // ======================================== + JDragUnit selectedJDragUnit; + Point mousePosOnJDragUnit; + public void startDragJDragUnit (JDragUnit jDragUnit, MouseEvent e, Point rowLocation) { + mousePosOnJDragUnit = e.getPoint (); + mousePosOnJDragUnit.translate (-rowLocation.x, -rowLocation.y); + jDragUnit.setBackground (Color.lightGray); + JRootPane jRootPane = getRootPane (); + Point absPos = jRootPane.getMousePosition (true); + jDragUnit.setLocation (absPos.x-mousePosOnJDragUnit.x, absPos.y-mousePosOnJDragUnit.y); + JLayeredPane jLayeredPane = jRootPane.getLayeredPane (); + if (selectedJDragUnit != null) + jLayeredPane.remove (selectedJDragUnit); + selectedJDragUnit = jDragUnit; + jLayeredPane.add (jDragUnit); + jLayeredPane.setLayer (jDragUnit, JLayeredPane.DRAG_LAYER.intValue ()); + repaint (); + } + + public void dragJDragUnit (MouseEvent e) { + if (selectedJDragUnit == null) + return; + Point absPos = getRootPane ().getMousePosition (true); + try { + selectedJDragUnit.setLocation (absPos.x-mousePosOnJDragUnit.x, absPos.y-mousePosOnJDragUnit.y); + } catch (Exception e2) { + } + } + + public void stopJDragUnit (MouseEvent e) { + if (selectedJDragUnit == null) + return; + //selectedJDragUnit.setBackground (UIManager.getColor ("Panel.background")); + selectedJDragUnit.setVisible (false); + selectedJDragUnit.getParent ().remove (selectedJDragUnit); + boolean inWorkspace = false; + JWorkspaceView jWorkspaceView = null; + JTree jTree = null; + try { + for (Component + component = findComponentAt (getMousePosition (true)), + parent = null; + component != null; + component = parent) { + parent = component.getParent (); + if (component == jTPWorkspace) { + inWorkspace = true; + break; + } + if (component instanceof JTree) { + jTree = (JTree) component; + break; + } + if (component instanceof JWorkspaceView) { + jWorkspaceView = (JWorkspaceView) component; + break; + } + } + } catch (Exception e2) { + } + Unit src = selectedJDragUnit.unit; + selectedJDragUnit = null; + if (jTree != null) + dropInJTree (src, jTree, e); + else if (src.isUncompleted (null)) + ; + else if (jWorkspaceView != null) + dropInWorkspace (src, jWorkspaceView); + else if (inWorkspace) + dropInEmptySpace (src); + repaint (); + } + private void dropInJTree (Unit src, JTree jTree, MouseEvent e) { + User user = adecWatt.getUser (); + if (!(user.isDataStructuresManager () || user.isEditor (src))) + return; + int selRow = jTree.getRowForLocation (e.getX (), e.getY ()); + if (selRow < 0) { + // stateNotifier.broadcastDisplay (BroadcastEditableSelection, (Unit) null); + return; + } + TreePath selPath = jTree.getPathForLocation (e.getX (), e.getY ()); + Unit dst = ((UnitNode) selPath.getLastPathComponent ()).getUnit (); + src.storyTransform (null, dst, null, null); + } + private void dropInEmptySpace (Unit src) { + switch (src.getTypeToken ()) { + case Furniture: + case Information: + case Line: + case Accessory: + return; + case Building: + addWorkspace ((Building) src); + break; + case Lightplot: + addWorkspace ((Lightplot) src); + break; + } + } + private void dropInWorkspace (Unit src, JWorkspaceView jWorkspaceView) { + Unit dst = jWorkspaceView.workspace; + if (src == dst || src.isUncompleted (null)) + return; + if (src instanceof NonWorkspace && + !adecWatt.getUser ().isEditor (dst)) + return; + switch (src.getTypeToken ()) { + case Furniture: + case Information: + jWorkspaceView.dropComp ((NonWorkspace) src, jWorkspaceView.getMousePosition (true)); + return; + case Line: + jWorkspaceView.dropSegm ((NonWorkspace) src, jWorkspaceView.getMousePosition (true)); + return; + case Accessory: + jWorkspaceView.dropAcc ((Accessory) src, jWorkspaceView.getMousePosition (true)); + return; + case Building: + if (dst.getTypeToken () == Unit.UnitTypeEnum.Lightplot && + adecWatt.getUser ().isEditor (dst)) { + ((Lightplot) dst).storyChangeBuilding ((Building) src); + break; + } + addWorkspace ((Building) src); + break; + case Lightplot: + if (dst.getTypeToken () == Unit.UnitTypeEnum.Building && + adecWatt.getUser ().isEditor (src)) { + if (!isWorkspaceContains (src, true)) + addWorkspace ((Lightplot) src); + ((Lightplot) src).storyChangeBuilding ((Building) dst); + break; + } + addWorkspace ((Lightplot) src); + break; + } + } + + // ======================================== + public void displayUpdateUnitTree (Object... objects) { + Unit unit = (Unit) objects[0]; + updateUnit (unit, true); + } + public void displayUpdateWorkspace (Object... objects) { + Workspace workspace = (Workspace) objects[0]; + JScrollPaneWorkspace jScrollPaneWorkspace = getJScrollPaneWorkspace (workspace); + if (jScrollPaneWorkspace == null) + return; + Workspace currentWorkspace = this.currentWorkspace; + closeWorkspace (workspace); + addWorkspace (workspace); + setCurrentWorkspace (currentWorkspace); + } + + public void displayConsole (Object... objects) { + synchronized (jConsole) { + jConsole.invalidate (); + String message = (String) objects[0]; + jConsole.append (message); + jConsole.validate (); + jConsole.repaint (); + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JAdecWattDialog.java b/src/java/adecWatt/view/JAdecWattDialog.java new file mode 100644 index 0000000..cd41da1 --- /dev/null +++ b/src/java/adecWatt/view/JAdecWattDialog.java @@ -0,0 +1,255 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.TreeSet; +import java.util.Vector; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.filechooser.FileNameExtensionFilter; + +import misc.Bundle; +import misc.Config; +import misc.ImagePreview; +import misc.OwnFrame; +import misc.RemoteUpdateManager; +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCNL; + +import adecWatt.model.AdecWatt; +import adecWatt.model.Editable; +import adecWatt.model.PermanentDB; +import adecWatt.model.Unit; +import adecWatt.model.User; +import adecWatt.model.unit.Workspace; + +public class JAdecWattDialog implements SwingConstants { + + // ======================================== + OwnFrame controller; + public OwnFrame getOwnFrame () { return controller; } + public JAdecWattDialog (OwnFrame controller) { + this.controller = controller; + } + + // ======================================== + public void todo () { + JOptionPane.showMessageDialog (controller.getJFrame (), "TODO !\n Oui, cette fonction n'est pas encore r\u00E9alis\u00E9 :-("); + } + public String getSimpleMessage (String msg, String value) { + return JOptionPane.showInputDialog (controller.getJFrame (), msg, value); + } + + // ======================================== + public void magnetPolicies (AdecWatt adecWatt) { + JPanel content = Util.getGridBagPanel (); + JCheckBox jHandleCD = Util.addCheckIcon ("HandleGlue", null, adecWatt.getHandleGlue (), content, GBC); + Util.addLabel ("HandleGlue", LEFT, content, GBCNL); + JCheckBox jBoundCB = Util.addCheckIcon ("BoundGlue", null, adecWatt.getBoundGlue (), content, GBC); + Util.addLabel ("BoundGlue", LEFT, content, GBCNL); + JCheckBox jGridCB = Util.addCheckIcon ("GridGlue", null, adecWatt.getGridGlue (), content, GBC); + Util.addLabel ("GridGlue", LEFT, content, GBCNL); + JCheckBox jInSegCB = Util.addCheckIcon ("InSegmentGlue", null, adecWatt.getInSegmentGlue (), content, GBC); + Util.addLabel ("InSegmentGlue", LEFT, content, GBCNL); + if (JOptionPane.showConfirmDialog (controller.getJFrame (), content, Bundle.getTitle ("MagnetPolicies"), + JOptionPane.YES_NO_OPTION) + != JOptionPane.YES_OPTION) + return; + adecWatt.setHandleGlue (jHandleCD.isSelected ()); + adecWatt.setBoundGlue (jBoundCB.isSelected ()); + adecWatt.setGridGlue (jGridCB.isSelected ()); + adecWatt.setInSegmentGlue (jInSegCB.isSelected ()); + } + + // ======================================== + public void patch (Workspace workspace) { + JPanel content = new JPatch (workspace.getPatch ()); + JDialog jDialog = removeDisplay (workspace); + boolean center = false; + if (jDialog == null) { + center = true; + jDialog = new JDialog (controller.getJFrame (), "Patch "+workspace.getLocalName (), false); + } + Container container = jDialog.getContentPane (); + container.removeAll (); + container.add (content, BorderLayout.CENTER); + addDisplay (workspace, jDialog, center); + } + private Hashtable, JDialog> currentDisplays = new Hashtable, JDialog> (); + public JDialog removeDisplay (Editable editable) { + try { + JDialog jDialog = currentDisplays.get (editable); + jDialog.setVisible (false); + currentDisplays.remove (editable); + return jDialog; + } catch (Exception e) { + return null; + } + } + public void removeAllDisplay () { + for (Editable editable : currentDisplays.keySet ()) + currentDisplays.get (editable).setVisible (false); + currentDisplays.clear (); + } + private void addDisplay (final Editable editable, JDialog jDialog, boolean center) { + currentDisplays.put (editable, jDialog); + jDialog.addWindowListener (new WindowAdapter () { + public void windowClosing (WindowEvent e) { + // XXX confirmBundle + removeDisplay (editable); + } + }); + jDialog.pack (); + if (center) + jDialog.setLocation ((int) controller.getJFrame ().getLocation ().getX () - (jDialog.getWidth () - controller.getJFrame ().getWidth ())/2, + (int) controller.getJFrame ().getLocation ().getY () - (jDialog.getHeight() - controller.getJFrame ().getHeight ())/2); + jDialog.setVisible (true); + jDialog.toFront (); + } + public void display (boolean edit, List> editables) { + Editable editable = editables.get (0); + JDialog jDialog = removeDisplay (editable); + JEditable jEditable = new JEditable (editables); + JPanel content = jEditable.getDislay (edit); + if (!edit) { + boolean center = false; + if (jDialog == null) { + center = true; + jDialog = new JDialog (controller.getJFrame (), editable.getLocalName (), false); + } + Container container = jDialog.getContentPane (); + container.removeAll (); + container.add (content, BorderLayout.CENTER); + addDisplay (editable, jDialog, center); + return; + } + if (JOptionPane.showConfirmDialog (controller.getJFrame (), content, Bundle.getTitle ("Edit"), + JOptionPane.YES_NO_OPTION) + != JOptionPane.YES_OPTION) + return; + jEditable.confirmChange (); + jEditable.confirmBundle (); + } + public void transform (Editable editable) { + JTransform jTransform = new JTransform (editable); + for (;;) { + if (JOptionPane.showConfirmDialog (controller.getJFrame (), jTransform, Bundle.getTitle ("Transform"), JOptionPane.YES_NO_OPTION) + != JOptionPane.YES_OPTION) + return; + if (jTransform.valideChange ()) + break; + // XXX message prop en double ou text en cours + } + jTransform.confirmChange (); + } + + // ======================================== + public boolean validation (String message, String name, PermanentDB.UnitLocation location) { + return + JOptionPane.showConfirmDialog (controller.getJFrame (), + MessageFormat.format (Bundle.getMessage (message), name, location), + null, JOptionPane.YES_NO_OPTION) + == JOptionPane.YES_OPTION; + } + + public boolean validation (String message, String name, PermanentDB.UnitLocation location, + HashSet> units, TreeSet icons, TreeSet images) { + JPanel msgPanel = Util.getGridBagPanel (); + Util.addComponent (new JLabel (MessageFormat.format (Bundle.getMessage (message), name, location)), msgPanel, GBCNL); + Util.addLabel ("Units", LEFT, msgPanel, GBC); + Util.addLabel ("Icons", LEFT, msgPanel, GBC); + Util.addLabel ("Images", LEFT, msgPanel, GBCNL); + Vector unitsVector = new Vector (); + for (Unit unit : units) + unitsVector.add (unit.toString ()); + if (icons.size () == 0) + icons = new TreeSet (Arrays.asList (" ")); + if (images.size () == 0) + images = new TreeSet (Arrays.asList (" ")); + Util.addComponent (Util.getJScrollPane (new JList (unitsVector)), msgPanel, GBC); + Util.addComponent (Util.getJScrollPane (new JList (new Vector (icons))), msgPanel, GBC); + Util.addComponent (Util.getJScrollPane (new JList (new Vector (images))), msgPanel, GBCNL); + return + JOptionPane.showConfirmDialog (controller.getJFrame (), msgPanel, null, JOptionPane.YES_NO_OPTION) + == JOptionPane.YES_OPTION; + } + + public String getName (String answer) { + return JOptionPane.showInputDialog (controller.getJFrame (), Bundle.getMessage ("GiveName"), answer); + } + + public Double getSpace () { + String answer = JOptionPane.showInputDialog (controller.getJFrame (), Bundle.getMessage ("GiveSpace"), ""); + if (answer == null) + return -1.; + try { + return Double.parseDouble (answer.replace (",", ".")); + } catch (Exception e) { + return null; + } + } + + public void checkAdmin (User user, RemoteUpdateManager remoteUpdateManager) { + JUser jUser = new JUser (user, remoteUpdateManager); + switch (JOptionPane.showConfirmDialog (controller.getJFrame (), jUser, Bundle.getTitle ("ChangeRole"), + JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE)) { + case JOptionPane.YES_OPTION: + jUser.confirm (); + return; + case JOptionPane.NO_OPTION: + return; + } + } + + public boolean abortModification () { + return JOptionPane.showConfirmDialog (controller.getJFrame (), Bundle.getMessage ("QuitJAdecWatt"), + Bundle.getTitle ("AdecWattStillRunning"), + JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION; + } + + // ======================================== + public File getChooseOpenFile (File lastFile) { + JFileChooser jFileChooser = new JFileChooser (Config.getString ("ExportDirName", "data/export")); + jFileChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("ExportFilter"), PermanentDB.exportExtention)); + jFileChooser.setFileSelectionMode (JFileChooser.FILES_ONLY); + jFileChooser.setAccessory (new ImagePreview (jFileChooser, 1024*1024)); + if (lastFile != null) + jFileChooser.setSelectedFile (lastFile); + if (jFileChooser.showOpenDialog (controller.getJFrame ()) != JFileChooser.APPROVE_OPTION) + return null; + File file = jFileChooser.getSelectedFile (); + Config.setFile ("ExportDirName", file.getParentFile ()); + return file; + } + + public File getChooseSaveFile (File lastFile) { + JFileChooser jFileChooser = new JFileChooser (Config.getString ("ExportDirName", "data/export")); + jFileChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("ExportFilter"), PermanentDB.exportExtention)); + jFileChooser.setFileSelectionMode (JFileChooser.FILES_ONLY); + jFileChooser.setAccessory (new ImagePreview (jFileChooser, 1024*1024)); + if (lastFile != null) + jFileChooser.setSelectedFile (lastFile); + if (jFileChooser.showSaveDialog (controller.getJFrame ()) != JFileChooser.APPROVE_OPTION) + return null; + File file = jFileChooser.getSelectedFile (); + Config.setFile ("ExportDirName", file.getParentFile ()); + return file; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JAdecWattMenuBar.java b/src/java/adecWatt/view/JAdecWattMenuBar.java new file mode 100644 index 0000000..bf33621 --- /dev/null +++ b/src/java/adecWatt/view/JAdecWattMenuBar.java @@ -0,0 +1,67 @@ +package adecWatt.view; + +import java.util.Hashtable; +import javax.swing.AbstractButton; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JMenu; +import javax.swing.JMenuBar; + +import misc.ApplicationManager; +import misc.ToolBarManager; +import misc.Util; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.User; + +@SuppressWarnings ("serial") public class JAdecWattMenuBar extends JMenuBar { + + JMenu editMenu, placementMenu, yodaMenu; + + // ======================================== + public JAdecWattMenuBar (ApplicationManager controllerManager, ApplicationManager adecWattManager, ApplicationManager storyManager, + ApplicationManager proxyManager, ApplicationManager remoteUpdateManager, ApplicationManager helpManager, + ToolBarManager toolBarManager) { + setLayout (new BoxLayout (this, BoxLayout.X_AXIS)); + JMenu fileMenu = Util.addJMenu (this, "File"); + editMenu = Util.addJMenu (this, "Edit"); + placementMenu = Util.addJMenu (this, "Placement"); + yodaMenu = Util.addJMenu (this, "Yoda"); + add (Box.createHorizontalGlue ()); + JMenu helpMenu = Util.addJMenu (this, "Help"); + + storyManager.addMenuItem (editMenu); + adecWattManager.addMenuItem (fileMenu, editMenu, placementMenu, yodaMenu, helpMenu); + controllerManager.addMenuItem (fileMenu); + proxyManager.addMenuItem (helpMenu); + remoteUpdateManager.addMenuItem (helpMenu); + helpManager.addMenuItem (helpMenu); + toolBarManager.addMenuItem (helpMenu); + + Hashtable buttons = new Hashtable (); + Util.collectButtons (buttons, fileMenu); + Util.collectButtons (buttons, editMenu); + Util.collectButtons (buttons, placementMenu); + Util.collectButtons (buttons, helpMenu); + + controllerManager.addActiveButtons (buttons); + adecWattManager.addActiveButtons (buttons); + storyManager.addActiveButtons (buttons); + proxyManager.addActiveButtons (buttons); + remoteUpdateManager.addActiveButtons (buttons); + helpManager.addActiveButtons (buttons); + toolBarManager.addActiveButtons (buttons); + + Util.setAccelerator (buttons, AdecWattManager.actionsControl); + } + + public void changeProfil (User user) { + boolean editor = user.isEditor (); + editMenu.setVisible (editor); + placementMenu.setVisible (editor); + yodaMenu.setVisible (user.isAdmin ()); + } + + // ======================================== +} + diff --git a/src/java/adecWatt/view/JAdecWattSearchToolBar.java b/src/java/adecWatt/view/JAdecWattSearchToolBar.java new file mode 100644 index 0000000..a560ee2 --- /dev/null +++ b/src/java/adecWatt/view/JAdecWattSearchToolBar.java @@ -0,0 +1,44 @@ +package adecWatt.view; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JTextField; +import javax.swing.JToolBar; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import misc.Util; + +@SuppressWarnings ("serial") public class JAdecWattSearchToolBar extends JToolBar implements ActionListener { + + JTextField searchTF = new JTextField (8); + + public JAdecWattSearchToolBar (final JAdecWatt jAdecWatt) { + super ("Search"); + searchTF.getDocument ().addDocumentListener (new DocumentListener () { + public void changedUpdate (DocumentEvent e) { + String search = Util.removeAccent (searchTF.getText ()).toLowerCase (); + jAdecWatt.searchUnit (search); + jAdecWatt.searchComp (search); + } + public void insertUpdate (DocumentEvent e) { changedUpdate (e); } + public void removeUpdate (DocumentEvent e) { changedUpdate (e); } + }); + // JPanel jPanel = new JPanel (new BorderLayout ()); + // jPanel.add (Util.newIconButton ("Find", this), BorderLayout.WEST); + // jPanel.add (searchTF, BorderLayout.CENTER); + // Util.unBoxButton (jPanel); + // add (jPanel, BorderLayout.NORTH); + + add (Util.newIconButton ("Search", this)); + add (searchTF); + //Util.unBoxButton (jPanel); + } + + public void setOrientation (int o) { + super.setOrientation (HORIZONTAL); + } + public void actionPerformed (ActionEvent e) { + // XXX + } +} diff --git a/src/java/adecWatt/view/JAdecWattToolBar.java b/src/java/adecWatt/view/JAdecWattToolBar.java new file mode 100644 index 0000000..9758b6e --- /dev/null +++ b/src/java/adecWatt/view/JAdecWattToolBar.java @@ -0,0 +1,64 @@ +package adecWatt.view; + +import java.util.Hashtable; +import javax.swing.AbstractButton; +import javax.swing.JToolBar; + +import misc.ApplicationManager; +import misc.ToolBarManager; +import misc.Util; + +import adecWatt.model.User; + +public class JAdecWattToolBar { + + JToolBar editToolBar; + JToolBar placementToolBar; + + // ======================================== + static public final String defaultCardinalPoint = "North"; + + public JAdecWattToolBar (ApplicationManager controllerManager, ApplicationManager adecWattManager, ApplicationManager storyManager, + ApplicationManager proxyManager, ApplicationManager remoteUpdateManager, ApplicationManager helpManager, + ToolBarManager toolBarManager, JToolBar searchToolBar, JToolBar slidersToolBar) { + + JToolBar fileToolBar = toolBarManager.newJToolBar ("File", defaultCardinalPoint); + editToolBar = toolBarManager.newJToolBar ("Edit", defaultCardinalPoint); + placementToolBar = toolBarManager.newJToolBar ("Placement", defaultCardinalPoint); + toolBarManager.add (searchToolBar, defaultCardinalPoint); + toolBarManager.add (slidersToolBar, defaultCardinalPoint); + JToolBar helpToolBar = toolBarManager.newJToolBar ("Help", defaultCardinalPoint); + + controllerManager.addIconButtons (fileToolBar); + storyManager.addIconButtons (editToolBar); + adecWattManager.addIconButtons (fileToolBar, editToolBar, placementToolBar, searchToolBar, slidersToolBar, helpToolBar); + proxyManager.addIconButtons (helpToolBar); + remoteUpdateManager.addIconButtons (helpToolBar); + helpManager.addIconButtons (helpToolBar); + toolBarManager.addIconButtons (helpToolBar); + + Hashtable buttons = new Hashtable (); + Util.collectButtons (buttons, fileToolBar); + Util.collectButtons (buttons, editToolBar); + Util.collectButtons (buttons, placementToolBar); + Util.collectButtons (buttons, searchToolBar); + Util.collectButtons (buttons, slidersToolBar); + Util.collectButtons (buttons, helpToolBar); + + controllerManager.addActiveButtons (buttons); + adecWattManager.addActiveButtons (buttons); + storyManager.addActiveButtons (buttons); + proxyManager.addActiveButtons (buttons); + remoteUpdateManager.addActiveButtons (buttons); + helpManager.addActiveButtons (buttons); + toolBarManager.addActiveButtons (buttons); + } + + public void changeProfil (User user) { + boolean editor = user.isEditor (); + editToolBar.setVisible (editor); + placementToolBar.setVisible (editor); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JBuildingView.java b/src/java/adecWatt/view/JBuildingView.java new file mode 100644 index 0000000..6249f23 --- /dev/null +++ b/src/java/adecWatt/view/JBuildingView.java @@ -0,0 +1,13 @@ +package adecWatt.view; + +import adecWatt.model.unit.Building; + +@SuppressWarnings ("serial") public class JBuildingView extends JWorkspaceView { + + // ======================================== + public JBuildingView (JAdecWatt jAdecWatt, Building building) { + super (jAdecWatt, building); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JComp.java b/src/java/adecWatt/view/JComp.java new file mode 100644 index 0000000..068f2b3 --- /dev/null +++ b/src/java/adecWatt/view/JComp.java @@ -0,0 +1,76 @@ +package adecWatt.view; + +//import javax.swing.UIManager; +import java.awt.Color; +import java.awt.Dimension; +import misc.ScaledImage; + +import adecWatt.model.AdecWatt; +import adecWatt.model.Comp; +import adecWatt.model.Item; + +@SuppressWarnings ("serial") public class JComp extends JItem { + + // ======================================== + public Comp comp; + + protected boolean isLow; + protected ScaledImage scaledImage; + protected Dimension tile = ScaledImage.ONE_TILE; + //protected JLabel jLabel; + + public Item getItem () { return comp; } + public boolean isLow () { return isLow; } + public ScaledImage getScaledImage () { return scaledImage; } + + // ======================================== + public JComp (JWorkspaceView jWorkspaceView, Comp comp) { + super (jWorkspaceView, comp); + } + + // ======================================== + public void setItem (Item item) { + if (item == null) + return; + comp = (Comp) item; + scaledImage = comp.getIcon (); + setCurrentThetaDegree (comp.getThetaDegree ()); + updateLevel (); + setCurrentSize (); + setCurrentPos (); + } + + // ======================================== + public void setScale () { + tile = Comp.getTile (comp.getTileSize (), comp.getSize ()); + super.setScale (); + } + + // ======================================== + public void updateLevel () { + if (comp.getLevel () <= AdecWatt.lowLevel == isLow) + return; + isLow = ! isLow; + if (!isLow) { + scaledImage = comp.getIcon (); + return; + } + ScaledImage scaledLowImage = comp.getLowIcon (); + if (scaledLowImage != null) + scaledImage = scaledLowImage; + Color compColor = comp.getColor (); + if (compColor != null) + scaledImage = comp.getAdecWatt ().getIconDB ().getColoredScaledImages (scaledImage, compColor); + } + + // ======================================== + public void updateIcon () { + if (currentPos == null || currentSize == null) + return; + tile = Comp.getTile (comp.getTileSize (), currentSize); + updateLevel (); + super.updateIcon (); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JDefLabel.java b/src/java/adecWatt/view/JDefLabel.java new file mode 100644 index 0000000..f5e5311 --- /dev/null +++ b/src/java/adecWatt/view/JDefLabel.java @@ -0,0 +1,41 @@ +package adecWatt.view; + +import java.util.List; +import java.util.Vector; +import javax.swing.JPanel; +import javax.swing.JTextField; + +@SuppressWarnings ("serial") +public class JDefLabel extends JPanel { + + private Vector refList = new Vector (); + private Vector list = new Vector (); + private JTextField[] labels; + + public List getLabels () { + if (refList.size () < 1) + return null; + return refList; + } + + public JDefLabel (List multiLabel) { + if (multiLabel == null) + return; + refList = new Vector (multiLabel); + } + public void initLabels (int nbLabel) { + removeAll (); + labels = new JTextField[nbLabel]; + for (int i = 0; i < nbLabel; i++) { + String ref = refList != null && refList.size () > i ? refList.get (i) : null; + add (labels[i] = new JTextField (ref, 8)); + } + } + public void confirmLabels () { + refList.clear (); + if (labels == null) + return; + for (JTextField label : labels) + refList.add (label.getText ()); + } +} diff --git a/src/java/adecWatt/view/JDefPropTable.java b/src/java/adecWatt/view/JDefPropTable.java new file mode 100644 index 0000000..c4c48a9 --- /dev/null +++ b/src/java/adecWatt/view/JDefPropTable.java @@ -0,0 +1,409 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +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.Collection; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; +import javax.swing.AbstractButton; +import javax.swing.DefaultCellEditor; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.event.ListSelectionEvent; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +import misc.Bundle; +import misc.Util; + +import adecWatt.model.Editable; +import adecWatt.model.Permanent; +import adecWatt.model.Prop; +import adecWatt.model.Unit; + +@SuppressWarnings ("serial") public class JDefPropTable extends JPanel implements ActionListener { + // ======================================== + static public final String + actionUp = "Up", + actionDown = "Down", + actionSetEnum = "SetEnum", + actionAdd = "Add", + actionRemove = "Remove"; + + static public final List + leftDefPropActionsNames = Arrays.asList (actionUp, actionDown, actionSetEnum, actionAdd), + rightDefPropActionsNames = Arrays.asList (actionRemove); + + @SuppressWarnings ("unchecked") + static public final Hashtable actionsMethod = + Util.collectMethod (JDefPropTable.class, + leftDefPropActionsNames, rightDefPropActionsNames); + + public void actionPerformed (ActionEvent e) { + Util.actionPerformed (actionsMethod, e, this); + } + + // ======================================== + public class PropShadow { + String propName; + Prop prop; + Collection oldModifiers; + Collection parentModifiers; + ArrayList jModifiers; + JComboBox jType; + JStringSet jStringSet; + JDefLabel jDefLabel; + + public PropShadow (String propName, Prop prop, Collection parentModifiers) { + this.propName = propName; + this.prop = prop; + this.oldModifiers = prop == null ? null : prop.getModifiers (); + if (parentModifiers != null && parentModifiers.size () > 0) + this.parentModifiers = parentModifiers; + jType = Util.newEnum (Prop.PropTypeEnum.class, Prop.PropTypeEnum.Text); + if (prop != null) { + oldModifiers = prop.getModifiers (); + jType.setSelectedIndex (prop.getTypeToken ().ordinal ()); + } else { + try { + Unit parent = jTransform.getPermanent ().getDirectUnit (); + oldModifiers = parent.getPropModifiers (propName); + jType.setSelectedIndex (parent.getProp (propName).getTypeToken ().ordinal ()); + } catch (Exception e) { + } + } + jModifiers = JTransform.getJModifiers (modifiersSet, oldModifiers, jTransform.isLock (propName) && !admin); + jStringSet = new JStringSet (prop == null ? null : prop.enumChoice); + jDefLabel = new JDefLabel (prop == null ? null : prop.multiLabel); + } + public Collection getModifiers () { + Collection modifiers = JTransform.getModifiers (jModifiers, oldModifiers, admin, Permanent.PropHiddenModifiersSet); + if (modifiers == null || parentModifiers == null) + return modifiers; + if (Permanent.getModifiersString (parentModifiers).equals (Permanent.getModifiersString (modifiers))) + return null; + return modifiers; + } + } + + // ======================================== + private String[] tabExtraNames = { Bundle.getLabel ("Type"), Bundle.getLabel ("Property") }; + private JTransform jTransform; + private Vector objectData = new Vector (); + private JTable jTableObject; + private JScrollPane jScrollPane; + private JButton setEnum; + public JTextField jNewPropName = new JTextField (16); + private boolean admin; + private Collection modifiersSet; + private int modifiersSetSize; + private TableObjectModel dataObjectModel; + + public Vector getObjectData () { return objectData; } + //public TableObjectModel getDataObjectModel () { return dataObjectModel; } + + // ======================================== + public JDefPropTable (JTransform jTransform, Editable editable) { + super (new BorderLayout ()); + this.jTransform = jTransform; + admin = jTransform.isAdmin (); + modifiersSet = admin ? Permanent.PropModifiersSet : Permanent.PropNotHiddenModifiersSet; + modifiersSetSize = modifiersSet.size (); + dataObjectModel = new TableObjectModel (); + + for (Prop prop : editable.getOrderedOwnProps ()) { + if (editable.getParentProp (prop.getName ()) != null && + prop.enumChoice == null && (prop.getModifiers () == null || + prop.getModifiersString ().equals (Prop.getModifiersString + (editable.getParentPropModifiers (prop.getName ()))))) + continue; + // XXX 2 fois editable.getParentPropModifiers (prop.getName () + Collection parentModifiers = editable.getParentPropModifiers (prop.getName ()); + objectData.add (new PropShadow (prop.getName (), prop, parentModifiers)); + } + jTableObject = new JTable (dataObjectModel) { + public void valueChanged (ListSelectionEvent e) { + super.valueChanged (e); + int idx = jTableObject.getSelectedRow (); + updateSetEnum (idx < 0 ? null : objectData.elementAt (idx)); + } + }; + jTableObject.getTableHeader ().setReorderingAllowed (true); + jTableObject.setShowHorizontalLines (false); + jTableObject.setShowVerticalLines (false); + jTableObject.setRowSelectionAllowed (true); + jTableObject.setColumnSelectionAllowed (false); + // jTableObject.setIntercellSpacing(new Dimension(spacing, spacing)); + jTableObject.setRowHeight (24); + jTableObject.setSelectionMode (0); + //jTableObject.setAutoResizeMode (0); + int columnIdx = 0; + for (String modifier : modifiersSet) { + CheckIconEditorRenderer editor = new CheckIconEditorRenderer (modifier); + TableColumn tableColumn = jTableObject.getColumnModel ().getColumn (columnIdx); + tableColumn.setCellRenderer (editor); + tableColumn.setCellEditor (editor); + tableColumn.setMaxWidth (24); + columnIdx++; + } + EnumEditorRenderer enumEditor = new EnumEditorRenderer (Prop.PropTypeEnum.class); + TableColumn tableColumn = jTableObject.getColumnModel ().getColumn (columnIdx); + tableColumn.setCellRenderer (enumEditor); + tableColumn.setCellEditor (enumEditor); + + add (jScrollPane = Util.getJScrollPane (jTableObject), BorderLayout.CENTER); + dataObjectModel.revalidate (-1); + + // command panel + JPanel propCmdPanel = new JPanel (new BorderLayout ()); + JPanel leftPropCmdPanel = new JPanel (); + Util.addIconButton (leftDefPropActionsNames, this, leftPropCmdPanel); + propCmdPanel.add (leftPropCmdPanel, BorderLayout.WEST); + propCmdPanel.add (jNewPropName, BorderLayout.CENTER); + propCmdPanel.add (Util.newIconButton (actionRemove, this), BorderLayout.EAST); + add (propCmdPanel, BorderLayout.SOUTH); + + Hashtable buttons = Util.collectButtons (null, leftPropCmdPanel); + Util.collectButtons (buttons, propCmdPanel); + for (AbstractButton button : buttons.values ()) + Util.unBoxButton (button); + setEnum = (JButton) buttons.get (actionSetEnum); + updateSetEnum (null); + } + + // ======================================== + public class TableObjectModel extends AbstractTableModel { + public int getColumnCount () { + return modifiersSetSize+tabExtraNames.length; + } + public int getRowCount () { + return objectData.size (); + } + public Object getValueAt (int row, int column) { + if (row >= objectData.size ()) + return null; + PropShadow prop = objectData.elementAt (row); + if (column < modifiersSetSize) + return prop.jModifiers.get (column); + switch (column-modifiersSetSize) { + case 0: return prop.jType; + case 1: return prop.propName; + } + return null; + } + public String getColumnName (int column) { + if (column < modifiersSetSize) + return ""; //modifiersSet.get (column); + return tabExtraNames[column-modifiersSetSize]; + } + public Class getColumnClass (int column) { + if (column < modifiersSetSize) + return JCheckBox.class; + switch (column-modifiersSetSize) { + case 0: return JComboBox.class; + case 1: return String.class; + } + throw new IllegalArgumentException ("Column 0 >= "+column+" > "+(modifiersSetSize+2)); + } + public boolean isCellEditable (int row, int column) { + PropShadow prop = objectData.elementAt (row); + if (prop == null) + return false; + return !jTransform.isLock (prop.propName) || admin; + } + public void setValueAt (Object aValue, int row, int column) { + PropShadow prop = objectData.elementAt (row); + if (column < modifiersSetSize) { + prop.jModifiers.get (column).setSelected ((Boolean) aValue); + return; + } + switch (column-modifiersSetSize) { + case 0: + prop.jType.setSelectedItem ((String) aValue); + updateSetEnum (prop); + return; + case 1: + prop.propName = (String) aValue; + return; + } + } + public void revalidate (int idx) { + if (jTableObject == null) + return; + jTableObject.revalidate (); + jTableObject.getSelectionModel ().clearSelection (); + Dimension preferredSize = new Dimension (jTableObject.getPreferredSize ()); + preferredSize.height += 40; + jScrollPane.setPreferredSize (preferredSize); + Util.packWindow (jScrollPane); + if (idx < 0) + return; + jTableObject.getSelectionModel ().setLeadSelectionIndex (idx); + } + public boolean contains (String propName) { + for (PropShadow prop : objectData) + if (prop.propName.equals (propName)) + return true; + return false; + } + public void addRow (String propName) { + objectData.add (new PropShadow (propName, null, null)); + revalidate (objectData.size ()-1); + } + public void removeRow () { + int idx = jTableObject.getSelectedRow (); + if (idx < 0) + return; + Prop prop = objectData.get (idx).prop; + if (prop != null && prop.isLock () && !admin) + return; + objectData.remove (idx); + if (idx == objectData.size ()) + idx--; + revalidate (idx); + } + public void move (int delta) { + int idx = jTableObject.getSelectedRow (); + if (idx < 0) + return; + int mod = objectData.size (); + PropShadow old = objectData.remove (idx); + idx = (idx+delta+mod) % mod; + if (idx == objectData.size ()) + objectData.add (old); + else + objectData.add (idx, old); + revalidate (idx); + } + public void setEnum () { + int idx = jTableObject.getSelectedRow (); + if (idx < 0) + return; + int nbLabel = 0; + switch (Prop.PropTypeEnum.values () [objectData.elementAt (idx).jType.getSelectedIndex ()]) { + case Enum: + JStringSet jStringSet = objectData.elementAt (idx).jStringSet; + jStringSet.init (); + if (JOptionPane.showConfirmDialog (JDefPropTable.this, + jStringSet, + null, JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) + return; + jStringSet.confirm (); + return; + case Square: + case Geo: + nbLabel = 2; + break; + case Cube: + nbLabel = 3; + break; + default: + return; + } + JDefLabel jDefLabel = objectData.elementAt (idx).jDefLabel; + jDefLabel.initLabels (nbLabel); + if (JOptionPane.showConfirmDialog (JDefPropTable.this, + jDefLabel, + null, JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) + return; + jDefLabel.confirmLabels (); + } + } + + // ======================================== + public class EnumEditorRenderer extends DefaultCellEditor implements TableCellRenderer { + public EnumEditorRenderer (Class> enumClass) { + super (Util.newEnum (enumClass, null)); + } + @Override + public Component getTableCellEditorComponent (JTable table, Object value, boolean isSelected, int row, int column) { + ((JComboBox)editorComponent).setSelectedIndex (((JComboBox) value).getSelectedIndex ()); + return editorComponent; + } + public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JComboBox jCombobox = objectData.elementAt (row).jType; + jCombobox.setBackground (isSelected ? table.getSelectionBackground () : table.getBackground ()); + jCombobox.setForeground (isSelected ? table.getSelectionForeground () : table.getForeground ()); + jCombobox.setSelectedItem (((JComboBox) value).getSelectedIndex ()); + return jCombobox; + } + }; + + // ======================================== + public class CheckIconEditorRenderer extends DefaultCellEditor implements TableCellRenderer { + public CheckIconEditorRenderer (String action) { + super (Util.newCheckIcon (Util.toCapital (action), null)); + } + @Override + public Component getTableCellEditorComponent (JTable table, Object value, boolean isSelected, int row, int column) { + ((JCheckBox)editorComponent).setSelected (((JCheckBox) value).isSelected ()); + return editorComponent; + } + public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + PropShadow prop = objectData.elementAt (row); + JCheckBox jCheckBox = prop.jModifiers.get (Util.viewToModel (table, column)); + if (jCheckBox == null) + return null; + jCheckBox.setBackground (isSelected ? table.getSelectionBackground () : table.getBackground ()); + jCheckBox.setForeground (isSelected ? table.getSelectionForeground () : table.getForeground ()); + jCheckBox.setSelected (((JCheckBox) value).isSelected ()); + return jCheckBox; + } + }; + + // ======================================== + public void actionUp () { + dataObjectModel.move (-1); + } + public void actionDown () { + dataObjectModel.move (+1); + } + public void actionSetEnum () { + dataObjectModel.setEnum (); + } + public void actionAdd () { + String propName = jNewPropName.getText (); + if (dataObjectModel.contains (propName)) + return; + dataObjectModel.addRow (propName); + jNewPropName.setText (""); + } + + // ======================================== + public void actionRemove () { + dataObjectModel.removeRow (); + } + public void updateSetEnum (PropShadow prop) { + boolean enable = false; + try { + switch (Prop.PropTypeEnum.values () [prop.jType.getSelectedIndex ()]) { + case Enum: + enable = true; + break; + case Square: + case Geo: + case Cube: + // XXX sauf si lock et pas admin + enable = true; + } + } catch (Exception e) { + } + setEnum.setEnabled (enable); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JDragUnit.java b/src/java/adecWatt/view/JDragUnit.java new file mode 100644 index 0000000..62c2782 --- /dev/null +++ b/src/java/adecWatt/view/JDragUnit.java @@ -0,0 +1,20 @@ +package adecWatt.view; + +import javax.swing.JLabel; + +import adecWatt.model.Unit; + +@SuppressWarnings ("serial") public class JDragUnit extends JLabel { + + // ======================================== + public Unit unit; + + public JDragUnit (Unit unit) { + this.unit = unit; + setIcon (unit.getIcon (16)); + setText (unit.toString ()); + setSize (getPreferredSize ()); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JEditable.java b/src/java/adecWatt/view/JEditable.java new file mode 100644 index 0000000..c50e1ca --- /dev/null +++ b/src/java/adecWatt/view/JEditable.java @@ -0,0 +1,354 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingConstants; + +import misc.Bundle; +import misc.LocalizedUserLabel; +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCNL; + +import misc.ScaledImage; +import misc.Story; + +import adecWatt.model.AdecWatt; +import adecWatt.model.Editable; +import adecWatt.model.Prop; +import adecWatt.model.Unit; +import adecWatt.model.unit.Workspace; +import adecWatt.view.PrintWorkspace; +import adecWatt.view.jProp.JPropGeo; +import adecWatt.view.jProp.JPropIcon; +import static adecWatt.model.Permanent.PropTypeEnum; +import static adecWatt.model.Prop.DoubleMix; +import static adecWatt.model.Prop.PropIcon; +import static adecWatt.model.Prop.PropMix; + +public class JEditable implements SwingConstants { + + // ======================================== + static public final int previewSize = 800; + + private Unit storyUnit; + private HashSet> editableSet = new HashSet> (); + private boolean linguist; + private JTabbedPane jTabbedPane = new JTabbedPane (); + private JPanel jPropList = Util.getGridBagPanel (); + protected LocalizedUserLabel localizedUserLabel; + private ArrayList localizedTabName = new ArrayList (); + + public boolean isLinguist () { return linguist; } + public AdecWatt getAdecWatt () { return storyUnit.getAdecWatt (); } + public void addLocalizedUserLabel (LocalizedUserLabel localizedUserLabel) { localizedTabName.add (localizedUserLabel); } + + public String getId () { + if (editableSet.size () > 1) + return PropMix; + for (Editable editable : editableSet) + return editable.getId (); + return null; + } + public String getModelName () { + String result = null; + for (Editable editable : editableSet) + try { + String model = editable.getModel ().getLocalName (); + if (result == null) { + result = model; + continue; + } + if (!result.equals (model)) + return PropMix; + } catch (Exception e) { + return null; + } + return result; + } + public String getName () { + if (editableSet.size () > 1) + return PropMix; + for (Editable editable : editableSet) + return editable.getName (); + return null; + } + public List getOrderedPropsName () { + List result = null; + for (Editable editable : editableSet) { + List tmp = editable.getOrderedPropsName (); + if (tmp == null) + continue; + if (result == null) { + result = tmp; + continue; + } + result.retainAll (tmp); + } + return result; + } + public PropTypeEnum getTypeToken (String propName) { + for (Editable editable : editableSet) { + Prop type = editable.getProp (propName); + if (type != null) + return type.getTypeToken (); + } + return null; + } + public int getNbVal (String propName) { + for (Editable editable : editableSet) { + Prop type = editable.getProp (propName); + if (type != null) + return type.nbVal; + } + return 0; + } + public List getPropLabel (String propName) { + List result = null; + for (Editable editable : editableSet) { + List tmp = editable.getPropLabel (propName); + if (result == null) { + result = tmp; + continue; + } + if (result.equals (tmp)) + continue; + return null; + } + return result; + } + public Collection getPropEnumChoice (String propName) { + Collection result = null; + for (Editable editable : editableSet) { + Collection tmp = editable.getPropEnumChoice (propName); + if (result == null) { + result = tmp; + continue; + } + if (result.equals (tmp)) + continue; + return null; + } + return result; + } + public boolean getPropHidden (String propName) { + for (Editable editable : editableSet) + if (!editable.getPropHidden (propName)) + return false; + return true; + } + public boolean getPropLocalized (String propName) { + for (Editable editable : editableSet) + if (editable.getPropLocalized (propName)) + return true; + return false; + } + public boolean getPropHorizontalSpin (String propName, boolean skipFirst) { + for (Editable editable : editableSet) + if (editable.getPropHorizontalSpin (propName, skipFirst)) + return true; + return false; + } + public String getPropValue (String propName, boolean skipFirst) { + String result = null; + boolean nullExist = false; + for (Editable editable : editableSet) { + try { + String tmp = editable.getPropVal (propName, skipFirst).sValue; + if (tmp == null) { + if (result != null) + return PropMix; + nullExist = true; + continue; + } + if (result == null) { + if (nullExist) + return PropMix; + result = tmp; + continue; + } + if (result.equals (tmp)) + continue; + return PropMix; + } catch (Exception e) { + if (!skipFirst && editable.getProp (propName) == null) + return PropMix; + nullExist = true; + continue; + } + } + if (result != null && nullExist) + return PropMix; + return result; + } + public Double[] getPartialPropValue (String propName, int nbVal, boolean skipFirst) { + Double[] result = null; + for (Editable editable : editableSet) { + Double[] tmp = new Double [nbVal]; + editable.getPartialProp (propName, tmp, skipFirst); + if (result == null) { + result = tmp; + continue; + } + int nbMix = 0; + for (int i = 0; i < result.length; i++) { + if (result[i] == DoubleMix) { + nbMix++; + continue; + } + if (result[i] == tmp[i] || (result[i] != null && result[i].equals (tmp[i]))) + continue; + result[i] = DoubleMix; + nbMix++; + } + if (nbMix == result.length) + return result; + } + return result; + } + public ScaledImage getPreview () { + try { + return new ScaledImage (PrintWorkspace.getIcon ((Workspace) storyUnit, previewSize, true)); + } catch (Exception e) { + return null; + } + } + private JPropGeo firstGeo; + ArrayList allProps = new ArrayList (); + + public void setFirstGeo (JPropGeo firstGeo) { + if (this.firstGeo == null) + this.firstGeo = firstGeo; + } + + public void plotCity (double latitude, double longitude) { + if (firstGeo == null) + return; + firstGeo.setGeo (latitude, longitude); + } + public void toFront (Component c) { + jTabbedPane.setSelectedComponent (c); + } + + // ======================================== + public JEditable (List> editables) { + for (Editable editable : editables) { + Unit storyUnit = editable.getStoryUnit (); + if (this.storyUnit != null && storyUnit != this.storyUnit) + throw new IllegalArgumentException ("Can't managed heterogenous unit"); + this.storyUnit = storyUnit; + editableSet.add (editable); + } + if (storyUnit == null) + throw new IllegalArgumentException ("Can't managed no unit"); + linguist = getAdecWatt ().getUser ().isLinguist (); + } + public JPanel getDislay (boolean edit) { + JPanel jDisplay = new JPanel (new BorderLayout ()); + JPanel right = new JPanel (); + jDisplay.add (right, BorderLayout.EAST); + right.add (jPropList); + // XXX si edit ... + String editableId = getId (); + String modelName = getModelName (); + modelName = modelName == null || modelName == PropMix ? "" : (" ("+modelName+")"); + JLabel jLabelId = new JLabel ((editableId == PropMix ? Bundle.getMessage ("MixId") : editableId)+modelName); + jLabelId.setForeground (Color.GRAY); + Util.addComponent (jLabelId, jPropList, GBCNL); + JPropIcon jPropIcon = new JPropIcon (PropIcon, this); + String editableName = getName (); + JLabel jLabelName = null; + if (editableName == PropMix) + jLabelName = new JLabel (Bundle.getMessage ("MixName")); + else { + localizedUserLabel = new LocalizedUserLabel (editableName, storyUnit.isLocalized (), linguist); + jLabelName = localizedUserLabel.getJLabel (); + } + jLabelName.setHorizontalTextPosition (SwingConstants.RIGHT); + // XXX si line autre icon + allProps.add (jPropIcon); + Util.addComponent (jPropIcon.getMainIcon (edit), jPropList, GBC); + Util.addComponent (jLabelName, jPropList, GBCNL); + for (String propName : getOrderedPropsName ()) + try { + if (PropIcon.equals (propName)) + continue; + JProp jProp = JProp.getJProp (propName, this); + allProps.add (jProp); + jProp.display (edit, jPropList, jTabbedPane); + } catch (Exception e) { + e.printStackTrace (); + } + if (jTabbedPane.getTabCount () > 0) + jDisplay.add (jTabbedPane, BorderLayout.CENTER); + if (linguist) + jTabbedPane.addMouseListener (new MouseAdapter () { + public void mousePressed (MouseEvent e) { + int idx = jTabbedPane.indexAtLocation (e.getX (), e.getY ()); + if (idx < 0) + return; + LocalizedUserLabel localizedUserLabel = localizedTabName.get (idx); + localizedUserLabel.mousePressed (e); + jTabbedPane.setTitleAt (idx, localizedUserLabel.getCurrentLabel ()); + } + }); + return jDisplay; + } + + // ======================================== + public boolean valideChange () { + // if (!jNewPropName.getText ().isEmpty ()) + // return false; + return true; + } + + public void confirmBundle () { + if (!getAdecWatt ().getUser ().isLinguist ()) + return; + if (localizedUserLabel != null) { + String newLabel = localizedUserLabel.getNewLabel (); + if (newLabel != null) + Bundle.setUser (JProp.AdecWattUser, getName (), newLabel); + } + for (JProp jProp : allProps) + jProp.confirmBundle (); + Bundle.save (JProp.AdecWattUser); + } + + public void updateStoryView () { + for (Editable editable : editableSet) + editable.updateView (); + } + public void confirmChange () { + // XXX revoir code avant 1/10/16 storyUnit.getLocalName () + // start story + Story.Commands commands = storyUnit.story.new Commands (Editable.StoryEdit) { + public void display () { updateStoryView (); } + }; + for (Editable editable : editableSet) { + ArrayList changeProps = new ArrayList (); + for (JProp jProp : allProps) { + String propName = jProp.getPropName (); + // props = {type, parent, own, last}; + Prop [] props = new Prop [] {editable.getProp (propName), editable.getParentPropVal (propName), + editable.getOwnProp (propName), null}; + jProp.getChange (props); + changeProps.add (props); + } + editable.storyChange (commands, changeProps); + } + storyUnit.story.add (commands); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JItem.java b/src/java/adecWatt/view/JItem.java new file mode 100644 index 0000000..ede6a6b --- /dev/null +++ b/src/java/adecWatt/view/JItem.java @@ -0,0 +1,172 @@ +package adecWatt.view; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +import misc.DimensionDouble; +import misc.Log; + +import adecWatt.model.Comp; +import adecWatt.model.Item; +import adecWatt.model.Segm; + +@SuppressWarnings ("serial") abstract public class JItem extends JLabel { + + // ======================================== + protected ItemMouseAdapter itemMouseAdapter = new ItemMouseAdapter (); + protected JWorkspaceView jWorkspaceView; + protected double currentThetaDegree; + protected Point2D.Double currentPos; + protected DimensionDouble currentSize; + protected double [] currentBounds = null; + + abstract public Item getItem (); + abstract public void setItem (Item item); + + public JWorkspaceView getJWorkspaceView () { return jWorkspaceView; } + public Point2D.Double getCurrentPos () { return currentPos; } + public DimensionDouble getCurrentSize () { return currentSize; } + public double getCurrentThetaDegree () { return currentThetaDegree; } + public double [] getCurrentBounds () { return currentBounds; } + + // ======================================== + static public JItem getNewJItem (JWorkspaceView jWorkspaceView, Item item) { + if (item instanceof Comp) + return new JComp (jWorkspaceView, (Comp) item); + if (item instanceof Segm) + return new JSegm (jWorkspaceView, (Segm) item); + throw new IllegalArgumentException ("Bad item type ("+item+")!"); + } + + public JItem (JWorkspaceView jWorkspaceView, Item item) { + try { + this.jWorkspaceView = jWorkspaceView; + setItem (item); + setCurrentSize (); + updateIcon (); + addMouseListener (itemMouseAdapter); + addMouseMotionListener (itemMouseAdapter); + } catch (Exception e) { + Log.keepLastException ("JItem ("+getItem ()+") :", e); + } + } + + // ======================================== + public class ItemMouseAdapter extends MouseAdapter { + public void mouseClicked (MouseEvent e) { + jWorkspaceView.mouseClicked (SwingUtilities.convertMouseEvent (JItem.this, e, jWorkspaceView)); + } + public void mousePressed (MouseEvent e) { + MouseEvent ec = SwingUtilities.convertMouseEvent (JItem.this, e, jWorkspaceView); + jWorkspaceView.mousePressed (ec); + } + public void mouseReleased (MouseEvent e) { + jWorkspaceView.mouseReleased (SwingUtilities.convertMouseEvent (JItem.this, e, jWorkspaceView)); + } + public void mouseDragged (MouseEvent e) { + jWorkspaceView.mouseDragged (SwingUtilities.convertMouseEvent (JItem.this, e, jWorkspaceView)); + } + }; + + // ======================================== + public void setCurrentPos (Point2D.Double currentPos) { + this.currentPos = currentPos; + updateBounds (); + updateLocation (); + } + public void setCurrentSize (DimensionDouble size) { + currentSize = size; + updateBounds (); + updateIcon (); + } + public void setCurrentThetaDegree (double currentThetaDegree) { + this.currentThetaDegree = currentThetaDegree; + updateBounds (); + updateIcon (); + } + public void setCurrentSize (Point2D.Double pos, DimensionDouble size) { + setCurrentGeo (pos, getItem ().getThetaDegree (), size); + } + public void setCurrentGeoDelta (Point2D.Double pos, double deltaTheta, DimensionDouble size) { + setCurrentGeo (pos, Math.toDegrees (Math.toRadians (currentThetaDegree)+deltaTheta), size); + } + private void setCurrentGeo (Point2D.Double pos, double thetaDegree, DimensionDouble size) { + currentPos = pos; + currentSize = size; + currentThetaDegree = thetaDegree; + updateBounds (); + updateIcon (); + } + + // ======================================== + public void setCurrentPos () { + setCurrentPos (getItem ().getPos ()); + } + public void setCurrentSize () { + setCurrentSize (getItem ().getSize ()); + } + public void setCurrentThetaDegree () { + setCurrentThetaDegree (getItem ().getThetaDegree ()); + } + public void setScale () { + updateIcon (); + } + + // ======================================== + public void updateLocation () { + Point pos = jWorkspaceView.scaleModelToView (currentPos); + pos.x -= getWidth ()/2; + pos.y -= getHeight ()/2; + setLocation (pos); + jWorkspaceView.setLayer (this, jWorkspaceView.levelModelToView (getItem ().getLevel ())); + } + + // ======================================== + public void cap (Point relPos) { + Dimension size = getSize (); + setCurrentThetaDegree (Math.toDegrees (Math.PI/2+Math.atan2 (relPos.y-size.height/2, relPos.x-size.width/2))); + } + + public void rotation (MouseEvent e) { + cap (e.getPoint ()); + } + + public void dragItem (DimensionDouble delta) { + setCurrentPos (new Point2D.Double (currentPos.x+delta.width, currentPos.y+delta.height)); + } + + // ======================================== + public void updateIcon () { + if (currentPos == null || currentSize == null) + return; + double scale = jWorkspaceView.getScale (); + Item item = getItem (); + DimensionDouble size = Item.getRotSize (new DimensionDouble (currentSize.width*scale, currentSize.height*scale), currentThetaDegree); + BufferedImage image = new BufferedImage (Math.max (1, (int) size.width), Math.max (1, (int) size.height), BufferedImage.TYPE_INT_ARGB); + + DimensionDouble currentRotSize = Item.getRotSize (currentSize, currentThetaDegree); + Point2D.Double halfCurrentRotSize = new Point2D.Double (currentRotSize.width/2, currentRotSize.height/2); + + Graphics2D printGraphics = (Graphics2D) image.getGraphics (); + printGraphics.scale (scale, scale); + item.print (printGraphics, jWorkspaceView.getWorkspace (), halfCurrentRotSize, currentSize, currentThetaDegree); + setIcon (new ImageIcon (image)); + setSize (getPreferredSize ()); + updateLocation (); + } + public void updateBounds () { + if (currentPos == null || currentSize == null) + return; + currentBounds = Item.getBounds (currentPos, currentSize, currentThetaDegree); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JItemHandler.java b/src/java/adecWatt/view/JItemHandler.java new file mode 100644 index 0000000..9b72fdb --- /dev/null +++ b/src/java/adecWatt/view/JItemHandler.java @@ -0,0 +1,168 @@ +package adecWatt.view; + +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +import misc.Util; +import misc.DimensionDouble; + +public class JItemHandler { + + // ======================================== + static public final ImageIcon handlerImage = Util.loadActionIcon ("handler"); + + // ======================================== + public JWorkspaceView jWorkspaceView; + public JLabel jSelectionPane; + public JItem jItem; + public HandlerSet corners, sides; + public boolean lineSelection; + + // ======================================== + public JItemHandler (JWorkspaceView jWorkspaceView, JLabel jSelectionPane, JItem jItem, boolean lineSelection) { + this.jWorkspaceView = jWorkspaceView; + this.jSelectionPane = jSelectionPane; + this.jItem = jItem; + this.lineSelection = lineSelection; + if (!lineSelection) + corners = new HandlerSet (true); + sides = new HandlerSet (false); + } + public void setCurrentBounds (double[] bounds) { + if (corners != null) + corners.setCurrentBounds (bounds); + sides.setCurrentBounds (bounds); + } + + Point mousePosOnItem; + int selectedIndex; + double oposedX, oposedY; + DimensionDouble currentSize; + double currentDiagonalLength; + + // ======================================== + class HandlerSet { + public boolean cornerSelection; + public double[] x = new double [4], y = new double [4]; + public JLabel[] handlers = new JLabel [4]; + + public HandlerSet (boolean cornerSelection) { + this.cornerSelection = cornerSelection; + for (int i = 0; i < 4; i++) { + if (i%2 != 0 && lineSelection) + continue; + final JLabel handler = new JLabel (handlerImage); + final int index = i; + handlers [i] = handler; + handler.setSize (8, 8); + MouseAdapter mouseAdapter = new MouseAdapter () { + // identique à JItem + public void mousePressed (MouseEvent e) { + if (SwingUtilities.isRightMouseButton (e)) { + // XXX ??? collectif ? + new JItemPopup (jWorkspaceView, jItem.getItem (), SwingUtilities.convertPoint (handler, e.getPoint (), jWorkspaceView)); + return; + } + selectedIndex = index; + oposedX = x[(index+2)%4]; + oposedY = y[(index+2)%4]; + currentSize = jItem.getCurrentSize (); + currentDiagonalLength = Math.sqrt (currentSize.width*currentSize.width + currentSize.height*currentSize.height); + mousePosOnItem = e.getPoint (); + } + public void mouseDragged (MouseEvent e) { + if (jWorkspaceView.notEditable ()) + return; + dragHandler (e); + jWorkspaceView.updateSelectionLayer (); + } + public void mouseReleased (MouseEvent e) { + if (jWorkspaceView.notEditable ()) + return; + jWorkspaceView.storyRotResizeItem (jItem); + } + }; + handler.addMouseListener (mouseAdapter); + handler.addMouseMotionListener (mouseAdapter); + } + } + + // ======================================== + public void setCurrentBounds (double[] bounds) { + if (cornerSelection) + for (int i = 0, j = 1, k = 0; k < 4; i += 2, j += 2, k++) { + x[k] = bounds[i]; + y[k] = bounds[j]; + } + else + for (int i = 8, j = 9, k = 0; k < 4; i += 2, j += 2, k++) { + x[k] = bounds[i]; + y[k] = bounds[j]; + } + double scale = jWorkspaceView.getScale (); + for (int k = 0; k < 4; k++) { + JLabel handler = handlers [k]; + if (handler == null) + continue; + handler.setLocation ((int) (x [k]*scale-4), (int) (y [k]*scale-4)); + jWorkspaceView.recordJLabel (handler); + } + } + + // ======================================== + public void dragHandler (MouseEvent e) { + double scale = jWorkspaceView.getScale (); + Point newPos = e.getPoint (); + double newX = x[selectedIndex]+(newPos.x-mousePosOnItem.x)/scale; + double newY = y[selectedIndex]+(newPos.y-mousePosOnItem.y)/scale; + Point2D.Double closePos = new Point2D.Double (newX, newY); + jWorkspaceView.setSelectedBound (e.isControlDown () ? null : jWorkspaceView.getWorkspace ().getMagnetPoint (closePos, JWorkspaceView.onGrid (closePos), JWorkspaceView.closePixelsBounds/scale)); + Point2D.Double newItemCenter = new Point2D.Double ((oposedX+closePos.x)/2, (oposedY+closePos.y)/2); + + DimensionDouble newItemSize = null; + if (e.isShiftDown ()) { + double currentTheta = Math.toRadians (jItem.getCurrentThetaDegree ()); + double[] reverse = new double [] {closePos.x-newItemCenter.x, closePos.y-newItemCenter.y}; + AffineTransform.getRotateInstance (-currentTheta).transform (reverse, 0, reverse, 0, 1); + newItemSize = new DimensionDouble (Math.max (1/scale, Math.abs (reverse[0]*2)), + Math.max (1/scale, Math.abs (reverse[1]*2))); + if (!cornerSelection) { + if (selectedIndex%2 == 0) { + newItemSize.height = currentSize.height; + reverse [1] = 0; + } else { + newItemSize.width = currentSize.width; + reverse [0] = 0; + } + AffineTransform.getRotateInstance (currentTheta).transform (reverse, 0, reverse, 0, 1); + newItemCenter.x = oposedX+reverse [0]; + newItemCenter.y = oposedY+reverse [1]; + } + jItem.setCurrentSize (newItemCenter, newItemSize); + return; + } + if (cornerSelection) { + double rate = Math.sqrt ((closePos.x-oposedX)*(closePos.x-oposedX) + + (closePos.y-oposedY)*(closePos.y-oposedY)) / currentDiagonalLength; + newItemSize = new DimensionDouble (currentSize.width*rate, currentSize.height*rate); + } else { + double length = Math.sqrt ((closePos.x-oposedX)*(closePos.x-oposedX) + (closePos.y-oposedY)*(closePos.y-oposedY)); + if (selectedIndex%2 == 0) + newItemSize = new DimensionDouble (length, currentSize.height); + else + newItemSize = new DimensionDouble (currentSize.width, length); + } + double deltaTheta = Math.atan2 (closePos.y-oposedY, closePos.x-oposedX) - + Math.atan2 (y[selectedIndex]-oposedY, x[selectedIndex]-oposedX); + jItem.setCurrentGeoDelta (newItemCenter, deltaTheta, newItemSize); + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JItemPopup.java b/src/java/adecWatt/view/JItemPopup.java new file mode 100644 index 0000000..5dc8e7c --- /dev/null +++ b/src/java/adecWatt/view/JItemPopup.java @@ -0,0 +1,80 @@ +package adecWatt.view; + +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Collection; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JPopupMenu; + +import misc.Util; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.Item; +import adecWatt.model.AdecWatt; +import adecWatt.model.User; + +@SuppressWarnings ("serial") public class JItemPopup extends JPopupMenu { + + private Item getLocal (JWorkspaceView jWorkspaceView, Item item) { + return jWorkspaceView.workspace.getCloseEmbedded (item); + } + private List getLocal2 (JWorkspaceView jWorkspaceView, Collection selectedItems) { + ArrayList localSelectedItems = new ArrayList (selectedItems.size ()); + for (Item item : selectedItems) + localSelectedItems.add (jWorkspaceView.workspace.getCloseEmbedded (item)); + return localSelectedItems; + } + + // ======================================== + public JItemPopup (final JWorkspaceView jWorkspaceView, final Item item, final Point pos) { + final AdecWatt adecWatt = jWorkspaceView.getAdecWatt (); + Item localItem = jWorkspaceView.workspace.getLocalEmbedded (item.getId ()); // XXX a supprimer + User user = adecWatt.getUser (); + boolean editor = user.isEditor (jWorkspaceView.getWorkspace ()); + + Util.addMenuItem (AdecWattManager.actionDisplayItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionDisplayItem, jWorkspaceView.getSelectedItems ()); + } + }, this); + if (editor) { + Util.addMenuItem (AdecWattManager.actionModifyItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionModifyItem, getLocal2 (jWorkspaceView, jWorkspaceView.getSelectedItems ())); + } + }, this); + Util.addMenuItem (AdecWattManager.actionHideItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionHideShowItem, jWorkspaceView, jWorkspaceView.getSelectedItems (), true); + } + }, this); + Util.addMenuItem (AdecWattManager.actionShowItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionHideShowItem, jWorkspaceView, jWorkspaceView.getSelectedItems (), false); + } + }, this); + Util.addMenuItem (AdecWattManager.actionTransformItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionTransformItem, getLocal (jWorkspaceView, item)); + } + }, this); + Util.addMenuItem (AdecWattManager.actionCopyItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionCopyItem, jWorkspaceView, jWorkspaceView.getSelectedItems (), pos); + } + }, this); + // XXX a mettre dans le fond + if (localItem != null) + Util.addMenuItem (AdecWattManager.actionRemoveItem, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionRemoveItem, jWorkspaceView, jWorkspaceView.getSelectedItems ()); + } + }, this); + } + show (jWorkspaceView, pos.x, pos.y); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JLightplotView.java b/src/java/adecWatt/view/JLightplotView.java new file mode 100644 index 0000000..cae799b --- /dev/null +++ b/src/java/adecWatt/view/JLightplotView.java @@ -0,0 +1,39 @@ +package adecWatt.view; + +import adecWatt.model.Unit; +import adecWatt.model.unit.Building; +import adecWatt.model.unit.Lightplot; + +@SuppressWarnings ("serial") public class JLightplotView extends JWorkspaceView { + + protected Building building; + + // ======================================== + public JLightplotView (JAdecWatt jAdecWatt, Lightplot lightplot) { + super (jAdecWatt, lightplot); + changeBuilding (); + workspace.stateNotifier.addUpdateObserver (this, Unit.BroadcastChangeBuilding); + // XXX updateConnectionLayer (); + } + + void changeBuilding () { + if (building != null) + building.stateNotifier.removeObserver (this); + building = workspace.getBuilding (); + // XXX repaint + building.stateNotifier.addMsgObserver (this, + Unit.BroadcastNewItem, Unit.BroadcastRemoveItem, + Unit.BroadcastChangePos, Unit.BroadcastChangeRot); + } + + // ======================================== + public void updateChangeBuilding () { + changeBuilding (); + realSize = workspace.getRealSize (); + //scaledBlueprint = workspace.getBlueprint (); + //setBlueprint (); + setScale (scale); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JPatch.java b/src/java/adecWatt/view/JPatch.java new file mode 100644 index 0000000..d88d5f7 --- /dev/null +++ b/src/java/adecWatt/view/JPatch.java @@ -0,0 +1,98 @@ +package adecWatt.view; + +import java.awt.Component; +import java.awt.GridLayout; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; + +import misc.Bundle; +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCNL; + +import adecWatt.model.Circuits; +import adecWatt.model.Patch; + +@SuppressWarnings ("serial") +public class JPatch extends JPanel implements SwingConstants { + + static public Border groupBorder = BorderFactory.createEtchedBorder (EtchedBorder.LOWERED); + + static public class JInfo extends JPanel { + public JInfo (Component line1, Component line2, Component line3) { + super (new GridLayout (3, 1)); + add (line1); + add (line2); + add (line3); + setBorder (groupBorder); + } + public JInfo (Component line1, Component line2) { + super (new GridLayout (2, 1)); + add (line1); + add (line2); + setBorder (groupBorder); + } + public JInfo (Component line) { + super (new GridLayout (1, 1)); + add (line); + setBorder (groupBorder); + } + } + + public JPatch (Patch patch) { + JPanel content = Util.getGridBagPanel (); + add (Util.getJScrollPane (content)); + + Util.addComponent (new JInfo (Util.newLabel ("Circuit", RIGHT), + Util.newLabel ("Line", RIGHT), + Util.newLabel ("Watt", RIGHT)), content, GBC); + if (patch != null) + for (String circuitName : patch.circuitLines.keySet ()) { + String lineNames = "", sep = ""; + for (String name : patch.circuitLines.get (circuitName)) { + lineNames += sep+name; + sep = ", "; + } + Util.addComponent (new JInfo (new JLabel (circuitName, CENTER), + new JLabel (lineNames, CENTER), + new JLabel (Util.toNumIn10Units (patch.circuitConsumption.get (circuitName)), CENTER)), content, GBC); + } + Util.addComponent (new JLabel (), content, GBCNL); + Util.addComponent (new JInfo (Util.newLabel ("Line", RIGHT), + Util.newLabel ("Circuit", RIGHT), + Util.newLabel ("Watt", RIGHT)), content, GBC); + if (patch != null) + for (String lineName : patch.getLineKeys ()) { + String circuitName = patch.lineCircuit.get (lineName); + JLabel consumption = null; + if (Circuits.SHORTCUT == circuitName) { + circuitName = Bundle.getLabel (Circuits.SHORTCUT); + consumption = new JLabel (""); + } else + consumption = new JLabel (Util.toNumIn10Units (patch.lineConsumption.get (lineName)), CENTER); + Util.addComponent (new JInfo (new JLabel (lineName, CENTER), + new JLabel (circuitName, CENTER), + consumption), content, GBC); + } + Util.addComponent (new JLabel (), content, GBCNL); + Util.addComponent (new JInfo (Util.newLabel (Circuits.UNPLUG, RIGHT)), content, GBC); + if (patch != null) + for (String circuitName : patch.unplug) + Util.addComponent (new JInfo (new JLabel (circuitName, CENTER)), content, GBC); + Util.addComponent (new JLabel (), content, GBCNL); + Util.addComponent (new JInfo (Util.newLabel (Circuits.SHORTCUT, RIGHT)), content, GBC); + if (patch != null) + for (String circuitName : patch.shortcut) + Util.addComponent (new JInfo (new JLabel (circuitName, CENTER)), content, GBC); + Util.addComponent (new JLabel (), content, GBCNL); + Util.addComponent (new JInfo (Util.newLabel (Circuits.CIRCUITLESS, RIGHT)), content, GBC); + if (patch != null) + for (String compName : patch.circuitless) + Util.addComponent (new JInfo (new JLabel (compName, CENTER)), content, GBC); + Util.addComponent (new JLabel (), content, GBCNL); + } +} diff --git a/src/java/adecWatt/view/JPreviewImp.java b/src/java/adecWatt/view/JPreviewImp.java new file mode 100644 index 0000000..180ea83 --- /dev/null +++ b/src/java/adecWatt/view/JPreviewImp.java @@ -0,0 +1,242 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JSplitPane; + +import misc.DimensionDouble; +import misc.Util; + +// sauver dans une liste de preview + +@SuppressWarnings ("serial") public class JPreviewImp extends JPanel implements ActionListener { + + // ======================================== + static public final String + actionPortrait = "Portrait", + actionLandscape = "Landscape", + actionAddZone = "AddZone", + actionAddPoster = "AddPoster", + actionAddPatch = "AddPatch", + actionRemoveZone = "RemoveZone", + actionTurnLeft = "TurnLeft", + actionTurnRight = "TurnRight", + actionCircuit = "Circuit"; + + static public final List + previewButtonsNames = Arrays.asList (//actionPortrait, actionLandscape, + actionAddZone, actionAddPoster, actionAddPatch, actionRemoveZone, + actionTurnLeft, actionTurnRight); + static public final List + previewActionsNames = Arrays.asList (//actionPortrait, actionLandscape, + actionAddZone, actionAddPoster, actionAddPatch, actionRemoveZone, + actionTurnLeft, actionTurnRight, actionCircuit); + @SuppressWarnings ("unchecked") + static public final Hashtable actionsMethod = + Util.collectMethod (JPreviewImp.class, previewActionsNames); + + public void actionPerformed (ActionEvent e) { + Util.actionPerformed (actionsMethod, e, this); + } + public void actionPortrait () { + setLandscape (false); + } + public void actionLandscape () { + setLandscape (true); + } + public void actionAddZone () { + Color color = getColor (); + JZones.Zone selectedZone = preview.getSelectedZone (); + JZones.Zone newZone = (selectedZone != null && selectedZone.getPair () != null) ? + workspace.addZone (color, selectedZone.getPair ().getRectangle ()) : + workspace.addZone (color); + preview.addZone (newZone, null); + preview.selectLastZone (); + actionCircuit (); + } + public void actionAddPoster () { + if (posterImage == null) + return; + Color color = getColor (); + preview.addZone (color, posterImage); + preview.selectLastZone (); + } + public void actionAddPatch () { + if (patchImage == null) + return; + Color color = getColor (); + preview.addZone (color, patchImage); + preview.selectLastZone (); + } + public void actionRemoveZone () { + JZones.Zone selectedZone = preview.getSelectedZone (); + if (selectedZone == null) + return; + preview.removeZone (selectedZone); + workspace.removeZone (selectedZone.getPair ()); + } + public void actionTurnLeft () { + preview.turnZoneLeft (); + } + public void actionTurnRight () { + preview.turnZoneRight (); + } + public void actionCircuit () { + JZones.Zone selectedZone = preview.getSelectedZone (); + if (selectedZone == null || !selectedZone.hasPair () || workspaceImageNoCircuit == null) + return; + boolean printCircuit = jCheckBoxCircuit.isSelected (); + if (printCircuit) { + noPrintCircuit.remove (selectedZone); + selectedZone.setImage (workspaceImage); + } else { + noPrintCircuit.add (selectedZone); + selectedZone.setImage (workspaceImageNoCircuit); + } + } + public void updateCircuit (JZones.Zone selectedZone) { + if (selectedZone == null || !selectedZone.hasPair () || workspaceImageNoCircuit == null) + return; + jCheckBoxCircuit.setSelected (!noPrintCircuit.contains (selectedZone)); + } + + // ======================================== + JSplitPane jSplitPane; + JZones workspace, preview; + HashSet noPrintCircuit = new HashSet (); + JCheckBox jCheckBoxCircuit; + BufferedImage workspaceImage, workspaceImageNoCircuit, posterImage, patchImage; + + public JPreviewImp (DimensionDouble workspaceSize, DimensionDouble pageSize, + BufferedImage workspaceImage, BufferedImage workspaceImageNoCircuit, + BufferedImage posterImage, BufferedImage patchImage, + int maxSide) { + this (new JZones (workspaceSize, maxSide), new JZones (pageSize, maxSide)); + this.workspaceImage = workspaceImage; + this.workspaceImageNoCircuit = workspaceImageNoCircuit; + this.posterImage = posterImage; + this.patchImage = patchImage; + workspace.setBackground (workspaceImage); + } + public JPreviewImp (DimensionDouble workspaceSize, DimensionDouble pageSize, int maxSide) { + this (new JZones (pageSize, maxSide), new JZones (workspaceSize, maxSide)); + } + private JPreviewImp (JZones workspace, JZones preview) { + super (new BorderLayout ()); + this.preview = preview; + this.workspace = workspace; + preview.setCornerSelection (false); + preview.setCreateZone (false); + jSplitPane = Util.getJSplitPane (JSplitPane.HORIZONTAL_SPLIT, getJZonesFrame (workspace), getJZonesFrame (preview)); + add (jSplitPane, BorderLayout.CENTER); + workspace.stateNotifier.addUpdateObserver (this, JZones.BroadcastSelectedLocationChange, JZones.BroadcastSelectedRateChange); + workspace.stateNotifier.addMsgObserver (this, JZones.BroadcastCreateZone, JZones.BroadcastSelectedChange); + preview.stateNotifier.addMsgObserver (this, JZones.BroadcastSelectedChange); + JPanel menuBar = new JPanel (); + menuBar.setLayout (new BoxLayout (menuBar, BoxLayout.X_AXIS)); + Util.addIconButton (previewButtonsNames, this, menuBar); + jCheckBoxCircuit = Util.newCheckIcon (actionCircuit, this, true); + menuBar.add (jCheckBoxCircuit); + Util.unBoxButton (menuBar); + add (menuBar, BorderLayout.NORTH); + } + public JPanel getJZonesFrame (JZones jZones) { + JPanel jPanel = new JPanel (new BorderLayout ()); + jPanel.add (Util.getJScrollPane (jZones), BorderLayout.CENTER); + jPanel.add (jZones.new SizeSlider (), BorderLayout.SOUTH); + return jPanel; + } + + static public final Color [] rainbow; + static { + int nbColors = 7; + rainbow = new Color[nbColors]; + for (int i = 0; i < nbColors; i++) + rainbow[i] = new Color (Color.HSBtoRGB (((float)i)/nbColors, 1, 1)); + } + int rainbowIndex = -1; + public Color getColor () { + rainbowIndex = (rainbowIndex+1)%rainbow.length; + return rainbow [rainbowIndex]; + } + public void displayCreateZone (Object... objects) { + if (objects[0] == null) + return; + Rectangle2D.Double area = (Rectangle2D.Double) objects[0]; + Color color = getColor (); + preview.addZone (workspace.addZone (color, area), null); + preview.selectLastZone (); + actionCircuit (); + } + public void displaySelectedChange (Object... objects) { + if (objects[0] == null) + return; + JZones src = (JZones) objects[0]; + JZones.Zone selectZone = (JZones.Zone) objects[1]; + if (selectZone == null) { + JZones dst = src == workspace ? preview : workspace; + dst.selectZoneQuiet (null); + return; + } + if (src == preview) { + updateCircuit (selectZone); + workspace.selectZoneQuiet (selectZone.getPair ()); + return; + } + JZones.Zone pair = preview.findPair (selectZone); + updateCircuit (pair); + preview.selectZoneQuiet (pair); + } + public void updateSelectedRateChange () { + JZones.Zone selectedZone = preview.getSelectedZone (); + if (selectedZone == null) + return; + selectedZone.updatePairRate (); + } + public void updateSelectedLocationChange () { + preview.repaint (); + } + public void setLandscape (boolean landscape) { + double currentPrevRate = preview.getScale (); + double currentWorkRate = workspace.getScale (); + if (!preview.setLandscape (landscape)) + return; + preview.resetScale (); + workspace.resetScale (); + //jSplitPane.resetToPreferredSizes (); + Util.packWindow (this); + preview.setScale (currentPrevRate); + workspace.setScale (currentWorkRate); + } + + // ======================================== + static public void main (String[] args) { + try { + misc.Config.setPWD (JPreviewImp.class); + BufferedImage workspaceImage = javax.imageio.ImageIO.read (new java.io.File ("/home/felix/perso/adecWatt/ws/exemplePrint.png")); + + DimensionDouble pageSize = new DimensionDouble (21, 29.7); + DimensionDouble workspaceSize = new DimensionDouble (25, 34); + int maxSide = 200; + JPreviewImp jPreviewImp = new JPreviewImp (workspaceSize, pageSize, workspaceImage, null, workspaceImage, workspaceImage, maxSide); + Util.newJFrame ("test", jPreviewImp, true); + jPreviewImp.actionAddZone (); + } catch (Exception e) { + e.printStackTrace (); + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JProp.java b/src/java/adecWatt/view/JProp.java new file mode 100644 index 0000000..5dfda31 --- /dev/null +++ b/src/java/adecWatt/view/JProp.java @@ -0,0 +1,263 @@ +package adecWatt.view; + +import java.awt.Color; +import java.awt.Font; +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.util.Collection; +import java.util.List; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import javax.swing.border.LineBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; + +import misc.Bundle; +import misc.LocalizedUserLabel; +import misc.Util; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.AdecWatt; +import adecWatt.model.ImageDB; +import adecWatt.model.PermanentDB; +import adecWatt.model.Prop; +import adecWatt.view.jProp.JPropText; +import static adecWatt.model.Permanent.PropTypeEnum; +import static adecWatt.model.Prop.PropMix; + +public abstract class JProp { + + // ======================================== + static public final String + AdecWattUser = "AdecWattUser"; + + public final static int defaultImageWidth = 256; + public final static int defaultImageHeight = 512; + + static public Color + textFgColor = Color.black, + textBgColor = Color.white, + noValueFgColor = Color.darkGray, + noValueBgColor = Color.lightGray, + badValueColor = Color.red; + + public Border + defaultBorder = null, + badValueBorder = new LineBorder (badValueColor); + + static protected JLabel getMsgLabel (String msg) { + JLabel unknown = new JLabel (msg); + unknown.setForeground (noValueFgColor); + unknown.setBackground (noValueBgColor); + unknown.setOpaque (true); + return unknown; + } + static public JLabel getUnknownLabel () { return getMsgLabel ("?"); } + static public JLabel getEmptyLabel () { return getMsgLabel ("_"); } + + // ======================================== + static public JProp getJProp (String propName, JEditable jEditable) { + PropTypeEnum type = jEditable.getTypeToken (propName); + try { + // find class adecWatt.view.jProp.JProp<> (avec TYPE = type.getTypeToken ()) + return (JProp) + ClassLoader.getSystemClassLoader (). + loadClass (JPropText.class.getPackage ().getName ()+".JProp"+type). + getConstructor (String.class, JEditable.class). + newInstance (propName, jEditable); + } catch (Exception e) { + throw new IllegalArgumentException ("Can't find constructor for type ("+type+")."); + } + } + + // ======================================== + protected JEditable jEditable; + protected AdecWatt adecWatt; // XXX ??? + protected PermanentDB permanentDB; + protected ImageDB iconDB; + protected ImageDB imageDB; + protected String propName; + protected PropTypeEnum type; + protected int nbVal; + protected Collection enumChoice; + protected boolean hidden; + protected String ownValue, parentValue, lastValue; + protected Double[] ownValues, parentValues, lastValues; + protected boolean horizontalSpin, parentHorizontalSpin; + protected LocalizedUserLabel localizedUserLabel; + protected LocalizedUserLabel[] localizedUserMultiLabels; + + //public String getSValue () { return lastValue; } + public ImageDB getIconDB () { return iconDB; } + public ImageDB getImageDB () { return imageDB; } + public String getLastValue () { return lastValue; } + public String getPropName () { return propName; } + public boolean getHorizontalSpin () { return horizontalSpin; } + protected void updateView () { } + abstract protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane); + + // ======================================== + protected JProp (String propName, JEditable jEditable) { + this.jEditable = jEditable; + adecWatt = jEditable.getAdecWatt (); + permanentDB = adecWatt.getPermanentDB (); + iconDB = adecWatt.getIconDB (); + imageDB = adecWatt.getImageDB (); + this.propName = propName; + type = jEditable.getTypeToken (propName); + nbVal = jEditable.getNbVal (propName); + enumChoice = jEditable.getPropEnumChoice (propName); + lastValue = ownValue = jEditable.getPropValue (propName, false); + parentValue = jEditable.getPropValue (propName, true); + if (nbVal > 0) { + ownValues = jEditable.getPartialPropValue (propName, nbVal, false); + parentValues = jEditable.getPartialPropValue (propName, nbVal, true); + lastValues = ownValues; + } + hidden = jEditable.getPropHidden (propName); + // XXX seulement si icon ou image + parentHorizontalSpin = jEditable.getPropHorizontalSpin (propName, true); + horizontalSpin = jEditable.getPropHorizontalSpin (propName, false)^parentHorizontalSpin; + if (ownValue == null) { + lastValue = ownValue = parentValue; + lastValues = ownValues = parentValues; + horizontalSpin = parentHorizontalSpin; + } + boolean isLocalized = jEditable.getPropLocalized (propName); + boolean linguist = jEditable.isLinguist (); + localizedUserLabel = new LocalizedUserLabel (propName, isLocalized, linguist); + List multiLabel = jEditable.getPropLabel (propName); + if (multiLabel == null) + return; + localizedUserMultiLabels = new LocalizedUserLabel [multiLabel.size ()]; + for (int i = 0; i < localizedUserMultiLabels.length; i++) { + localizedUserMultiLabels[i] = new LocalizedUserLabel (multiLabel.get (i), isLocalized, linguist); + JLabel result = localizedUserMultiLabels[i].getJLabel (); + Font defaultFont = result.getFont (); + result.setFont (new Font (defaultFont.getName (), Font.PLAIN, (defaultFont.getSize ()*3)/4)); + } + } + + // ======================================== + public void display (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + if (!edit && (hidden || lastValue == null) && type != PropTypeEnum.Preview) + return; + displayByType (edit, jPropList, jTabbedPane); + } + + public void setUnchange (JTextComponent jTextComponent, boolean unchange) { + if (unchange) { + jTextComponent.setText (""); + jTextComponent.setForeground (noValueFgColor); + jTextComponent.setBackground (noValueBgColor); + } else { + jTextComponent.setForeground (textFgColor); + jTextComponent.setBackground (textBgColor); + } + } + public void setChangeListener (final JTextComponent jTextComponent) { + final Document document = jTextComponent.getDocument (); + document.addDocumentListener (new DocumentListener () { + public void changedUpdate (DocumentEvent e) { + document.removeDocumentListener (this); + setUnchange (jTextComponent, false); + document.addDocumentListener (this); + } + public void insertUpdate (DocumentEvent e) { changedUpdate (e); } + public void removeUpdate (DocumentEvent e) { changedUpdate (e); } + }); + jTextComponent.addMouseListener (new MouseAdapter () { + @SuppressWarnings ("serial") + public void mousePressed (final MouseEvent e) { + if (!SwingUtilities.isRightMouseButton (e)) + return; + new JPopupMenu () { + { + Util.addMenuItem (AdecWattManager.actionUnchange, new ActionListener () { + public void actionPerformed (ActionEvent e) { + setUnchange (jTextComponent, true); + } + }, this); + Point pos = e.getPoint (); + show (jTextComponent, pos.x, pos.y); + } + }; + } + }); + } + public void removeVal () { + if (lastValue == parentValue) + return; + lastValue = parentValue; + lastValues = parentValues; + updateView (); + } + public void unchangeVal () { + lastValue = PropMix; + lastValues = Prop.string2tab (lastValue, nbVal); + updateView (); + } + public void setSpin (boolean horizontalSpin) { + this.horizontalSpin = horizontalSpin; + updateView (); + } + public void setVal (String newVal) { + if (newVal == null | newVal.isEmpty ()) { + removeVal (); + return; + } + if (lastValue != null && newVal.equals (lastValue)) + return; + lastValue = newVal; + lastValues = Prop.string2tab (lastValue, nbVal); + updateView (); + } + + // ======================================== + /** + props = {type, parent, own, last}; + */ + public void getChange (Prop[] props) { + lastValue = getLastValue (); + if (lastValue != null && lastValue.isEmpty ()) + lastValue = null; + boolean newHorizontalSpin = horizontalSpin ^ parentHorizontalSpin; + if (!(newHorizontalSpin)) { + if ((lastValue == null && props [2] == null) || + (lastValue != null && props [2] != null && lastValue.equals (props [2].sValue))) { + props [3] = props [2]; + return; + } + if (lastValue == null && props [2] != null) { + props [3] = props [1]; + return; + } + } + props [3] = new Prop (propName, type, horizontalSpin); + props [3].setValue (lastValue); + } + + public void confirmBundle () { + String newLabel = localizedUserLabel.getNewLabel (); + if (newLabel != null) + Bundle.setUser (AdecWattUser, localizedUserLabel.getLabel (), newLabel); + if (localizedUserMultiLabels == null) + return; + for (int i = 0; i < localizedUserMultiLabels.length; i++) { + newLabel = localizedUserMultiLabels[i].getNewLabel (); + if (newLabel != null) + Bundle.setUser (AdecWattUser, localizedUserMultiLabels[i].getLabel (), newLabel); + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JScrollPaneWorkspace.java b/src/java/adecWatt/view/JScrollPaneWorkspace.java new file mode 100644 index 0000000..0bfa575 --- /dev/null +++ b/src/java/adecWatt/view/JScrollPaneWorkspace.java @@ -0,0 +1,87 @@ +package adecWatt.view; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Rectangle; +import javax.swing.JComponent; +import javax.swing.JScrollPane; + +import misc.DimensionDouble; + +import adecWatt.model.unit.Workspace; + +@SuppressWarnings ("serial") public class JScrollPaneWorkspace extends JScrollPane { + + static public final boolean HORIZONTAL = true; + static public final boolean VERTICAL = false; + static public final int SIZE = 16; + static public final Color BG = Color.LIGHT_GRAY; + static public final int TICK_LENGTH = 5; + + private JWorkspaceView jWorkspaceView; + private JRule horizontalJRule = new JRule (HORIZONTAL); + private JRule verticalJRule = new JRule (VERTICAL); + + public JWorkspaceView getJWorkspaceView () { return jWorkspaceView; } + public Workspace getWorkspace () { return jWorkspaceView.getWorkspace (); } + + public JScrollPaneWorkspace (JWorkspaceView jWorkspaceView) { + super (jWorkspaceView, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); + this.jWorkspaceView = jWorkspaceView; + setColumnHeaderView (horizontalJRule); + setRowHeaderView (verticalJRule); + } + + void updateScale () { + horizontalJRule.repaint (); + verticalJRule.repaint (); + } + + public class JRule extends JComponent { + public boolean horizontal; + public JRule (boolean horizontal) { + this.horizontal = horizontal; + setPreferredSize (new Dimension (SIZE, SIZE)); + } + + protected void paintComponent (Graphics g) { + Rectangle viewRect = getViewport ().getViewRect (); + double scale = jWorkspaceView.getScale (); + DimensionDouble realSize = jWorkspaceView.getRealSize (); + + int minTick = (int) Math.round ((horizontal ? viewRect.x : viewRect.y)/scale); + int maxTick = + (int) Math.round (Math.min ((horizontal ? realSize.width : realSize.height), + (horizontal ? viewRect.x+viewRect.width : viewRect.y+viewRect.height)/scale)); + + Rectangle drawHere = g.getClipBounds (); + g.setColor (BG); + g.fillRect (drawHere.x, drawHere.y, drawHere.width, drawHere.height); + g.setFont (new Font ("SansSerif", Font.PLAIN, 8)); + g.setColor (Color.black); + + for (int i = minTick; i <= maxTick; i += 1) { + int p = (int) (i*scale - (horizontal ? viewRect.x : viewRect.y)); + if (horizontal) + g.drawLine (p, SIZE-1, p, SIZE-TICK_LENGTH-1); + else + g.drawLine (SIZE-1, p, SIZE-TICK_LENGTH-1, p); + String text = Integer.toString (i); + if (i == 0) { + text += "m"; + if (horizontal) + g.drawString (text, p+2, 8); + else + g.drawString (text, 1, p+10); + continue; + } + if (horizontal) + g.drawString (text, p-3, 8); + else + g.drawString (text, 0, p+3); + } + } + } +} diff --git a/src/java/adecWatt/view/JSegm.java b/src/java/adecWatt/view/JSegm.java new file mode 100644 index 0000000..b5eccb5 --- /dev/null +++ b/src/java/adecWatt/view/JSegm.java @@ -0,0 +1,28 @@ +package adecWatt.view; + +import adecWatt.model.Item; +import adecWatt.model.Segm; + +@SuppressWarnings ("serial") public class JSegm extends JItem { + + // ======================================== + public Segm segm; + + public Item getItem () { return segm; } + + // ======================================== + public JSegm (JWorkspaceView jWorkspaceView, Segm segm) { + super (jWorkspaceView, segm); + } + + public void setItem (Item item) { + if (item == null) + return; + segm = (Segm) item; + setCurrentThetaDegree (item.getAngle ()); + setCurrentSize (); + setCurrentPos (); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JStringSet.java b/src/java/adecWatt/view/JStringSet.java new file mode 100644 index 0000000..af116aa --- /dev/null +++ b/src/java/adecWatt/view/JStringSet.java @@ -0,0 +1,137 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.Collection; +import java.util.Collections; +import java.util.Vector; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import misc.Util; + +@SuppressWarnings ("serial") +public class JStringSet extends JPanel { + + // ======================================== + static public final String + actionAdd = "Add", + actionRemove = "Remove"; + + // ======================================== + private Vector refList = new Vector (); + private Vector list = new Vector (); + private JList jList = new JList (); + private JTextField jTextField = new JTextField (8); + + public Collection getSet () { + if (list.size () < 1) + return null; + return list; + } + + // ======================================== + public JStringSet (Collection enumChoice) { + super (new BorderLayout ()); + jTextField.addAncestorListener (new AncestorListener () { + @Override + public void ancestorRemoved (final AncestorEvent event) {} + @Override + public void ancestorMoved (final AncestorEvent event) {} + @Override + public void ancestorAdded (final AncestorEvent event) { + jTextField.requestFocusInWindow (); + } + }); + jTextField.addFocusListener (new FocusListener () { + @Override + public void focusGained (final FocusEvent e) {} + @Override + public void focusLost (final FocusEvent e) { + if (isFirstTime) { + // When we lose focus, ask for it back but only once + jTextField.requestFocusInWindow (); + isFirstTime = false; + } + } + private boolean isFirstTime = true; + }); + jList.addListSelectionListener (new ListSelectionListener () { + public void valueChanged (ListSelectionEvent e) { + jTextField.setText (jList.getSelectedValue ()); + } + }); + + JPanel jPanel = new JPanel (new BorderLayout ()); + jPanel.add (Util.newIconButton (actionAdd, new ActionListener () { + public void actionPerformed (ActionEvent e) { + actionAdd (); + } + }), BorderLayout.WEST); + jPanel.add (jTextField, BorderLayout.CENTER); + jPanel.add (Util.newIconButton (actionRemove, new ActionListener () { + public void actionPerformed (ActionEvent e) { + actionRemove (); + } + }), BorderLayout.EAST); + add (jPanel, BorderLayout.SOUTH); + add (Util.getJScrollPane (jList), BorderLayout.CENTER); + Util.unBoxButton (jPanel); + if (enumChoice == null) + return; + refList.addAll (enumChoice); + Collections.sort (refList); + list.addAll (refList); + } + + // ======================================== + public void init () { + list.clear (); + list.addAll (refList); + updateList (); + } + public void confirm () { + actionAdd (); + refList.clear (); + refList.addAll (list); + } + + // ======================================== + public void updateList () { + jList.setListData (list); + jList.revalidate (); + } + + public void actionAdd () { + String value = jTextField.getText (); + jTextField.setText (""); + if (value == null || value.isEmpty ()) + return; + if (list.contains (value)) + return; + list.addElement (value); + Collections.sort (list); + updateList (); + // XXX jList.setSelectedValue (value, true); + jList.setSelectedValue (null, false); + } + public void actionRemove () { + int selection = jList.getSelectedIndex (); + if (selection < 0) + return; + list.removeElementAt (selection); + updateList (); + if (selection >= list.size ()) + selection--; + jList.setSelectedIndex (selection); + } + // ======================================== +} diff --git a/src/java/adecWatt/view/JTransform.java b/src/java/adecWatt/view/JTransform.java new file mode 100644 index 0000000..4c0a975 --- /dev/null +++ b/src/java/adecWatt/view/JTransform.java @@ -0,0 +1,151 @@ +package adecWatt.view; + +import java.awt.GridBagLayout; +import java.util.ArrayList; +import java.util.Collection; +import java.util.TreeSet; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCNL; + +import adecWatt.model.Embedded; +import adecWatt.model.Editable; +import adecWatt.model.Permanent; +import adecWatt.model.Prop; +import adecWatt.model.Unit; +import adecWatt.model.UnitNode; + +@SuppressWarnings ("serial") +public class JTransform extends JPanel { + // ======================================== + static public ArrayList getJModifiers (Collection modifiersSet, Collection modifiers, boolean isLock) { + ArrayList result = new ArrayList (); + for (String modifier : modifiersSet) { + JCheckBox button = Util.newCheckIcon (Util.toCapital (modifier), null); + if (modifiers != null && modifiers.contains (modifier)) + button.setSelected (true); + Util.unBoxButton (button); + result.add (button); + } + if (isLock) + for (JCheckBox button : result) + button.setEnabled (false); + return result; + } + + static public Collection getModifiers (ArrayList buttons, + Collection oldModifiers, boolean admin, Collection hiddenModifiers) { + TreeSet modifiers = new TreeSet (); + for (JCheckBox button : buttons) + if (button.isSelected ()) + modifiers.add (button.getActionCommand ().toLowerCase ()); + if (!admin && oldModifiers != null) + for (String modifier : hiddenModifiers) + if (oldModifiers.contains (modifier)) + modifiers.add (modifier); + return modifiers.size () < 1 ? null : modifiers; + } + + public boolean isLock (String propName) { + return editable.getDirectUnit ().getPropLock (propName); + } + + // ======================================== + private Editable editable; + private Unit root; + private boolean isRoot; + private boolean isEmbedded; + private ArrayList jModifiers; + private ArrayList> permanents; + private JComboBox jPermanents; + private JTextField jName; + private JDefPropTable jDefPropTable; + private boolean admin; + + public boolean isAdmin () { return admin; } + + public JTransform (Editable editable) { + super (new GridBagLayout ()); + this.editable = editable; + root = editable.getDirectUnit ().getUnitRoot (); + isRoot = root == editable; + isEmbedded = editable instanceof Embedded; + admin = editable.getDirectUnit ().getAdecWatt ().getUser ().isAdmin (); + + setAvailablePermanents (); + jName = new JTextField (editable.getName (), 16); + jDefPropTable = new JDefPropTable (this, editable); + + if (!isEmbedded) { + jModifiers = getJModifiers (editable.getModifiersSet (), editable.getModifiers (), editable.isLock ()); + JPanel jDisplayModifiers = new JPanel (); + for (JCheckBox jModifier : jModifiers) + jDisplayModifiers.add (jModifier); + Util.addComponent (jDisplayModifiers, this, GBC); + } + if (isRoot) + Util.addComponent (jName, this, GBCNL); + else { + Util.addComponent (jPermanents, this, isEmbedded ? GBCNL : GBC); + if (!isEmbedded) + Util.addComponent (jName, this, GBCNL); + } + Util.addComponent (Util.getJScrollPane (jDefPropTable), this, GBCNL); + + // XXX devrait être géré par jDefPropTable + } + + // ======================================== + @SuppressWarnings ("unchecked") + public void setAvailablePermanents () { + if (isRoot) + return; + permanents = (ArrayList>) editable.getDirectUnit ().getAvailablePermanents (isEmbedded, editable); + jPermanents = new JComboBox (); + for (Unit unit : permanents) + jPermanents.addItem (unit.getLocalName ()); + jPermanents.setSelectedIndex (permanents.indexOf (editable.getParentUnit ())); + } + + // ======================================== + public boolean valideChange () { + if (!jDefPropTable.jNewPropName.getText ().isEmpty ()) + return false; + TreeSet propNames = new TreeSet (); + for (JDefPropTable.PropShadow defProp : jDefPropTable.getObjectData ()) { + String propName = defProp.propName; + if (propName == null || propName.isEmpty () || propNames.contains (propName)) + return false; + propNames.add (propName); + } + return true; + } + + @SuppressWarnings ("unchecked") + public void confirmChange () { + ArrayList transProps = new ArrayList (); + int rank = 0; + for (JDefPropTable.PropShadow defProp : jDefPropTable.getObjectData ()) + transProps.add (new Prop[] { + defProp.prop, + new Prop (defProp.propName, + Prop.PropTypeEnum.values()[defProp.jType.getSelectedIndex ()], + new Integer (rank++), + defProp.getModifiers (), + defProp.jStringSet.getSet (), + defProp.jDefLabel.getLabels ()) + }); + Collection newModifiers = jModifiers == null ? null : getModifiers (jModifiers, null, admin, null); + editable.storyTransform (newModifiers, getPermanent (), jName.getText (), transProps); + } + public Unit getPermanent () { + return isRoot ? null : permanents.get (jPermanents.getSelectedIndex ()); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JUnitPopup.java b/src/java/adecWatt/view/JUnitPopup.java new file mode 100644 index 0000000..af04a5a --- /dev/null +++ b/src/java/adecWatt/view/JUnitPopup.java @@ -0,0 +1,79 @@ +package adecWatt.view; + +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Arrays; +import java.util.List; +import javax.swing.JPopupMenu; +import javax.swing.JTree; + +import misc.Util; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.AdecWatt; +import adecWatt.model.Unit; +import adecWatt.model.User; + +@SuppressWarnings ("serial") +public class JUnitPopup extends JPopupMenu { + + // ======================================== + public JUnitPopup (final AdecWatt adecWatt, JTree jTree, final Unit unit, Point pos) { + User user = adecWatt.getUser (); + boolean editor = user.isEditor (unit); + final List selectedUnits = Arrays.asList (unit); + Util.addMenuItem (AdecWattManager.actionDisplayUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionDisplayUnit, selectedUnits); + } + }, this); + if (editor) + Util.addMenuItem (AdecWattManager.actionModifyUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionModifyUnit, selectedUnits); + } + }, this); + if (editor && unit.getParent () != null) + Util.addMenuItem (AdecWattManager.actionRenameUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionRenameUnit, selectedUnits); + } + }, this); + if (user.isDataStructuresManager ()) { + Util.addMenuItem (AdecWattManager.actionTransformUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionTransformUnit, unit); + } + }, this); + } + if (editor) { + if (unit.getParent () != null) + Util.addMenuItem (AdecWattManager.actionCopyUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionCopyUnit, unit); + } + }, this); + Util.addMenuItem (AdecWattManager.actionNewUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionNewUnit, unit); + } + }, this); + } + if ((!unit.getRemote () || unit.story.isModified ()) && !user.isVisitorId ()) + Util.addMenuItem (AdecWattManager.actionPromoteUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionPromoteUnit, unit); + } + }, this); + if (!unit.getRemote ()) + Util.addMenuItem (AdecWattManager.actionRemoveUnit, new ActionListener () { + public void actionPerformed (ActionEvent e) { + adecWatt.broadcastDisplay (AdecWattManager.actionRemoveUnit, unit); + } + }, this); + show (jTree, pos.x, pos.y); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JUser.java b/src/java/adecWatt/view/JUser.java new file mode 100644 index 0000000..45e04b0 --- /dev/null +++ b/src/java/adecWatt/view/JUser.java @@ -0,0 +1,94 @@ +package adecWatt.view; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashSet; +import java.util.Hashtable; +import javax.swing.JCheckBox; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +import misc.Bundle; +import misc.RemoteUpdate; +import misc.RemoteUpdateManager; +import misc.Util; +import static misc.Util.GBCNL; + +import adecWatt.model.User; + +@SuppressWarnings ("serial") +public class JUser extends JPanel { + + // ======================================== + private User user; + private HashSet roles; + private Hashtable rolesCB = new Hashtable (); + + private JTextField loginTF; + private JPasswordField passwordTF; + private JTextField idTF; + + // ======================================== + public JUser (User user, final RemoteUpdateManager remoteUpdateManager) { + super (new BorderLayout ()); + this.user = user; + loginTF = new JTextField (user.getLogin ()); + passwordTF = new JPasswordField (user.getPassword ()); + idTF = new JTextField (""+user.getUserId ()); + roles = user.getRoles (); + JPanel form = Util.getGridBagPanel (); + Util.addLabelFields (form, "Login", loginTF); + Util.addLabelFields (form, "Password", passwordTF); + Util.addButton ("Connection", new ActionListener () { + public void actionPerformed (ActionEvent e) { + RemoteUpdate remoteUpdate = remoteUpdateManager.getRemoteUpdate (); + remoteUpdate.logoutDokuwiki (); + char[] pass = passwordTF.getPassword (); + remoteUpdate.loginDokuwiki (loginTF.getText (), ""+new String (pass)); + String newRoles = remoteUpdate.getRoles (loginTF.getText ()); + if (newRoles == null) { + remoteUpdateManager.setConnected (false); + JOptionPane.showMessageDialog (JUser.this, Bundle.getMessage ("ConnectionFailed")); + return; + } + remoteUpdateManager.setConnected (true); + idTF.setText (""+User.updateRoles (roles, newRoles)); + for (User.Role role : User.Role.values ()) + rolesCB.get (role).setSelected (roles.contains (role)); + JOptionPane.showMessageDialog (JUser.this, Bundle.getMessage ("ConnectionSucceeded")); + } + }, form, GBCNL); + int idx = 0; + for (final User.Role role : User.Role.values ()) { + if (idx++ == 5) { + Util.addComponent (new JTextArea (Bundle.getMessage ("ChangeRole")), form, GBCNL); + Util.addLabelFields (form, "Id", idTF); + } + JCheckBox jCheckBox = Util.addCheckButton (role.toString (), new ActionListener () { + public void actionPerformed (ActionEvent e) { + if (((JCheckBox) e.getSource ()).isSelected ()) + roles.add (role); + else + roles.remove (role); + } + }, form, GBCNL); + jCheckBox.setSelected (roles.contains (role)); + rolesCB.put (role, jCheckBox); + } + add (form, BorderLayout.CENTER); + } + + // ======================================== + public void confirm () { + user.setLogin (loginTF.getText ()); + user.setPassword (new String (passwordTF.getPassword ())); + user.setUserId (Integer.parseInt (idTF.getText ())); + user.setRoles (roles); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JWorkspaceSlidersToolBar.java b/src/java/adecWatt/view/JWorkspaceSlidersToolBar.java new file mode 100644 index 0000000..1b4f5f6 --- /dev/null +++ b/src/java/adecWatt/view/JWorkspaceSlidersToolBar.java @@ -0,0 +1,80 @@ +package adecWatt.view; + +// XXX still magics values + +import javax.swing.BoxLayout; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.JToolBar; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import misc.Bundle; + +@SuppressWarnings ("serial") public class JWorkspaceSlidersToolBar extends JToolBar implements ChangeListener { + + JWorkspaceView jWorkspaceView; + JPanel jSet = new JPanel (); + JSlider jScale = new JSlider (0, 200, 100); + JSlider jOpacity = new JSlider (0, 200, 100); + + public JWorkspaceSlidersToolBar (JAdecWatt jAdecWatt) { + super ("Slider"); + add (jSet); + jScale.setMajorTickSpacing (50); + jScale.setMinorTickSpacing (10); + jSet.add (jScale); + jSet.add (jOpacity); + setJWorkspaceView (null); + jScale.addChangeListener (this); + jOpacity.addChangeListener (this); + jAdecWatt.stateNotifier.addUpdateObserver (this, JAdecWatt.BroadcastChangeScale); + // XXX jAdecWatt.stateNotifier.addUpdateObserver (this, JAdecWatt.BroadcastChangeOpacity); + jScale.setToolTipText (Bundle.getAction ("Scale")); + jOpacity.setToolTipText (Bundle.getAction ("Crossfades")); + } + public void setOrientation (int o) { + if (jScale != null) { + jScale.setOrientation (o); + jOpacity.setOrientation (o); + jSet.setLayout (new BoxLayout (jSet, o == HORIZONTAL ? BoxLayout.Y_AXIS : BoxLayout.X_AXIS)); + } + super.setOrientation (o); + } + public void setJWorkspaceView (JWorkspaceView jWorkspaceView) { + this.jWorkspaceView = jWorkspaceView; + if (jWorkspaceView == null) { + jScale.setEnabled (false); + jOpacity.setEnabled (false); + jOpacity.setValue (100); + } else { + jScale.setEnabled (true); + if (jWorkspaceView.workspace.getBuilding () != null) { + jOpacity.setEnabled (true); + jOpacity.setValue ((int) (jWorkspaceView.workspace.getOpacity ()*200)); + } else + jOpacity.setValue (100); + } + updateChangeScale (); + } + public void stateChanged (ChangeEvent e) { + if (jWorkspaceView == null) + return; + if (e.getSource () == jScale) { + jWorkspaceView.setScale (Math.pow (10, jScale.getValue ()/100.-1)*jWorkspaceView.getInitScale ()); + return; + } + jWorkspaceView.workspace.setOpacity (jOpacity.getValue ()/200F); + jWorkspaceView.repaint (); + } + + public void updateChangeScale () { + if (jWorkspaceView == null) { + jScale.setValue (100); + return; + } + jScale.removeChangeListener (this); + jScale.setValue ((int) (100*(Math.log10 (jWorkspaceView.getScale ()/jWorkspaceView.getInitScale ())+1))); + jScale.addChangeListener (this); + } +} diff --git a/src/java/adecWatt/view/JWorkspaceView.java b/src/java/adecWatt/view/JWorkspaceView.java new file mode 100644 index 0000000..d4c0364 --- /dev/null +++ b/src/java/adecWatt/view/JWorkspaceView.java @@ -0,0 +1,926 @@ +package adecWatt.view; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Shape; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JScrollBar; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; + +import misc.DimensionDouble; +import adecWatt.control.AdecWattManager; +import adecWatt.model.Acc; +import adecWatt.model.AdecWatt; +import adecWatt.model.Comp; +import adecWatt.model.ImageDB; +import adecWatt.model.Item; +import adecWatt.model.PermanentDB; +import adecWatt.model.Prop; +import adecWatt.model.Unit; +import adecWatt.model.UnitNode; +import adecWatt.model.User; +import adecWatt.model.unit.Accessory; +import adecWatt.model.unit.Building; +import adecWatt.model.unit.Lightplot; +import adecWatt.model.unit.NonWorkspace; +import adecWatt.model.unit.Workspace; + +@SuppressWarnings ("serial") public class JWorkspaceView extends JLayeredPane { + + // ======================================== + static public final int closePixelsBounds = 10; + static public final int closePixelsAccs = 2; + static public final int closePixelsItems = 4; + static final double gridStep = .1; + + static public final Color noColor = new Color (255, 255, 255, 0); + static public final Color selectionColor = new Color (0, 255, 0, 64); + static public final Color selectionBoundColor = new Color (0, 0, 255, 96); + + protected double scale = 1, minScale = 1, maxScale = 1, initScale = 1, scaleStep = 1; + protected JAdecWatt jAdecWatt; + protected AdecWatt adecWatt; + protected User user; + protected PermanentDB permanentDB; + protected ImageDB iconDB; + + protected T workspace; + protected DimensionDouble realSize; + protected Rectangle2D.Double backgroundShape; + protected Dimension currentSize; + protected JLabel jSelectionPane; + protected Graphics2D selectionGraphics; + protected Item lastSelectedItem; + protected Hashtable selectedItems = new Hashtable (); + protected int lastSelectedAccId; + protected JAcc selectedAcc; + + public JAdecWatt getJAdecWatt () { return jAdecWatt; } + public AdecWatt getAdecWatt () { return adecWatt; } + public PermanentDB getPermanentDB () { return permanentDB; } + public ImageDB getIconDB () { return iconDB; } + public T getWorkspace () { return workspace; } + public double getScale () { return scale; } + public double getInitScale () { return initScale; } + public DimensionDouble getRealSize () { return realSize; } + public boolean notEditable () { return !user.isEditor (workspace); } + + public boolean isSelected (Item item) { + return selectedItems.containsKey (item.getId ()); + } + + public boolean isSticky (Item item) { + if (!workspace.getInheritedEmbedded ().contains (item) || item.isReserved ()) + return true; + return item.isSticky (); + } + + private JScrollPaneWorkspace getJScrollPaneWorkspace () { + for (Container parent = getParent () ; parent != null; parent = parent.getParent ()) + if (parent instanceof JScrollPaneWorkspace) + return (JScrollPaneWorkspace) parent; + return null; + } + + // ======================================== + static public JWorkspaceView getInstance (JAdecWatt jAdecWatt, Workspace workspace) { + switch (workspace.getTypeToken ()) { + case Furniture: + case Information: + case Line: + case Accessory: + throw new IllegalArgumentException ("Can't find workspace view for type "+workspace.getTypeToken ()+"."); + case Building: + return new JBuildingView (jAdecWatt, (Building) workspace); + case Lightplot: + return new JLightplotView (jAdecWatt, (Lightplot) workspace); + } + throw new IllegalArgumentException ("Can't find constructor for type "+workspace.getTypeToken ()+"."); + } + + protected JWorkspaceView (JAdecWatt jAdecWatt, T workspace) { + this.jAdecWatt = jAdecWatt; + this.workspace = workspace; + adecWatt = jAdecWatt.getAdecWatt (); + user = adecWatt.getUser (); + permanentDB = adecWatt.getPermanentDB (); + iconDB = adecWatt.getIconDB (); + // XXX comment mettre à jour realSize + realSize = workspace.getRealSize (); + backgroundShape = new Rectangle2D.Double (.0, .0, realSize.width, realSize.height); + jSelectionPane = createJLabelLayer (1001); + initScale (); + addMouseListener (workspaceViewMouseAdapter); + addMouseMotionListener (workspaceViewMouseAdapter); + addMouseWheelListener (workspaceViewMouseAdapter); + workspace.stateNotifier.addUpdateObserver (this, AdecWatt.BroadcastStory); + adecWatt.addMsgObserver (this, Unit.BroadcastSetSelectionItems); + workspace.stateNotifier. + addMsgObserver (this, + Unit.BroadcastNewItem, Unit.BroadcastRemoveItem, Unit.BroadcastUpdateItem, + Unit.BroadcastUpdatePermItem, + Unit.BroadcastChangeRotSize, Unit.BroadcastChangePos, Unit.BroadcastChangeRot); + } + + // ======================================== + private JLabel createJLabelLayer (int layer) { + JLabel result = new JLabel (); + result.setLocation (0, 0); + add (result); + setLayer (result, layer); + return result; + } + private Graphics2D createGraphicsLayer (JLabel layer) { + BufferedImage image = new BufferedImage (currentSize.width, currentSize.height, BufferedImage.TYPE_INT_ARGB); + layer.setIcon (new ImageIcon (image)); + layer.setSize (currentSize); + return image.createGraphics (); + } + + // ======================================== + public ArrayList findItems (Point pos) { + return workspace.findItems (scaleViewToModel (pos), closePixelsItems/scale); + } + public Hashtable> findAccs (Point pos, ArrayList overlap) { + Hashtable> result = new Hashtable> (); + if (overlap ==null) + return result; + Point2D.Double realPos = scaleViewToModel (new Point (pos.x, pos.y)); + for (Item item : overlap) { + ArrayList accs = item.findAccs (realPos, closePixelsAccs/scale); + if (accs.size () > 0) + result.put (item, accs); + } + return result; + } + + // ======================================== + public void paint (Graphics g) { + Graphics2D g2 = (Graphics2D) g; + AffineTransform iat = g2.getTransform (); + Shape clip = g2.getClip (); + g2.scale (scale, scale); + g2.setColor (Color.WHITE); + g2.fill (backgroundShape); + g2.setColor (Color.BLACK); + g2.setStroke (new BasicStroke ((float) (1/scale))); + g2.draw (backgroundShape); + workspace.print (g2, scale, selectedItems.keySet (), true); + g2.setTransform (iat); + g2.setClip (clip); + paintChildren (g); + } + + // ======================================== + MouseAdapter workspaceViewMouseAdapter = new MouseAdapter () { + public void mouseClicked (MouseEvent e) { JWorkspaceView.this.mouseClicked (e); } + public void mousePressed (MouseEvent e) { JWorkspaceView.this.mousePressed (e); } + public void mouseReleased (MouseEvent e) { JWorkspaceView.this.mouseReleased (e); } + public void mouseDragged (MouseEvent e) { JWorkspaceView.this.mouseDragged (e); } + public void mouseWheelMoved (MouseWheelEvent e) { + jAdecWatt.setCurrentWorkspace (workspace); + try { + if (0 != (e.getModifiersEx () & (MouseWheelEvent.SHIFT_MASK|MouseWheelEvent.SHIFT_DOWN_MASK))) + scrollView (true, e.getWheelRotation ()); + else if (0 != (e.getModifiersEx () & (MouseWheelEvent.CTRL_MASK|MouseWheelEvent.CTRL_DOWN_MASK))) + changeScale (e.getPoint (), e.getWheelRotation ()); + else + scrollView (false, e.getWheelRotation ()); + } catch (Exception e2) { + } + } + }; + // ======================================== + public void mouseClicked (MouseEvent e) { + requestFocusInWindow (); + jAdecWatt.setCurrentWorkspace (workspace); + if (selectedAcc != null) { + adecWatt.broadcastDisplay (AdecWattManager.actionDisplayAcc, selectedAcc.getAcc ()); + return; + } + ArrayList overlapItems = findItems (e.getPoint ()); + if (e.getClickCount () > 1) { + // double click + if (selectedItems.size () > 1) + for (Item item : overlapItems) + if (selectedItems.containsKey (item.getId ())) + // XXX info multiple + return; + if (overlapItems.size () < 1) + return; + setSelectedItems (overlapItems.get ((overlapItems.indexOf (lastSelectedItem)+1)%overlapItems.size ())); + List param = Arrays.asList (lastSelectedItem); + adecWatt.broadcastDisplay (AdecWattManager.actionDisplayItem, param); + return; + } + } + public void mousePressed (MouseEvent e) { + jAdecWatt.setCurrentWorkspace (workspace); + if (SwingUtilities.isRightMouseButton (e)) { + if (performPopup (e)) + return; + performSelection (e); + performPopup (e); + return; + } + if (e.isControlDown ()) { + rotation (e); + return; + } + performSelection (e); + } + protected boolean performPopup (MouseEvent e) { + if (selectedAcc != null) { + new JAccPopup (this, selectedAcc.getItem (), selectedAcc.getAcc (), e.getPoint ()); + return true; + } + if (selectedItems.size () > 0) { + // XXX ??? collectif ? + new JItemPopup (this, selectedItems.values ().iterator ().next ().getItem (), e.getPoint ()); + return true; + } + return false; + } + private ArrayList overlapItems; + protected void performSelection (MouseEvent e) { + Point mPos = e.getPoint (); + setSelectedAcc (); + overlapItems = findItems (mPos); + if (overlapItems.size () < 1) { + startsZoneSelection (e); + return; + } + firstClick = lastClick = mPos; + Hashtable> overlapAccs = findAccs (mPos, overlapItems); + if (overlapAccs.size () > 0) { + lastSelectedAccId = (lastSelectedAccId+1)%nbOverlapAccs (overlapAccs); + setSelectedAcc (overlapAccs, lastSelectedAccId); + return; + } + lastSelectedAccId = -1; + // XXX revoir si overlapAccs deja selectionnes + if (e.isShiftDown ()) { + invertItemSelection (overlapItems.get (0)); + if (selectedItems.size () < 1) { + firstClick = lastClick = null; + refHandle = null; + handleOff = null; + } + // XXX changement du choix de la poignée de référence ? + return; + } + if (selectedItems.size () > 0) + for (Item item : overlapItems) + if (selectedItems.containsKey (item.getId ())) { + selectionRefHandle (item, mPos); + return; + } + Item item = overlapItems.get ((overlapItems.indexOf (lastSelectedItem)+1) % overlapItems.size ()); + selectionRefHandle (item, mPos); + setSelectedItems (item); + } + public void selectionRefHandle (Item item, Point mPos) { + Point2D.Double firstModelClick = new Point2D.Double (mPos.x/scale, mPos.y/scale); + refHandle = (Point2D.Double) firstModelClick.clone (); + item.getCloseBound (firstModelClick, Double.MAX_VALUE, refHandle); + handleOff = new DimensionDouble (refHandle.x-firstModelClick.x, refHandle.y-firstModelClick.y); + } + public void mouseReleased (MouseEvent e) { + if (selectedAcc != null) { + dropAcc (e); + return; + } + if (zoneSelectionStart != null) { + endsZoneSelection (e); + return; + } + if (e.isControlDown () && refHandle == null) { + rotation (e); + storyRotSelectedComp (); + return; + } + //dragComps (e); + storyMoveSelectedItem (e); + } + public void mouseDragged (MouseEvent e) { + if (selectedAcc != null) { + dragAcc (e); + return; + } + if (zoneSelectionStart != null) { + extendsZoneSelection (e); + return; + } + if (e.isControlDown () && refHandle == null) { + rotation (e); + return; + } + dragItems (e); + } + + // ======================================== + Point zoneSelectionStart; + Point zoneSelectionEnd; + public void startsZoneSelection (MouseEvent e) { + removeAllSelectedItems (); + zoneSelectionEnd = zoneSelectionStart = e.getPoint (); + updateSelection (); + } + public void extendsZoneSelection (MouseEvent e) { + zoneSelectionEnd = e.getPoint (); + updateSelectionLayer (); + } + public void endsZoneSelection (MouseEvent e) { + removeAllSelectedItems (); + zoneSelectionEnd = e.getPoint (); + Point2D.Double realStart = scaleViewToModel (zoneSelectionStart); + Rectangle2D.Double selectedZone = new Rectangle2D.Double (realStart.x, realStart.y, 0, 0); + selectedZone.add (scaleViewToModel (zoneSelectionEnd)); + for (Item item : workspace.getAllItems ()) { + if (!isSticky (item) && item.inside (selectedZone)) + addSelectedItem (item); + } + zoneSelectionEnd = zoneSelectionStart = null; + updateSelection (); + } + // ======================================== + Line2D.Double selectedBound; + protected void setSelectedBound (Line2D.Double selectedBound) { + this.selectedBound = selectedBound; + } + + protected void removeAllSelectedItems () { + for (JItem jItem : selectedItems.values ()) + remove (jItem); + selectedItems.clear (); + selectedBound = null; + selectedJItemHandlers.clear (); + } + protected boolean removeSelectedItem (Item item) { + selectedBound = null; + JItem jItem = selectedItems.remove (item.getId ()); + if (jItem == null) + return false; + remove (jItem); + return true; + } + protected void addSelectedItem (Item item) { + String itemId = item.getId (); + if (selectedItems.containsKey (itemId)) + return; + JItem jItem = JItem.getNewJItem (this, item); + selectedItems.put (itemId, jItem); + add (jItem); + setLayer (jItem, levelModelToView (item.getLevel ())); + } + + public void setSelectedItemsBySearch (String text) { + removeAllSelectedItems (); + if (text != null && !text.isEmpty ()) + for (Item item : workspace.getAllItems ()) + try { + if (item.match (text)) + addSelectedItem (item); + } catch (Exception e) { + // XXX un pb étrange !!! + // e.printStackTrace (); + // System.err.println ("coucou:"+e+" "+item+" "+item.getModel ()+" "+item.getPos ()); + } + updateSelection (); + } + public void selectAllItems () { + removeAllSelectedItems (); + for (Item item : workspace.getAllItems ()) + if (!isSticky (item)) + addSelectedItem (item); + updateSelection (); + } + public void setSelectedItems () { + removeAllSelectedItems (); + updateSelection (); + } + public void setSelectedItems (List items) { + removeAllSelectedItems (); + if (items == null) + return; + for (Item item : items) { + if (!isSticky (item)) + addSelectedItem (item); + } + updateSelection (); + } + public void setSelectedItems (Item item) { + removeAllSelectedItems (); + if (item != null) + addSelectedItem (item); + lastSelectedItem = item; + updateSelection (); + } + public void invertItemSelection (Item item) { + JItem jItem = selectedItems.remove (item.getId ()); + if (jItem == null) + addSelectedItem (item); + else + remove (jItem); + updateSelection (); + } + public void updateSelection () { + jAdecWatt.stateNotifier.broadcastUpdate (JAdecWatt.BroadcastSelection); + updateSelectionLayer (); + } + public int getNbSelectedItems () { + int result = 0; + for (String itemId : selectedItems.keySet ()) + if (workspace.containsItem (itemId)) + result++; + return result; + } + public Vector getSelectedItems () { + int nbSelected = selectedItems.size (); + Vector items = new Vector (nbSelected); + if (nbSelected < 1) + return items; + for (String itemId : selectedItems.keySet ()) { + if (workspace.containsItem (itemId)) + items.add (selectedItems.get (itemId).getItem ()); + } + return items; + } + + protected int nbOverlapAccs (Hashtable> overlapAccs) { + int result = 0; + for (ArrayList accs : overlapAccs.values ()) + result += accs.size (); + return result; + } + protected void setSelectedAcc () { + if (selectedAcc == null) + return; + remove (selectedAcc); + selectedAcc = null; + updateSelection (); + } + protected void setSelectedAcc (Hashtable> overlapAccs, int idx) { + for (Item item : overlapAccs.keySet ()) { + ArrayList accs = overlapAccs.get (item); + int size = accs.size (); + if (idx >= size) { + idx -= size; + continue; + } + selectedAcc = new JAcc (this, item, accs.get (idx)); + add (selectedAcc); + setLayer (selectedAcc, levelModelToView (item.getLevel ())); + } + updateSelection (); + } + + // ======================================== + protected Hashtable selectedJItemHandlers = new Hashtable (); + protected ArrayList newJLabel = new ArrayList (); + public void recordJLabel (JLabel jLabel) { + newJLabel.add (jLabel); + } + public void updateSelectionLayer () { + AffineTransform af = selectionGraphics.getTransform (); + jSelectionPane.invalidate (); + newJLabel.clear (); + selectionGraphics.setBackground (noColor); + selectionGraphics.clearRect (0, 0, currentSize.width, currentSize.height); + selectionGraphics.setColor (selectionColor); + if (zoneSelectionStart != null) { + int x = Math.min (zoneSelectionStart.x, zoneSelectionEnd.x); + int y = Math.min (zoneSelectionStart.y, zoneSelectionEnd.y); + int width = Math.abs (zoneSelectionEnd.x - zoneSelectionStart.x); + int height = Math.abs (zoneSelectionEnd.y - zoneSelectionStart.y); + selectionGraphics.fillRect (x, y, width, height); + } + if (selectedAcc != null) { + // XXX selectionGraphics à l'échelle ? + Item item = selectedAcc.getItem (); + Acc acc = selectedAcc.getAcc (); + String accId = acc.getId (); + DimensionDouble accSize = item.getAccSize (accId); + double halfWidth = accSize.width*scale/2, halfHeight = accSize.height*scale/2; + AffineTransform at = AffineTransform.getRotateInstance (Math.toRadians (item.getThetaDegree ())); + double [] bounds = new double [] {-halfWidth, -halfHeight, -halfWidth, halfHeight, halfWidth, halfHeight, halfWidth, -halfHeight}; + at.transform (bounds, 0, bounds, 0, 4); + Point accPos = selectedAcc.getLocation (); + int [] x = new int[4]; + int [] y = new int[4]; + for (int i = 0; i < 4; i++) { + x[i] = (int) bounds [2*i]+accPos.x+8; + y[i] = (int) bounds [2*i+1]+accPos.y+8; + } + selectionGraphics.fillPolygon (x, y, 4); + } + // XXX selectionGraphics à l'échelle ? + for (String itemId : selectedItems.keySet ()) { + if (!workspace.containsItem (itemId)) + continue; + try { + JItem jItem = selectedItems.get (itemId); + Item item = jItem.getItem (); + double [] bounds = jItem.getCurrentBounds (); + int [] x = new int[4]; + int [] y = new int[4]; + for (int i = 0, j = 1, k = 0; k < 4; i += 2, j += 2, k++) { + x [k] = (int) (bounds [i]*scale); + y [k] = (int) (bounds [j]*scale); + } + selectionGraphics.fillPolygon (x, y, 4); + if (item.getPropNoMouse (Prop.PropSize)) + continue; + + JItemHandler handler = selectedJItemHandlers.get (jItem); + if (handler == null) + selectedJItemHandlers.put (jItem, handler = new JItemHandler (this, jSelectionPane, jItem, !(jItem instanceof JComp))); + handler.setCurrentBounds (bounds); + } catch (Exception e) { + e.printStackTrace (); + // XXX + } + } + for (Component component : jSelectionPane.getComponents ()) + if (!newJLabel.contains (component)) + jSelectionPane.remove (component); + for (JLabel label : newJLabel) + if (!jSelectionPane.isAncestorOf (label)) + jSelectionPane.add (label); + selectionGraphics.scale (scale, scale); + if (selectedBound != null) { + selectionGraphics.setPaint (selectionBoundColor); + selectionGraphics.setStroke (new BasicStroke (2*closePixelsBounds/(float)scale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f)); + if (selectedBound.x1 == selectedBound.x2 && selectedBound.y1 == selectedBound.y2) { + double r = closePixelsItems/scale, dr = r+r; + java.awt.Shape disc = new java.awt.geom.Ellipse2D.Double (selectedBound.x1-r, selectedBound.y1-r, dr, dr); + selectionGraphics.draw (disc); + } else + selectionGraphics.draw (selectedBound); + } + selectionGraphics.setTransform (af); + jSelectionPane.repaint (); + jSelectionPane.validate (); + } + + // ======================================== + public void scrollView (boolean horizontal, int delta) { + JScrollPaneWorkspace jScrollPaneWorkspace = getJScrollPaneWorkspace (); + JScrollBar jScrollBar = horizontal ? jScrollPaneWorkspace.getHorizontalScrollBar () : jScrollPaneWorkspace.getVerticalScrollBar (); + int min = jScrollBar.getMinimum (); + int max = jScrollBar.getMaximum (); + int step = (max-min)/10; + jScrollBar.setValue (Math.min (max, Math.max (min, jScrollBar.getValue ()+delta*step))); + jScrollPaneWorkspace.updateScale (); + } + public void changeScale (Point mousePos, int delta) { + JViewport jViewport = getJScrollPaneWorkspace ().getViewport (); + Point viewPosA = jViewport.getViewPosition (); + Point2D.Double realPos = scaleViewToModel (mousePos); + setScale (delta < 0 ? scale+scaleStep : scale-scaleStep); + Point viewPosB = scaleModelToView (realPos); + viewPosB.translate (-mousePos.x+viewPosA.x, -mousePos.y+viewPosA.y); + if (viewPosB.x < 0) + viewPosB.x = 0; + if (viewPosB.y < 0) + viewPosB.y = 0; + jViewport.setViewPosition (viewPosB); + } + public void initScale () { + initScale = Math.rint (Math.min (jAdecWatt.screenSize.width/realSize.getWidth (), jAdecWatt.screenSize.height/realSize.getHeight ())); + minScale = initScale/10; + maxScale = initScale*10; + scaleStep = minScale/2; + setScale (initScale); + } + public void setScale (double scale) { + scale = Math.rint (Math.max (minScale, Math.min (maxScale, scale))); + this.scale = scale; + currentSize = scaleModelToView (realSize); + setPreferredSize (currentSize); + selectionGraphics = createGraphicsLayer (jSelectionPane); + for (JItem jItem : selectedItems.values ()) + jItem.setScale (); + // XXX selectedAcc.setScale (); + updateSelectionLayer (); + repaint (); + jAdecWatt.stateNotifier.broadcastUpdate (JAdecWatt.BroadcastChangeScale); + JScrollPaneWorkspace jScrollPaneWorkspace = getJScrollPaneWorkspace (); + if (jScrollPaneWorkspace == null) + return; + jScrollPaneWorkspace.updateScale (); + } + + // ======================================== + public int levelModelToView (double level) { + return (int) (level*10); + } + public Point2D.Double scaleViewToModel (Point pos) { + return new Point2D.Double (pos.x/scale, pos.y/scale); + } + public DimensionDouble scaleViewToModel (Dimension size) { + return new DimensionDouble (size.width/scale, size.height/scale); + } + public Point scaleModelToView (Point2D pos) { + return new Point ((int)(pos.getX ()*scale), (int)(pos.getY ()*scale)); + } + public Dimension scaleModelToView (DimensionDouble size) { + return new Dimension ((int)(size.getWidth ()*scale), (int)(size.getHeight ()*scale)); + } + + // ======================================== + public void rotation (MouseEvent e) { + if (notEditable ()) + return; + for (String itemId : selectedItems.keySet ()) { + if (!workspace.containsItem (itemId)) + continue; + try { + // XXX et segm ? + JComp jComp = (JComp) selectedItems.get (itemId); + if (jComp.comp.getPropNoMouse (Prop.PropRot)) + continue; + jComp.rotation (SwingUtilities.convertMouseEvent (this, e, jComp)); + } catch (Exception e2) { + // XXX c'est un segm + } + } + updateSelectionLayer (); + } + Point firstClick, lastClick; + Point2D.Double refHandle; + DimensionDouble handleOff; + public void dragItems (MouseEvent e) { + if (notEditable () || firstClick == null) + return; + Point newPos = e.getPoint (); + + Point2D.Double newModelPos = new Point2D.Double (newPos.x/scale+handleOff.width, newPos.y/scale+handleOff.height); + setSelectedBound (e.isControlDown () ? null : workspace.getMagnetPoint (newModelPos, onGrid (newModelPos), closePixelsBounds/scale)); + + lastClick = newPos; + DimensionDouble delta = new DimensionDouble (newModelPos.x-refHandle.x, newModelPos.y-refHandle.y); + refHandle = newModelPos; + for (String itemId : selectedItems.keySet ()) { + if (!workspace.containsItem (itemId)) + continue; + JItem jItem = selectedItems.get (itemId); + if (jItem.getItem ().getPropNoMouse (Prop.PropPos)) + continue; + jItem.dragItem (delta); + } + updateSelectionLayer (); + } + public void dragAcc (MouseEvent e) { + if (notEditable () || lastClick == null) + return; + Point newPos = e.getPoint (); + Dimension delta = new Dimension (newPos.x-lastClick.x, newPos.y-lastClick.y); + lastClick = newPos; + selectedAcc.dragAcc (delta); + } + + // ======================================== + public void dropAcc (MouseEvent e) { + if (notEditable ()) + return; + try { + Point2D.Double realPos = scaleViewToModel (e.getPoint ()); + ArrayList dstItems = workspace.findItems (realPos, closePixelsItems/scale); + PermanentDB permanentDB = adecWatt.getPermanentDB (); + if (selectedAcc.getAcc ().getDirectUnit ().isDescendingFrom (permanentDB.getPowerPlugId ())) { + + + if (dstItems.size () < 1) { + eraseAcc (selectedAcc.getAcc ()); + return; + } + // rechercher un "avec prise" le plus proche + // XXX Il peut y avoir plusieurs items + ArrayList dstAccs = dstItems.get (0).findAccs (realPos, closePixelsAccs/scale); + // XXX Il peut y avoir plusieurs accs + // XXX prendre le premier acc compatible et libre + Acc dstAcc = dstAccs.size () < 1 ? null : dstAccs.get (0); + try { + // XXX et segm + storyConnect ((Comp) selectedAcc.getItem (), selectedAcc.getAcc (), (Comp) dstItems.get (0), dstAcc, permanentDB.getPowerSocketId ()); + } catch (Exception e2) { + // c'est un segm + } + } + if (dstItems.size () < 1) { + // si pas prise mais "avec prise" => prendre la première libre + eraseAcc (selectedAcc.getAcc ()); + return; + } + // XXX sinon traiter la gélatine + } catch (Exception e2) { + e2.printStackTrace (); + } finally { + setSelectedAcc (); + } + } + public void dropAcc (Accessory accessory, Point pos) { + if (notEditable () || accessory == null) + return; + ArrayList overlapItems = findItems (pos); + if (overlapItems.size () < 1) + return; + //|| isSticky (jItem.item)) + // XXX + workspace.storyAddAcc (overlapItems.get (0), accessory); + } + static public Point2D.Double onGrid (Point2D.Double pos) { + return new Point2D.Double (gridStep*Math.rint (pos.x/gridStep), gridStep*Math.rint (pos.y/gridStep)); + } + public void dropSegm (NonWorkspace model, Point mPos) { + workspace.storyAddSegm (model, onGrid (scaleViewToModel (mPos))); + } + public void dropComp (NonWorkspace model, Point mPos) { + workspace.storyAddComp (model, onGrid (scaleViewToModel (mPos))); + } + public void eraseAcc (Acc acc) { + workspace.storyRemoveAcc (acc); + } + public void cloneItem (Item item, Point pos) { + workspace.storyCloneItem (item, scaleViewToModel (pos)); + } + public void hideShowItem (List items, boolean hidden) { + workspace.storyHideShowItem (items, hidden); + } + public void eraseItem (List items) { + workspace.storyRemoveItems (items); + } + public void storyRotSelectedComp () { + // XXX et segm + if (notEditable ()) + return; + int nbSelected = selectedItems.size (); + if (nbSelected < 1) + return; + Vector items = new Vector (nbSelected); + Vector thetas = new Vector (nbSelected); + for (String itemId : selectedItems.keySet ()) { + if (!workspace.containsItem (itemId)) + continue; + Item item = selectedItems.get (itemId).getItem (); + if (item.getPropNoMouse (Prop.PropRot)) + continue; + items.add (item); + thetas.add (selectedItems.get (itemId).getCurrentThetaDegree ()); + } + workspace.storyRotItem (items, thetas); + } + public void storyMoveSelectedItem (MouseEvent e) { + if (notEditable ()) + return; + try { + if (firstClick == null || firstClick.equals (e.getPoint ())) + return; + int nbSelected = selectedItems.size (); + if (nbSelected < 1) + return; + Vector items = new Vector (nbSelected); + Vector poss = new Vector (nbSelected); + for (String itemId : selectedItems.keySet ()) { + if (!workspace.containsItem (itemId)) + continue; + Item item = selectedItems.get (itemId).getItem (); + if (item.getPropNoMouse (Prop.PropPos)) + continue; + items.add (item); + poss.add (selectedItems.get (itemId).getCurrentPos ()); + } + workspace.storyMoveItem (items, poss); + } catch (Exception e2) { + e2.printStackTrace (); + } finally { + firstClick = lastClick = null; + refHandle = null; + handleOff = null; + } + } + public void storyRotResizeItem (JItem jItem) { + if (notEditable ()) + return; + workspace.storyRotResize (jItem.getItem (), jItem.getCurrentPos (), + jItem.getCurrentThetaDegree (), jItem.getCurrentSize ()); + } + + public void storyConnect (Comp srcComp, Acc srcAcc, Comp dstComp, Acc dstAcc, String dstModelId) { + if (notEditable ()) + return; + if (dstAcc == null) + dstAcc = dstComp.findEmbeddedBaseOn (dstModelId); + // XXX accessory powerSocket libre ! + if (dstAcc == null || !dstAcc.getDirectUnit ().isDescendingFrom (dstModelId)) + return; + // XXX recherche d'autres objets ? + workspace.storyConnect (srcComp, srcAcc, dstComp.getId (), dstAcc.getId ()); + } + + // ======================================== + public void updateStory () { + updateSelection (); + } + + public void displaySetSelectionItems (Object... objects) { + setSelectedItems ((List) objects[1]); + } + + public void displayNewItem (Object... objects) { + updateSelection (); + repaint (); + } + + public void displayRemoveItem (Object... objects) { + updateSelection (); + //setSelectedItems (); + repaint (); + } + + public void displayUpdateItem (Object... objects) { + try { + Item item = (Item) objects[0]; + selectedItems.get (item.getId ()).setItem (item); + } catch (Exception e) { + } + repaint (); + } + public void displayUpdatePermItem (Object... objects) { + NonWorkspace permItem = (NonWorkspace) objects[0]; + UnitNode ancestor = (UnitNode) permItem.getUnitNode (); + boolean repaint = false; + for (Item item : workspace.getAllItems ()) + if (item.getModel ().getUnitNode ().isNodeAncestor (ancestor)) { + repaint = true; + break; + } + if (! repaint) + return; + repaint (); + } + public void displayChangePos (Object... objects) { + for (Object obj : objects) { + JItem jItem = updateJItem (obj); + if (jItem == null) + continue; + jItem.setCurrentPos (); + } + } + + public void displayChangeRotSize (Object... objects) { + for (Object obj : objects) { + JItem jItem = updateJItem (obj); + if (jItem == null) + continue; + jItem.setCurrentSize (); + } + } + + public void displayChangeRot (Object... objects) { + for (Object obj : objects) { + // XXX et segm + JItem jItem = updateJItem (obj); + if (jItem == null) + return; + try { + jItem.setCurrentThetaDegree (); + } catch (Exception e) { + // XXX c'est un segm + } + } + } + private JItem updateJItem (Object obj) { + Item item = (Item) obj; + JItem jItem = selectedItems.get (item.getId ()); + if (jItem == null) + return null; + jItem.setItem (item); + return jItem; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/JZones.java b/src/java/adecWatt/view/JZones.java new file mode 100644 index 0000000..8c81442 --- /dev/null +++ b/src/java/adecWatt/view/JZones.java @@ -0,0 +1,613 @@ +package adecWatt.view; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JSlider; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import misc.StateNotifier; +import misc.DimensionDouble; +import misc.Util; + +// XXX candidat "misc" +/** + Affiche des zones transparentes avec des poignées de déformation (bords ou coins). +*/ +@SuppressWarnings ("serial") public class JZones extends JLayeredPane { + + static public final int minPixels = 10; + static public final String + BroadcastSelectedLocationChange = "SelectedLocationChange", + BroadcastSelectedRateChange = "SelectedRateChange", + BroadcastSelectedChange = "SelectedChange", + BroadcastCreateZone = "CreateZone", + BroadcastChangeScale = "ChangeScale"; + static public final Color defineColor = new Color (128, 128, 128, 64); + + // ======================================== + public StateNotifier stateNotifier = new StateNotifier (); + + private DimensionDouble realSize; + private Rectangle2D.Double backgroundShape; + private double rate; + // gestion du zoom + private double scale = 1, initScale = 1, minScale = 1, maxScale = 1, scaleStep = 1; + private double minSide; + + /** Fond du panneau. */ + private BufferedImage background; + private AffineTransform bgat; + + public DimensionDouble getRealSize () { return realSize; } + public double getScale () { return scale; } + public Rectangle2D.Double getMaxRate (double rate) { + double width = realSize.width, height = realSize.height; + if (rate == 0 || rate == this.rate) + ; + else if (rate < this.rate) + width = rate*height; + else + height = width/rate; + return new Rectangle2D.Double (0, 0, width, height); + } + + public class Zone { + private Rectangle2D.Double rectangle; + private Color color; + private int rotation; + private Zone pair; + private BufferedImage image; + Rectangle2D.Double imageRectangle; + + public Zone (Rectangle2D.Double rectangle, Color color, BufferedImage image) { + this.rectangle = new Rectangle2D.Double (rectangle.x, rectangle.y, rectangle.width, rectangle.height); + this.color = color; + setImage (image); + } + public Zone (Rectangle2D.Double rectangle, Zone pair, BufferedImage image) { + this.rectangle = new Rectangle2D.Double (rectangle.x, rectangle.y, rectangle.width, rectangle.height); + this.color = pair.color; + this.pair = pair; + setImage (image); + } + public boolean hasPair () { return pair != null; } + public Zone getPair () { return pair; } + public BufferedImage getImage () { return image; } + public DimensionDouble getRealSize () { return realSize; } + public Rectangle2D.Double getRectangle () { return rectangle; } + public int getRotation () { return rotation; } + public void turnLeft () { setRotation (rotation+1); } + public void turnRight () { setRotation (rotation-1); } + public void setImage (BufferedImage image) { + this.image = image; + imageRectangle = null; + if (image == null) + return; + imageRectangle = new Rectangle2D.Double (0, 0, image.getWidth (), image.getHeight ()); + repaint (); + } + public void drawImage (Graphics2D g2) { + if (image == null) + return; + g2.drawImage (image, new AffineTransform (), null); + } + public double getScale () { + return rotation % 2 == 1 ? rectangle.width/pair.rectangle.height : rectangle.width/pair.rectangle.width; + } + private void setRotation (int rotation) { + rotation += 4; + rotation %= 4; + if (this.rotation == rotation) + return; + if ((this.rotation+rotation)%2 == 1) { + double tmp = rectangle.width; + rectangle.width = rectangle.height; + rectangle.height = tmp; + fitLandscape (); + } else if (selectedZone == this) + jZoneHandler.updateRectangle (rectangle); + this.rotation = rotation; + repaint (); + } + public void updatePairRate () { + if (pair == null) + return; + double rate = pair.rectangle.width/pair.rectangle.height; + if (rotation % 2 == 1) + rate = 1/rate; + setRate (rate); + } + private void setRate (double rate) { + double width = rectangle.width, height = rectangle.height; + double prevRate = width / height; + if (prevRate == rate) + return; + double maxWidth = realSize.width - rectangle.x, maxHeight = realSize.height - rectangle.y; + if (prevRate > 1) { + height = width/rate; + if (height > maxHeight) { + height = maxHeight; + width = rate*height; + } + } else { + width = rate*height; + if (width > maxWidth) { + width = maxWidth; + height = width/rate; + } + } + setBounds (rectangle.x, rectangle.y, width, height); + } + public void setLocation (double x, double y) { + x = Math.max (.0, Math.min (realSize.width-rectangle.width, x)); + y = Math.max (.0, Math.min (realSize.height-rectangle.height, y)); + rectangle.x = x; + rectangle.y = y; + if (selectedZone == this) + jZoneHandler.updateRectangle (rectangle); + repaint (); + stateNotifier.broadcastUpdate (BroadcastSelectedLocationChange); + } + public void setBounds (double x, double y, double width, double height) { + rectangle.width = Math.max (minSide, Math.min (realSize.width, width)); + rectangle.height = Math.max (minSide, Math.min (realSize.height, height)); + setLocation (x, y); + stateNotifier.broadcastUpdate (BroadcastSelectedRateChange); + } + public void fitLandscape () { + double rate = rectangle.width/rectangle.height; + if (rectangle.width > realSize.width) { + rectangle.width = realSize.width; + rectangle.height = rectangle.width/rate; + } + if (rectangle.height > realSize.height) { + rectangle.height = realSize.height; + rectangle.width = rate*rectangle.height; + } + rectangle.x = Math.min (rectangle.x, realSize.width - rectangle.width); + rectangle.y = Math.min (rectangle.y, realSize.height - rectangle.height); + if (selectedZone == this) + jZoneHandler.updateRectangle (rectangle); + } + public void projection (Graphics2D g2) { + Rectangle2D.Double refRectangle = pair == null ? imageRectangle : pair.rectangle; + double copyScale = rotation%2 == 1 ? rectangle.width/refRectangle.height : rectangle.width/refRectangle.width; + double theta = Math.PI*rotation/2; + double halfWidth = refRectangle.width/2, halfHeight = refRectangle.height/2; + g2.clip (rectangle); + g2.translate (rectangle.x, rectangle.y); + g2.scale (copyScale, copyScale); + if (rotation % 2 == 1) + g2.translate (halfHeight, halfWidth); + else + g2.translate (halfWidth, halfHeight); + g2.rotate (-theta); + g2.translate (-halfWidth, -halfHeight); + g2.translate (-refRectangle.x, -refRectangle.y); + } + }; + + // ======================================== + ArrayList zones = new ArrayList (); + private JZoneHandler jZoneHandler; + private boolean cornerSelection, createZone = true; + + public void setCornerSelection (boolean cornerSelection) { + if (this.cornerSelection == cornerSelection) + return; + this.cornerSelection = cornerSelection; + if (jZoneHandler != null) + jZoneHandler.setVisible (false); + jZoneHandler = new JZoneHandler (cornerSelection); + } + public void setCreateZone (boolean createZone) { + this.createZone = createZone; + repaint (); + } + public boolean setLandscape (boolean landscape) { + if (rate > 1 == landscape) + return false; + realSize = new DimensionDouble (realSize.height, realSize.width); + backgroundShape = new Rectangle2D.Double (.0, .0, realSize.width, realSize.height); + rate = realSize.width/realSize.height; + for (Zone zone : zones) + zone.fitLandscape (); + repaint (); + return true; + } + public void setCenterScale (double scale) { + JViewport jViewport = getJScrollPane ().getViewport (); + Rectangle prevView = jViewport.getViewRect (); + Point2D.Double realCenter = scaleViewToModel (new Point (prevView.x+prevView.width/2, prevView.y+prevView.height/2)); + setScale (scale); + Rectangle nextView = jViewport.getViewRect (); + Point viewCenter = scaleModelToView (realCenter); + viewCenter.translate (-nextView.width/2, -nextView.height/2); + if (viewCenter.x < 0) + viewCenter.x = 0; + if (viewCenter.y < 0) + viewCenter.y = 0; + jViewport.setViewPosition (viewCenter); + } + public void resetScale () { setScale (initScale); } + public void setScale (double scale) { + scale = Math.max (minScale, Math.min (maxScale, scale)); + this.scale = scale; + minSide = minPixels/scale; + setPreferredSize (scaleModelToView (realSize)); + if (selectedZone != null) + jZoneHandler.updateRectangle (selectedZone.rectangle); + if (background != null) + bgat = AffineTransform.getScaleInstance (realSize.width/background.getWidth (), realSize.height / background.getHeight ()); + repaint (); + stateNotifier.broadcastUpdate (BroadcastChangeScale); + } + + // ======================================== + public void setBackground (BufferedImage background) { + this.background = background; + setScale (scale); + } + + public JZones (DimensionDouble realSize, int maxSide) { + this.realSize = realSize; + setCornerSelection (true); + backgroundShape = new Rectangle2D.Double (.0, .0, realSize.width, realSize.height); + rate = realSize.width/realSize.height; + if (maxSide > 0) + initScale = maxSide/Math.max (realSize.getWidth (), realSize.getHeight ()); + scale = initScale; + minScale = initScale/10; + maxScale = initScale*10; + scaleStep = minScale/2; + addMouseListener (jZonesMouseAdapter); + addMouseMotionListener (jZonesMouseAdapter); + addMouseWheelListener (jZonesMouseAdapter); + setScale (scale); + } + + // ======================================== + public Zone addZone (Color color) { + return addZone (new Zone (getMaxRate (0), color, null)); + } + public Zone addZone (Color color, Rectangle2D.Double rectangle) { + return addZone (new Zone (rectangle, color, null)); + } + public Zone addZone (Color color, BufferedImage image) { + return addZone (new Zone (getMaxRate (((double)image.getWidth ())/image.getHeight ()), color, image)); + } + public Zone addZone (Zone pair, BufferedImage image) { + return addZone (new Zone (getMaxRate (pair.rectangle.width/pair.rectangle.height), pair, image)); + } + public Zone addZone (Zone zone) { + zones.add (zone); + repaint (); + return zone; + } + public void turnZoneLeft () { + if (selectedZone == null) + return; + selectedZone.turnLeft (); + } + public void turnZoneRight () { + if (selectedZone == null) + return; + selectedZone.turnRight (); + } + public void removeZone (Zone zone) { + if (zone == null) + return; + if (selectedZone == zone) + selectZone (null); + zones.remove (zone); + repaint (); + } + + public void paint (Graphics g) { + Graphics2D g2 = (Graphics2D) g; + AffineTransform iat = g2.getTransform (); + Shape clip = g2.getClip (); + g2.scale (scale, scale); + g2.setColor (Color.WHITE); + g2.fill (backgroundShape); + if (background != null) + g2.drawImage (background, bgat, null); + g2.setColor (Color.BLACK); + g2.setStroke (new BasicStroke ((float) (1/scale))); + g2.draw (backgroundShape); + for (Zone zone : zones) { + if (zone.pair == null && zone.image == null) + continue; + double refBgScale = zone.pair == null ? 1 : zone.pair.getRealSize ().width/zone.image.getWidth (); + g2.setTransform (iat); + g2.setClip (clip); + g2.scale (scale, scale); + zone.projection (g2); + AffineTransform bat = new AffineTransform (); + bat.scale (refBgScale, refBgScale); + g2.drawImage (zone.image, bat, null); + } + g2.setTransform (iat); + g2.setClip (clip); + g2.scale (scale, scale); + for (Zone zone : zones) { + Color color = zone.color; + Color aColor = new Color (color.getRed (), color.getGreen (), color.getBlue (), 64); + g2.setColor (aColor); + g2.fill (zone.rectangle); + } + g2.setTransform (iat); + g2.setColor (defineColor); + if (createZone && defineSelectionStart != null) { + Rectangle selection = new Rectangle (defineSelectionStart); + selection.add (defineSelectionEnd); + g2.fill (selection); + } + paintChildren (g); + } + + public DimensionDouble scaleViewToModel (Dimension size) { + return new DimensionDouble (size.width/scale, size.height/scale); + } + public Dimension scaleModelToView (DimensionDouble size) { + return new Dimension ((int)(size.getWidth ()*scale), (int)(size.getHeight ()*scale)); + } + public Point2D.Double scaleViewToModel (Point pos) { + return new Point2D.Double (pos.x/scale, pos.y/scale); + } + public Point scaleModelToView (Point2D pos) { + return new Point ((int)(pos.getX ()*scale), (int)(pos.getY ()*scale)); + } + + private JScrollPane getJScrollPane () { + for (Container parent = getParent () ; parent != null; parent = parent.getParent ()) + if (parent instanceof JScrollPane) + return (JScrollPane) parent; + return null; + } + public void scrollView (boolean horizontal, int delta) { + JScrollPane jScrollPane = getJScrollPane (); + JScrollBar jScrollBar = horizontal ? jScrollPane.getHorizontalScrollBar () : jScrollPane.getVerticalScrollBar (); + int min = jScrollBar.getMinimum (); + int max = jScrollBar.getMaximum (); + int step = (max-min)/10; + jScrollBar.setValue (Math.min (max, Math.max (min, jScrollBar.getValue ()+delta*step))); + } + + public void changeScale (Point mousePos, int delta) { + JViewport jViewport = getJScrollPane ().getViewport (); + Point viewPosA = jViewport.getViewPosition (); + Point2D.Double realPos = scaleViewToModel (mousePos); + setScale (delta < 0 ? scale+scaleStep : scale-scaleStep); + Point viewPosB = scaleModelToView (realPos); + viewPosB.translate (-mousePos.x+viewPosA.x, -mousePos.y+viewPosA.y); + if (viewPosB.x < 0) + viewPosB.x = 0; + if (viewPosB.y < 0) + viewPosB.y = 0; + jViewport.setViewPosition (viewPosB); + } + + // ======================================== + private Zone selectedZone; + public Zone getSelectedZone () { + return selectedZone; + } + public void selectLastZone () { + if (zones.size () < 0) + return; + selectZone (zones.get (zones.size ()-1)); + } + public void selectZone (Zone zone) { + if (selectedZone == zone) + return; + selectZoneQuiet (zone); + stateNotifier.broadcastDisplay (BroadcastSelectedChange, this, zone); + } + public Zone findPair (Zone pair) { + if (pair == null) { + return null; + } + for (Zone zone : zones) + if (zone.pair == pair) { + return zone; + } + return null; + } + public void selectZoneQuiet (Zone zone) { + selectedZone = zone; + if (selectedZone != null) + jZoneHandler.updateRectangle (selectedZone.rectangle); + jZoneHandler.setVisible (selectedZone != null); + } + + private Point defineSelectionStart, defineSelectionEnd; + private MouseAdapter jZonesMouseAdapter = new MouseAdapter () { + Point2D.Double mousePosOnZone; + public void mousePressed (MouseEvent e) { + if (SwingUtilities.isRightMouseButton (e)) { + selectZone (null); + return; + } + Point2D.Double posInPage = scaleViewToModel (e.getPoint ()); + ArrayList overlap = new ArrayList (); + for (Zone zone : zones) + if (zone.rectangle.contains (posInPage.x, posInPage.y)) + overlap.add (zone); + if (overlap.size () < 1) { + selectZone (null); + defineSelectionStart = defineSelectionEnd = e.getPoint (); + return; + } + JZones.this.selectZone (overlap.get ((zones.indexOf (selectedZone)+1)%overlap.size ())); + mousePosOnZone = posInPage; + mousePosOnZone.x -= selectedZone.rectangle.x; + mousePosOnZone.y -= selectedZone.rectangle.y; + } + public void mouseReleased (MouseEvent e) { + if (!createZone || defineSelectionStart == null) + return; + Rectangle selection = new Rectangle (defineSelectionStart); + selection.add (defineSelectionEnd); + defineSelectionStart = defineSelectionEnd = null; + Point2D.Double start = scaleViewToModel (selection.getLocation ()); + DimensionDouble dim = scaleViewToModel (selection.getSize ()); + Rectangle2D.Double area = new Rectangle2D.Double (start.x, start.y, dim.width, dim.height); + if (area.width > minSide && area.height > minSide) + stateNotifier.broadcastDisplay (BroadcastCreateZone, area); + repaint (); + } + public void mouseDragged (MouseEvent e) { + if (defineSelectionStart != null) { + defineSelectionEnd = e.getPoint (); + repaint (); + } + if (selectedZone == null) + return; + Point2D.Double posInPage = scaleViewToModel (e.getPoint ()); + selectedZone.setLocation (posInPage.x - mousePosOnZone.x, posInPage.y - mousePosOnZone.y); + } + public void mouseWheelMoved (MouseWheelEvent e) { + try { + if (0 != (e.getModifiersEx () & (MouseWheelEvent.SHIFT_MASK|MouseWheelEvent.SHIFT_DOWN_MASK))) + scrollView (true, e.getWheelRotation ()); + else if (0 != (e.getModifiersEx () & (MouseWheelEvent.CTRL_MASK|MouseWheelEvent.CTRL_DOWN_MASK))) + changeScale (e.getPoint (), e.getWheelRotation ()); + else + scrollView (false, e.getWheelRotation ()); + } catch (Exception e2) { + } + } + }; + + // ======================================== + static public final ImageIcon handlerImage = Util.loadActionIcon ("handler"); + public class JZoneHandler { + private boolean cornerSelection; + private double[] x = new double [4], y = new double [4]; + private JLabel[] handlers = new JLabel [4]; + private double oposedX, oposedY; + + public JZoneHandler (final boolean cornerSelection) { + this.cornerSelection = cornerSelection; + for (int i = 0; i < 4; i++) { + final JLabel handler = new JLabel (handlerImage); + final int index = i; + handlers [i] = handler; + handler.setSize (8, 8); + MouseAdapter mouseAdapter = new MouseAdapter () { + Point mousePosOnHandler; + public void mousePressed (MouseEvent e) { + if (SwingUtilities.isRightMouseButton (e)) { + selectZone (null); + return; + } + oposedX = x[(index+2)%4]; + oposedY = y[(index+2)%4]; + mousePosOnHandler = e.getPoint (); + } + public void mouseDragged (MouseEvent e) { + Point deltaMousePos = e.getPoint (); + deltaMousePos.x -= mousePosOnHandler.x; + deltaMousePos.y -= mousePosOnHandler.y; + Point2D.Double deltaInPage = scaleViewToModel (deltaMousePos); + double newX = Math.max (.0, Math.min (realSize.width, x[index]+deltaInPage.x)); + double newY = Math.max (.0, Math.min (realSize.height, y[index]+deltaInPage.y)); + if (cornerSelection) { + double cx = (oposedX+newX)/2; + double cy = (oposedY+newY)/2; + double width = Math.abs (oposedX-newX); + double height = Math.abs (oposedY-newY); + selectedZone.setBounds (cx - width/2, cy - height/2, width, height); + return; + } + Rectangle2D.Double rectangle = selectedZone.rectangle; + double rate = rectangle.width/rectangle.height; + if (index%2 == 0) { + double height = Math.max (minSide, index == 0 ? oposedY-newY : newY-oposedY); + double width = Math.max (minSide, Math.min (rate*height, Math.min (x[0], realSize.width - x[0])*2)); + height = width/rate; + selectedZone.setBounds (x[0]-width/2, index == 0 ? y[2]-height : y[0], width, height); + } else { + double width = Math.max (minSide, index == 3 ? oposedX-newX : newX-oposedX); + double height = Math.max (minSide, Math.min (width/rate, Math.min (y[1], realSize.height - y[1])*2)); + width = rate*height; + selectedZone.setBounds (index == 3 ? x[1]-width : x[3], y[1]-height/2, width, height); + } + } + }; + handler.addMouseListener (mouseAdapter); + handler.addMouseMotionListener (mouseAdapter); + JZones.this.add (handler); + JZones.this.setLayer (handler, 10+i); + handler.setVisible (false); + } + } + public void updateRectangle (Rectangle2D.Double rectangle) { + if (cornerSelection) { + x[0] = x[3] = rectangle.x; + y[0] = y[1] = rectangle.y; + x[1] = x[2] = rectangle.x+rectangle.width; + y[2] = y[3] = rectangle.y+rectangle.height; + } else { + x[3] = rectangle.x; + x[0] = x[2] = rectangle.x+rectangle.width/2; + x[1] = rectangle.x+rectangle.width; + y[0] = rectangle.y; + y[1] = y[3] = rectangle.y+rectangle.height/2; + y[2] = rectangle.y+rectangle.height; + } + for (int i = 0; i < 4; i++) + handlers[i].setLocation ((int) (x[i]*scale-4), (int) (y[i]*scale-4)); + } + public void setVisible (boolean visible) { + for (int i = 0; i < 4; i++) + handlers[i].setVisible (visible); + } + }; + + public class SizeSlider extends JSlider implements ChangeListener { + public SizeSlider () { + super (0, 200, 100); + setMajorTickSpacing (50); + setMinorTickSpacing (10); + setPaintTicks (true); + setSnapToTicks (true); + addChangeListener (this); + stateNotifier.addUpdateObserver (this, JZones.BroadcastChangeScale); + } + public void stateChanged (ChangeEvent e) { + setCenterScale (Math.pow (10, getValue ()/100.-1)*initScale); + } + public void updateChangeScale () { + removeChangeListener (this); + setValue ((int) (100*(Math.log10 (scale/initScale)+1))); + addChangeListener (this); + } + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/PrintWorkspace.java b/src/java/adecWatt/view/PrintWorkspace.java new file mode 100644 index 0000000..9a560aa --- /dev/null +++ b/src/java/adecWatt/view/PrintWorkspace.java @@ -0,0 +1,150 @@ +package adecWatt.view; + +//import java.awt.RenderingHints; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterJob; +import java.util.ArrayList; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import misc.DimensionDouble; +import misc.Log; +import misc.OwnFrame; + +import adecWatt.model.Prop; +import adecWatt.model.unit.Workspace; + +public class PrintWorkspace implements Printable { + + static public final int formatScale = 20; + static public final int labelSpace = 4; + + // ======================================== + static public void print (OwnFrame controller, PrinterJob printer, Workspace workspace) { + ArrayList jPreviewImpPtr = new ArrayList (); + try { + PrintWorkspace printWorkspace = new PrintWorkspace (workspace); + printWorkspace.resetPrint (controller, jPreviewImpPtr); + printer.setPrintable (printWorkspace); + printer.print (); + if (printWorkspace.canceled) { + printer.cancel (); + return; + } + return; + } catch (Throwable t) { + Log.keepLastException ("Printworkspace::print", t); + } + } + + // ======================================== + private Workspace workspace; + private Image printPage; + private BufferedImage workspaceImage, workspaceImageNoCircuit, posterImage, patchImage; + private JPanel patchJPanel; + private OwnFrame controller; + ArrayList jPreviewImpPtr; + boolean canceled; + + public PrintWorkspace (Workspace workspace) { + this.workspace = workspace; + workspaceImage = getIcon (workspace, 800, true); + workspaceImageNoCircuit = getIcon (workspace, 800, false); + try { + posterImage = workspace.getIconImage (Prop.PropPoster).reference; + } catch (Exception e) { + } + try { + patchJPanel = new JPatch (workspace.getPatch ()); + JFrame jFrame = new JFrame (); + jFrame.setVisible (false); + jFrame.getContentPane ().add (patchJPanel, BorderLayout.CENTER); + jFrame.pack (); + patchImage = new BufferedImage (patchJPanel.getWidth (), patchJPanel.getHeight (), BufferedImage.TYPE_INT_ARGB); + patchJPanel.paint (patchImage.getGraphics ()); + } catch (Exception e) { + } + } + public void resetPrint (OwnFrame controller, ArrayList jPreviewImpPtr) { + this.controller = controller; + this.jPreviewImpPtr = jPreviewImpPtr; + } + public synchronized int print (Graphics g1, PageFormat pf, int pageIndex) { + if (pageIndex > 0) + return NO_SUCH_PAGE; + if (jPreviewImpPtr.size () < 1) { + JPreviewImp jPreviewImp = new JPreviewImp (workspace.getRealSize (), + new DimensionDouble (pf.getImageableWidth (), pf.getImageableHeight ()), + workspaceImage, workspaceImageNoCircuit, posterImage, patchImage, 400); + jPreviewImpPtr.add (jPreviewImp); + if (JOptionPane.showConfirmDialog (controller.getJFrame (), jPreviewImp, misc.Bundle.getTitle ("Layout"), JOptionPane.YES_NO_OPTION) + != JOptionPane.YES_OPTION) { + canceled = true; + return NO_SUCH_PAGE; + } + } + Graphics2D printGraphics = (Graphics2D) g1; + printGraphics.translate ((int) pf.getImageableX ()+1, (int) pf.getImageableY ()); + print (printGraphics, 1, jPreviewImpPtr.get (0)); + return PAGE_EXISTS; + } + + // ======================================== + public void print (Graphics2D printGraphics, double lineWidth, JPreviewImp jPreviewImp) { + if (jPreviewImp.preview.zones.size () < 1) { + DimensionDouble printSize = jPreviewImp.preview.getRealSize (); + DimensionDouble realSize = jPreviewImp.workspace.getRealSize (); + double scale = Math.min (printSize.width/realSize.width, printSize.height/realSize.height); + printGraphics.scale (scale, scale); + workspace.print (printGraphics, lineWidth*scale, null, true); + return; + } + AffineTransform iat = printGraphics.getTransform (); + Shape clip = printGraphics.getClip (); + for (JZones.Zone zone : jPreviewImp.preview.zones) { + printGraphics.setTransform (iat); + printGraphics.setClip (clip); + zone.projection (printGraphics); + if (zone.hasPair ()) { + workspace.print (printGraphics, lineWidth*zone.getScale (), null, !jPreviewImp.noPrintCircuit.contains (zone)); + continue; + } + if (zone.getImage () == patchImage) { + patchJPanel.paint (printGraphics); + continue; + } + zone.drawImage (printGraphics); + } + } + + static public BufferedImage getIcon (Workspace workspace, int maxSide, boolean printCircuit) { + DimensionDouble realSize = workspace.getRealSize (); + double rate = realSize.width/realSize.height; + int width = maxSide, height = maxSide; + if (rate > 1) + height = (int) (width/rate); + else + width = (int) (rate*height); + BufferedImage result = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D printGraphics = (Graphics2D) result.getGraphics (); + //printGraphics.setRenderingHint (RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + printGraphics.setColor (Color.WHITE); + printGraphics.fillRect (0, 0, width, height); + double printScale = Math.min (width/realSize.width, height/realSize.height); + printGraphics.scale (printScale, printScale); + workspace.print (printGraphics, printScale, null, printCircuit); + return result; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/SpringUtilities.java b/src/java/adecWatt/view/SpringUtilities.java new file mode 100644 index 0000000..77f2ed7 --- /dev/null +++ b/src/java/adecWatt/view/SpringUtilities.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package adecWatt.view; + +import javax.swing.*; +import javax.swing.SpringLayout; +import java.awt.*; + +/** + * A 1.4 file that provides utility methods for + * creating form- or grid-style layouts with SpringLayout. + * These utilities are used by several programs, such as + * SpringBox and SpringCompactGrid. + */ +public class SpringUtilities { + /** + * A debugging utility that prints to stdout the component's + * minimum, preferred, and maximum sizes. + */ + static public void printSizes(Component c) { + System.out.println("minimumSize = " + c.getMinimumSize()); + System.out.println("preferredSize = " + c.getPreferredSize()); + System.out.println("maximumSize = " + c.getMaximumSize()); + } + + /** + * Aligns the first rows * cols + * components of parent in + * a grid. Each component is as big as the maximum + * preferred width and height of the components. + * The parent is made just big enough to fit them all. + * + * @param rows number of rows + * @param cols number of columns + * @param initialX x location to start the grid at + * @param initialY y location to start the grid at + * @param xPad x padding between cells + * @param yPad y padding between cells + */ + static public void makeGrid(Container parent, + int rows, int cols, + int initialX, int initialY, + int xPad, int yPad) { + SpringLayout layout; + try { + layout = (SpringLayout)parent.getLayout(); + } catch (ClassCastException exc) { + System.err.println("The first argument to makeGrid must use SpringLayout."); + return; + } + + Spring xPadSpring = Spring.constant(xPad); + Spring yPadSpring = Spring.constant(yPad); + Spring initialXSpring = Spring.constant(initialX); + Spring initialYSpring = Spring.constant(initialY); + int max = rows * cols; + + //Calculate Springs that are the max of the width/height so that all + //cells have the same size. + Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)). + getWidth(); + Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)). + getHeight(); + for (int i = 1; i < max; i++) { + SpringLayout.Constraints cons = layout.getConstraints( + parent.getComponent(i)); + + maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth()); + maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight()); + } + + //Apply the new width/height Spring. This forces all the + //components to have the same size. + for (int i = 0; i < max; i++) { + SpringLayout.Constraints cons = layout.getConstraints( + parent.getComponent(i)); + + cons.setWidth(maxWidthSpring); + cons.setHeight(maxHeightSpring); + } + + //Then adjust the x/y constraints of all the cells so that they + //are aligned in a grid. + SpringLayout.Constraints lastCons = null; + SpringLayout.Constraints lastRowCons = null; + for (int i = 0; i < max; i++) { + SpringLayout.Constraints cons = layout.getConstraints( + parent.getComponent(i)); + if (i % cols == 0) { //start of new row + lastRowCons = lastCons; + cons.setX(initialXSpring); + } else { //x position depends on previous component + cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST), + xPadSpring)); + } + + if (i / cols == 0) { //first row + cons.setY(initialYSpring); + } else { //y position depends on previous row + cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH), + yPadSpring)); + } + lastCons = cons; + } + + //Set the parent's size. + SpringLayout.Constraints pCons = layout.getConstraints(parent); + pCons.setConstraint(SpringLayout.SOUTH, + Spring.sum( + Spring.constant(yPad), + lastCons.getConstraint(SpringLayout.SOUTH))); + pCons.setConstraint(SpringLayout.EAST, + Spring.sum( + Spring.constant(xPad), + lastCons.getConstraint(SpringLayout.EAST))); + } + + /* Used by makeCompactGrid. */ + private static SpringLayout.Constraints getConstraintsForCell( + int row, int col, + Container parent, + int cols) { + SpringLayout layout = (SpringLayout) parent.getLayout(); + Component c = parent.getComponent(row * cols + col); + return layout.getConstraints(c); + } + + /** + * Aligns the first rows * cols + * components of parent in + * a grid. Each component in a column is as wide as the maximum + * preferred width of the components in that column; + * height is similarly determined for each row. + * The parent is made just big enough to fit them all. + * + * @param rows number of rows + * @param cols number of columns + * @param initialX x location to start the grid at + * @param initialY y location to start the grid at + * @param xPad x padding between cells + * @param yPad y padding between cells + */ + static public void makeCompactGrid(Container parent, + int rows, int cols, + int initialX, int initialY, + int xPad, int yPad) { + SpringLayout layout; + try { + layout = (SpringLayout)parent.getLayout(); + } catch (ClassCastException exc) { + System.err.println("The first argument to makeCompactGrid must use SpringLayout."); + return; + } + + //Align all cells in each column and make them the same width. + Spring x = Spring.constant(initialX); + for (int c = 0; c < cols; c++) { + Spring width = Spring.constant(0); + for (int r = 0; r < rows; r++) { + width = Spring.max(width, + getConstraintsForCell(r, c, parent, cols). + getWidth()); + } + for (int r = 0; r < rows; r++) { + SpringLayout.Constraints constraints = + getConstraintsForCell(r, c, parent, cols); + constraints.setX(x); + constraints.setWidth(width); + } + x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); + } + + //Align all cells in each row and make them the same height. + Spring y = Spring.constant(initialY); + for (int r = 0; r < rows; r++) { + Spring height = Spring.constant(0); + for (int c = 0; c < cols; c++) { + height = Spring.max(height, + getConstraintsForCell(r, c, parent, cols). + getHeight()); + } + for (int c = 0; c < cols; c++) { + SpringLayout.Constraints constraints = + getConstraintsForCell(r, c, parent, cols); + constraints.setY(y); + constraints.setHeight(height); + } + y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); + } + + //Set the parent's size. + SpringLayout.Constraints pCons = layout.getConstraints(parent); + pCons.setConstraint(SpringLayout.SOUTH, y); + pCons.setConstraint(SpringLayout.EAST, x); + } +} diff --git a/src/java/adecWatt/view/jProp/JAutoComboBox.java b/src/java/adecWatt/view/jProp/JAutoComboBox.java new file mode 100644 index 0000000..fb86d5c --- /dev/null +++ b/src/java/adecWatt/view/jProp/JAutoComboBox.java @@ -0,0 +1,72 @@ +package adecWatt.view.jProp; + +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.Vector; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.text.JTextComponent; + +@SuppressWarnings ("serial") +public class JAutoComboBox extends JComboBox { + + static public interface Filter { + public Vector match (String value); + } + + private JTextComponent editor; + private final Filter filter; + + public JTextComponent getEditorComponent () { return editor; } + + public JAutoComboBox (Filter filter) { + this.filter = filter; + setEditable (true); + editor = (JTextComponent) (getEditor ().getEditorComponent ()); + updateFilter (); + editor.setFocusable (true); + editor.addKeyListener (new KeyAdapter() { + public void keyReleased (KeyEvent key) { + switch (key.getKeyCode ()) { + case KeyEvent.VK_ENTER: + hidePopup (); + return; + } + if (key.getKeyChar () == KeyEvent.CHAR_UNDEFINED) + return; + updateFilter (); + } + }); + } + + private boolean needUpdate (Vector founds) { + int nbItems = getItemCount (); + if (founds == null) + return nbItems != 0; + if (nbItems != founds.size ()) + return true; + int i = 0; + for (String val : founds) + if (!val.equals (getItemAt (i))) + return true; + return false; + } + public void updateFilter () { + String text = editor.getText (); + Vector founds = filter.match (text); + if (needUpdate (founds)) + if (founds == null) + removeAllItems (); + else + setModel (new DefaultComboBoxModel (founds)); + setSelectedIndex (-1); + editor.setText (text); + try { + if (founds != null && founds.size () > 0) + showPopup (); + else + hidePopup (); + } catch (Exception e) { + } + } +} diff --git a/src/java/adecWatt/view/jProp/JFilePreview.java b/src/java/adecWatt/view/jProp/JFilePreview.java new file mode 100644 index 0000000..be7c6ce --- /dev/null +++ b/src/java/adecWatt/view/jProp/JFilePreview.java @@ -0,0 +1,70 @@ +package adecWatt.view.jProp; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.swing.ImageIcon; +import javax.swing.JComponent; + +@SuppressWarnings("serial") +public class JFilePreview extends JComponent { + + static public int maxInSide = 100; + static public int border = 5; + static public int maxOutSide = maxInSide+2*border; + static public Dimension previewDim = new Dimension (maxOutSide, maxOutSide); + + protected ImageIcon thumbnail = null; + protected long maxSize; + + public JFilePreview (long maxSize) { + this.maxSize = maxSize; + setPreferredSize (previewDim); + } + + public void setFile (File file, boolean horizontalSpin) { + thumbnail = getIcon (file, maxInSide, maxSize); + if (thumbnail != null && horizontalSpin) { + int width = thumbnail.getIconWidth (); + int height = thumbnail.getIconHeight (); + AffineTransform at = AffineTransform.getScaleInstance (horizontalSpin ? -1 : 1, 1); + at.translate (horizontalSpin ? -width : 0, 0); + BufferedImage image = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); + image.createGraphics ().drawImage (thumbnail.getImage (), at, null); + thumbnail = new ImageIcon (image); + } + repaint (); + } + + static public ImageIcon getIcon (File file, int thumbSide, long maxSize) { + if (file == null || (maxSize > 0 && file.length () > maxSize)) + return null; + ImageIcon tmpIcon = new ImageIcon (file.getPath ()); + if (tmpIcon == null) + return null; + if (tmpIcon.getIconWidth () > tmpIcon.getIconHeight ()) { + if (tmpIcon.getIconWidth () > thumbSide) + tmpIcon = new ImageIcon (tmpIcon.getImage ().getScaledInstance (thumbSide, -1, Image.SCALE_DEFAULT)); + } else { + if (tmpIcon.getIconHeight () > thumbSide) + tmpIcon = new ImageIcon (tmpIcon.getImage ().getScaledInstance (-1, thumbSide, Image.SCALE_DEFAULT)); + } + return tmpIcon; + } + + protected void paintComponent (Graphics g) { + if (thumbnail == null) + return; + 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/adecWatt/view/jProp/JImagePopup.java b/src/java/adecWatt/view/jProp/JImagePopup.java new file mode 100644 index 0000000..678b812 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JImagePopup.java @@ -0,0 +1,655 @@ +package adecWatt.view.jProp; + +import javax.swing.JProgressBar; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Hashtable; +import java.util.List; +import java.util.TreeSet; +import java.util.Vector; +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JViewport; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.filechooser.FileNameExtensionFilter; + +import misc.Bundle; +import misc.Config; +import misc.ImagePreview; +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCNL; + +import adecWatt.control.AdecWattManager; +import adecWatt.model.PreviewCache; +import adecWatt.model.ImageDB; +import adecWatt.view.JProp; +import adecWatt.view.JStringSet; + +@SuppressWarnings ("serial") public class JImagePopup extends JPopupMenu implements ActionListener { + + // ======================================== + static public final String + actionTag = "Tag", + actionAdd = "Add", + actionUpdate = "Update", + actionRemove = "Remove", + actionValidate = "Validate", + actionHorizontalSpin = "HorizontalSpin", + actionFilter = "Filter", + actionNoFilter = "NoFilter"; + static public final Vector emptyTag = new Vector (); + + // ======================================== + static public final List + popupActionsNames = Arrays.asList (AdecWattManager.actionRemoveImage, + AdecWattManager.actionChangeImage, + AdecWattManager.actionUnchange), + iconActionsNames = Arrays.asList (actionTag, actionAdd, actionUpdate, actionRemove, actionValidate); + @SuppressWarnings ("unchecked") + static public final Hashtable actionsMethod = + Util.collectMethod (JImagePopup.class, + popupActionsNames, iconActionsNames); + + public void actionPerformed (ActionEvent e) { + Util.actionPerformed (actionsMethod, e, this); + } + + // ======================================== + static public int thumbSide = 40; + static public Dimension thumbDim = new Dimension (thumbSide, thumbSide); + static public final int MAX_FILE_PREVIEW = 1024*1024; + static public final int MAX_COL = 10; + static public final int MAX_VISIBLE_LINE = 5; + static public final int horizontalThickness = 2, verticalThickness = 4, selectedThickness = 1; + static public Color selectionForeground = new Color (0x63, 0x82, 0xbf); + static public Color selectionBackground = new Color (0xb8, 0xcf, 0xe5); + static public Color standardBackground = new Color (0xee, 0xee, 0xee); + static public final Border emptyBorder = BorderFactory.createEmptyBorder (horizontalThickness, verticalThickness, + horizontalThickness, verticalThickness); + static public final Border selectedBorder = + BorderFactory.createCompoundBorder (BorderFactory.createLineBorder (selectionForeground, selectedThickness), + BorderFactory.createEmptyBorder (horizontalThickness-selectedThickness, verticalThickness-selectedThickness, + horizontalThickness-selectedThickness, verticalThickness-selectedThickness)); + static public final Dimension DIM_AREA = new Dimension (10+horizontalThickness+MAX_COL*(thumbSide+horizontalThickness), + 10+verticalThickness+MAX_VISIBLE_LINE*(thumbSide+verticalThickness)); + + // ======================================== + ImageDB imageDB; + boolean horizontalSpin; + + int nbImages; + Vector nameList; + + JFilePreview preview = new JFilePreview (MAX_FILE_PREVIEW); + JLabel previewId = new JLabel (" ", SwingConstants.CENTER); + JList previewTags = new JList (emptyTag); + JPanel selectionPanel; + JViewport filesViewPort; + JPanel filesPanel; + JProp jProp; + JLabel refLabel; + JTextField filterTF = new JTextField ("", 16); + JTextField noFilterTF = new JTextField ("", 16); + Vector namesLocals; + Font localFont, normalFont; + JProgressBar progressBar; + + public JImagePopup (JLabel jLabel, Point pos, final JProp jProp, ImageDB imageDB) { + this.imageDB = imageDB; + this.jProp = jProp; + refLabel = jLabel; + Util.addMenuItem (popupActionsNames, this, this); + show (jLabel, pos.x, pos.y); + DocumentListener documentListener = new DocumentListener () { + public void changedUpdate (DocumentEvent e) { + doFilter (); + } + public void insertUpdate (DocumentEvent e) { changedUpdate (e); } + public void removeUpdate (DocumentEvent e) { changedUpdate (e); } + }; + filterTF.getDocument ().addDocumentListener (documentListener); + noFilterTF.getDocument ().addDocumentListener (documentListener); + (new Thread () { + public void run () { + updateNamesLocals (); + doFilter (); + if (nbSelection > 0) + return; + try { + setSelection (jProp.getLastValue ()); + } catch (Exception e) { + } + updatePreview (); + } + }).start (); + previewTags.setForeground (Color.GRAY); + previewTags.setBackground (getBackground ()); + previewId.setForeground (Color.GRAY); + + normalFont = getFont (); + localFont = normalFont.deriveFont (Font.ITALIC, normalFont.getSize ()); + selectionPanel = Util.getGridBagPanel (); + horizontalSpin = jProp.getHorizontalSpin (); + progressBar = new JProgressBar (0, 100); + progressBar.setValue (0); + + JPanel cmdLine = new JPanel (); + Util.addIconButton (iconActionsNames, this, cmdLine); + cmdLine.add (Util.newCheckIcon (actionHorizontalSpin, new ActionListener () { + public void actionPerformed (ActionEvent e) { + horizontalSpin = ((JCheckBox)e.getSource ()).isSelected (); + updatePreview (); + } + }, horizontalSpin)); + Util.addIconButton (actionFilter, null, cmdLine); + cmdLine.add (filterTF); + Util.addIconButton (actionNoFilter, null, cmdLine); + cmdLine.add (noFilterTF); + Util.unBoxButton (cmdLine); + filesPanel = new JPanel (null); + JPanel filesPanel2 = new JPanel (); + filesPanel2.add (filesPanel); + JScrollPane filesScrollPane = Util.getJScrollPane (filesPanel2); + filesPanel2.addMouseListener (new MouseAdapter () { + public void mousePressed (MouseEvent e) { + if (!SwingUtilities.isLeftMouseButton (e)) + return; + selectionPanel.requestFocusInWindow (); + clearSelection (); + updatePreview (); + } + }); + filesScrollPane.setPreferredSize (DIM_AREA); + filesViewPort = filesScrollPane.getViewport (); + JScrollPane tagsScrollPane = Util.getJScrollPane (previewTags); + tagsScrollPane.setPreferredSize (JFilePreview.previewDim); + JPanel side = new JPanel (new BorderLayout ()); + side.add (previewId, BorderLayout.NORTH); + side.add (preview, BorderLayout.CENTER); + side.add (tagsScrollPane, BorderLayout.SOUTH); + Util.addComponent (filesScrollPane, selectionPanel, GBC); + Util.addComponent (side, selectionPanel, GBCNL); + Util.addComponent (progressBar, selectionPanel, GBCNL); + Util.addComponent (cmdLine, selectionPanel, GBCNL); + + selectionPanel.addKeyListener (new KeyAdapter () { + public void keyPressed (KeyEvent e) { + switch (e.getKeyCode ()) { + case KeyEvent.VK_A: + if (e.isControlDown ()) { + selectRange (0, nbImages-1); + setCursorIndex (lastSelection); + } + return; + case KeyEvent.VK_HOME: + setCursorIndex (0); + return; + case KeyEvent.VK_END: + setCursorIndex (nbImages-1); + return; + } + if (cursorIndex < 0 || cursorIndex > nbImages-1) + return; + int nextCursorIndex = cursorIndex; + switch (e.getKeyCode ()) { + case KeyEvent.VK_SPACE: + if (e.isControlDown ()) + nameList.get (cursorIndex).toggleSelection (); + else + setSelection (cursorIndex, true); + return; + case KeyEvent.VK_UP: + case KeyEvent.VK_KP_UP: + nextCursorIndex -= MAX_COL; + break; + case KeyEvent.VK_DOWN: + case KeyEvent.VK_KP_DOWN: + nextCursorIndex += MAX_COL; + break; + case KeyEvent.VK_LEFT: + case KeyEvent.VK_KP_LEFT: + nextCursorIndex--; + break; + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_KP_RIGHT: + nextCursorIndex++; + break; + default: + return; + } + if (nextCursorIndex == cursorIndex || + nextCursorIndex < 0 || + nextCursorIndex > nbImages-1) + return; + setCursorIndex (nextCursorIndex); + if (e.isShiftDown ()) + selectRange (beginSelection, nextCursorIndex); + else + beginSelection = lastSelection = nextCursorIndex; + } + }); + } + + public void chooseIconImage (JLabel attach) { + updatePreview (); + if (JOptionPane.showConfirmDialog (attach, selectionPanel, + Bundle.getTitle ("SelectImage"), + JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION || nbSelection < 1) + return; + jProp.setSpin (horizontalSpin); + jProp.setVal (Util.getBase (nameList.get (minSelection).nameLocal.fileName)); + } + + private String splitFilter (String pattern, TreeSet set) { + String part = null; + for (String word : pattern.toLowerCase ().split ("\\s")) { + if (part != null) { + set.add (part); + part = null; + } + if (!word.isEmpty ()) { + part = word; + } + } + return part; + } + + public synchronized void doFilter () { + TreeSet setToKeep = new TreeSet (); + String partToKeep = splitFilter (filterTF.getText (), setToKeep); + boolean noTag = filterTF.getText ().length () > 0 && partToKeep == null && setToKeep.size () < 1; + TreeSet setToForget = new TreeSet (); + String partToForget = splitFilter (noFilterTF.getText (), setToForget); + Vector result = new Vector (namesLocals.size ()); + for (ImageDB.NameLocal namesLocal : namesLocals) { + Collection tags = imageDB.getTags (namesLocal.fileName); + if (noTag && tags != null) + continue; + if (partToKeep != null && !Util.containsPart (partToKeep, tags)) + continue; + if (setToKeep.size () > 0 && !Util.containsOne (setToKeep, tags)) + continue; + if (partToForget != null && Util.containsPart (partToForget, tags)) + continue; + if (setToForget.size () > 0 && Util.containsOne (setToForget, tags)) + continue; + result.add (namesLocal); + } + setFilesPanel (result); + } + + public void setFilesPanel (Vector namesLocals) { + filesViewPort.invalidate (); + nbSelection = 0; + beginSelection = lastSelection = 0; + cursorIndex = -1; + nbImages = namesLocals.size (); + nameList = new Vector (nbImages); + for (ImageDB.NameLocal nameLocal: namesLocals) + nameList.add (new HighlightFile (nameLocal)); + filesPanel.removeAll (); + GridLayout gridLayout = new GridLayout (0, MAX_COL); + filesPanel.setLayout (gridLayout); + for (int i = 0 ; i < nbImages; i++) { + HighlightFile highlightFile = nameList.get (i); + highlightFile.index = i; + filesPanel.add (highlightFile); + } + selectionPanel.setFocusable (true); + filesViewPort.setViewPosition (new Point (0, 0)); + filesViewPort.repaint (); + filesViewPort.validate (); + } + + int cursorIndex = -1, minSelection, maxSelection, nbSelection; + int beginSelection, lastSelection; + public void clearSelection () { + setCursorIndex (-1); + if (nbSelection > 0) + for (int i = minSelection; i <= maxSelection; i++) + nameList.get (i).setSelection (false); + nbSelection = minSelection = maxSelection = beginSelection = lastSelection = 0; + } + + public void setCursorIndex (int newVal) { + if (cursorIndex == newVal) + return; + if (cursorIndex >= 0) + nameList.get (cursorIndex).borderSelection (false); + cursorIndex = newVal; + if (cursorIndex < 0) + return; + HighlightFile hf = nameList.get (cursorIndex); + hf.borderSelection (true); + hf.checkVisible (); + } + + public synchronized void setSelection (String name) { + if (name == null || name.isEmpty ()) + return; + name = Util.getBase (name); + for (int i = 0; i < nbImages; i++) + if (name.equals (Util.getBase (nameList.get (i).nameLocal.fileName))) { + setSelection (i, true); + return; + } + } + public void setSelection (int index, boolean clearSelection) { + if (clearSelection) + clearSelection (); + setCursorIndex (index); + if (index < 0 || index >= nbImages) + return; + addSelection (index); + beginSelection = lastSelection = index; + } + public void selectRange (int start, int stop) { + int minRange = Integer.min (start, stop); + int maxRange = Integer.max (start, stop); + int minOldRange = Integer.min (beginSelection, lastSelection); + int maxOldRange = Integer.max (beginSelection, lastSelection); + beginSelection = start; + lastSelection = stop; + if (nbSelection > 0) + for (int i = minOldRange; i <= maxOldRange; i++) { + HighlightFile name = nameList.get (i); + if (name == null || !name.isSelected) + continue; + name.setSelection (false); + nbSelection--; + } + for (int i = minRange; i <= maxRange; i++) { + HighlightFile name = nameList.get (i); + if (name == null || name.isSelected) + continue; + nameList.get (i).setSelection (true); + nbSelection++; + } + if (nbSelection > 0) { + minSelection = Math.min (minSelection, minRange); + maxSelection = Math.max (maxSelection, maxRange); + } + updateMinMax (); + updatePreview (); + } + public void addSelection (int index) { + HighlightFile name = nameList.get (index); + if (name == null) + return; + name.setSelection (true); + name.checkVisible (); + if (nbSelection > 0) { + minSelection = Math.min (minSelection, index); + maxSelection = Math.max (maxSelection, index); + } else + minSelection = maxSelection = index; + nbSelection++; + updatePreview (); + } + public void removeSelection (int index) { + HighlightFile name = nameList.get (index); + if (name == null) + return; + name.setSelection (false); + nbSelection--; + updateMinMax (); + updatePreview (); + } + public void updateMinMax () { + if (nbSelection < 1) + return; + for (int i = minSelection; i <= maxSelection; i++) + if (nameList.get (i).isSelected) { + minSelection = i; + break; + } + for (int i = maxSelection; i >= minSelection; i--) + if (nameList.get (i).isSelected) { + maxSelection = i; + break; + } + if (cursorIndex < minSelection) + nameList.get (minSelection).checkVisible (); + if (cursorIndex > maxSelection) + nameList.get (maxSelection).checkVisible (); + } + public void updatePreview () { + if (nbSelection < 1) { + preview.setFile (null, false); + previewId.setText (""); + previewTags.setListData (emptyTag); + Util.packWindow (previewTags); + return; + } + nameList.get (minSelection).preview (); + } + public void updateNamesLocals () { + namesLocals = imageDB.listImage (); + progressBar.setStringPainted (true); + progressBar.setMaximum (namesLocals.size ()); + progressBar.setValue (0); + int done = 0; + PreviewCache previewCache = imageDB.previewCache; + previewCache.prepareClean (); + for (ImageDB.NameLocal nameLocal: namesLocals) { + nameLocal.icon = previewCache.getIcon (imageDB.getFile (nameLocal.fileName, nameLocal.isLocal)); + done++; + progressBar.setValue (done); + } + previewCache.clean (); + progressBar.setValue (0); + progressBar.setStringPainted (false); + } + + // ======================================== + class HighlightFile extends JLabel { + public int index; + public ImageDB.NameLocal nameLocal; + public boolean isSelected; + + public HighlightFile (ImageDB.NameLocal nameLocal) { + super (nameLocal.icon, SwingConstants.CENTER); + setMinimumSize (thumbDim); + setPreferredSize (thumbDim); + setSize (thumbDim); + this.nameLocal = nameLocal; + setFont (nameLocal.isLocal ? localFont : normalFont); + setBorder (emptyBorder); + setOpaque (true); + setBackground (standardBackground); + addMouseListener (new MouseAdapter () { + public void mousePressed (MouseEvent e) { + if (!SwingUtilities.isLeftMouseButton (e)) + return; + selectionPanel.requestFocusInWindow (); + setCursorIndex (index); + if (e.isControlDown ()) { + beginSelection = index; + lastSelection = index; + toggleSelection (); + return; + } + if (e.isShiftDown ()) { + selectRange (beginSelection, index); + return; + } + JImagePopup.this.setSelection (index, true); + } + }); + } + + public void toggleSelection () { + if (isSelected) + removeSelection (index); + else + addSelection (index); + } + public void borderSelection (boolean isSelected) { + setBorder (isSelected ? selectedBorder : emptyBorder); + } + + public void setSelection (boolean isSelected) { + setBackground (isSelected ? selectionBackground : standardBackground); + this.isSelected = isSelected; + } + public void preview () { + preview.setFile (imageDB.getFile (nameLocal.fileName, nameLocal.isLocal), horizontalSpin); + previewId.setText (Util.getBase (nameLocal.fileName)); + previewTags.setListData (emptyTag); + Collection tags = imageDB.getTags (nameLocal.fileName); + if (tags == null) { + Util.packWindow (previewTags); + return; + } + previewTags.setListData (new Vector (tags)); + Util.packWindow (previewTags); + } + + public void checkVisible () { + Rectangle nameBounds = getBounds (); + Rectangle viewBounds = filesViewPort.getViewRect (); + if (!viewBounds.contains (nameBounds)) + filesViewPort.setViewPosition (new Point (0, nameBounds.y)); + } + } + + // ======================================== + public void actionRemoveImage () { + jProp.removeVal (); + }; + public void actionChangeImage () { + chooseIconImage (refLabel); + } + public void actionUnchange () { + jProp.unchangeVal (); + } + + // ======================================== + public void actionTag () { + try { + if (nbSelection < 1) + return; + String imageName = Util.getBase (nameList.get (minSelection).nameLocal.fileName); + JStringSet jStringSet = new JStringSet (imageDB.getTags (imageName)); + jStringSet.init (); + if (JOptionPane.showConfirmDialog (refLabel, + jStringSet, + null, JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) + return; + jStringSet.confirm (); + imageDB.putTags (imageName, jStringSet.getSet ()); + doFilter (); + setSelection (imageName); + } finally { + selectionPanel.requestFocusInWindow (); + } + } + + static public JFileChooser jFileChooser = new JFileChooser (Config.getString ("ImageDirName", "")); + public boolean chooseFile () { + jFileChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("ImageFilter"), PreviewCache.imageExtentions)); + jFileChooser.setAccessory (new ImagePreview (jFileChooser, MAX_FILE_PREVIEW)); + jFileChooser.setFileSelectionMode (JFileChooser.FILES_ONLY); + if (jFileChooser.showOpenDialog (selectionPanel) != JFileChooser.APPROVE_OPTION) + return false; + Config.setFile ("ImageDirName", jFileChooser.getSelectedFile ().getParentFile ()); + return true; + } + + public void actionAdd () { + jFileChooser.setMultiSelectionEnabled (true); + if (!chooseFile ()) + return; + String last = null; + for (File file : jFileChooser.getSelectedFiles ()) + last = imageDB.addImage (file); + updateNamesLocals (); + doFilter (); + // XXX sélection multiple + setSelection (last); + } + public void actionUpdate () { + if (nbSelection != 1) + return; + jFileChooser.setMultiSelectionEnabled (false); + if (!chooseFile ()) + return; + String newImageName = imageDB.updateImage (nameList.get (minSelection).nameLocal, jFileChooser.getSelectedFile ()); + updateNamesLocals (); + doFilter (); + setSelection (newImageName); + } + public void actionRemove () { + if (nbSelection < 1) + return; + boolean removed = false; + TreeSet selectedNames = new TreeSet (); + for (int i = minSelection; i <= maxSelection; i++) { + HighlightFile name = nameList.get (i); + if (!name.isSelected || !name.nameLocal.isLocal) + continue; + imageDB.removeImage (name.nameLocal.fileName); + removed = true; + selectedNames.add (name.nameLocal.fileName); + } + if (!removed) + return; + updateNamesLocals (); + doFilter (); + for (String name : selectedNames) + setSelection (name); + } + public void actionValidate () { + if (nbSelection < 1) + return; + TreeSet imageNames = new TreeSet (); + TreeSet imageTagNames = new TreeSet (); + for (int i = minSelection; i <= maxSelection; i++) { + HighlightFile name = nameList.get (i); + if (!name.isSelected) + continue; + imageTagNames.add (name.nameLocal.fileName); + if (!name.nameLocal.isLocal) + continue; + imageNames.add (name.nameLocal.fileName); + } + imageDB.promoteTag (imageTagNames); // XXX a changé de nom + if (imageNames.size () == 0) + return; + System.err.println ("coucou actionValidate:"+imageNames); + imageDB.renameVisitor (imageNames); + imageDB.promote (imageNames); // XXX a changé de nom + updateNamesLocals (); + doFilter (); + } + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPImage.java b/src/java/adecWatt/view/jProp/JPImage.java new file mode 100644 index 0000000..8352fb4 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPImage.java @@ -0,0 +1,65 @@ +package adecWatt.view.jProp; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; + +import misc.ScaledImage; +import misc.Util; + +import adecWatt.model.ImageDB; +import adecWatt.view.JEditable; +import adecWatt.view.JProp; +import static adecWatt.model.Prop.PropMix; + +public abstract class JPImage extends JProp { + // ======================================== + protected JLabel jImage = new JLabel (); + protected ScaledImage scaledImage; + protected ImageDB rightDB; + + public JPImage (String propName, JEditable jEditable) { + super (propName, jEditable); + jImage.setHorizontalAlignment (SwingConstants.CENTER); + } + + protected void updateView () { + setImage (); + Util.packWindow (jImage); + } + + protected abstract ImageIcon getFitImage (); + protected void setImage () { + scaledImage = null; + if (lastValue == null) { + jImage.setIcon (Util.loadActionIcon ("EmptyIcon")); + return; + } + if (lastValue == PropMix) { + jImage.setIcon (Util.loadActionIcon ("MixIcon")); + return; + } + scaledImage = rightDB.getImage (lastValue, horizontalSpin); + if (scaledImage == null) { + jImage.setIcon (Util.loadActionIcon ("BreakIcon")); + return; + } + jImage.setIcon (getFitImage ()); + } + + protected void setPopup () { + jImage.addMouseListener (new MouseAdapter () { + public void mousePressed (MouseEvent e) { + System.err.flush (); + if (!SwingUtilities.isRightMouseButton (e)) + return; + new JImagePopup (jImage, e.getPoint (), JPImage.this, rightDB); + } + }); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPLabel.java b/src/java/adecWatt/view/jProp/JPLabel.java new file mode 100644 index 0000000..cab11b9 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPLabel.java @@ -0,0 +1,69 @@ +package adecWatt.view.jProp; + +import java.util.HashSet; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.text.JTextComponent; + +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCLNL; + +import adecWatt.view.JEditable; +import adecWatt.view.JProp; +import static adecWatt.model.Prop.PropMix; + +public abstract class JPLabel extends JProp { + + // ======================================== + protected JTextComponent[] editors; + protected HashSet unchanged = new HashSet (); + + protected boolean verify (JTextComponent editor) { + return true; + } + + public void setUnchange (JTextComponent editor, boolean unchange) { + super.setUnchange (editor, unchange); + if (unchange) + unchanged.add (editor); + else + unchanged.remove (editor); + verify (editor); + } + + // ======================================== + public JPLabel (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + protected abstract JComponent getEditor (); + protected JComponent getValue () { + if (lastValue == null) + return null; + if (lastValue == PropMix) + return getUnknownLabel (); + return new JLabel (lastValue); + } + + protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + JComponent jValue = edit ? getEditor () : getValue (); + if (jValue == null) + return; + Util.addComponent (localizedUserLabel.getJLabel (), jPropList, GBC); + Util.addComponent (new JLabel (" : "), jPropList, GBC); + Util.addComponent (jValue, jPropList, GBCLNL); + } + + // ======================================== + public String getLastValue () { + String val = editors[0].getText (); + if (unchanged.size () > 0) + val = PropMix; + return val; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPMultiValues.java b/src/java/adecWatt/view/jProp/JPMultiValues.java new file mode 100644 index 0000000..7e39393 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPMultiValues.java @@ -0,0 +1,116 @@ +package adecWatt.view.jProp; + +import java.text.NumberFormat; +import javax.swing.InputVerifier; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.text.JTextComponent; + +import adecWatt.view.JEditable; +import static adecWatt.model.Prop.DoubleMix; +import static adecWatt.model.Prop.PropMix; +import static adecWatt.model.Prop.numberFormat; + +public abstract class JPMultiValues extends JPLabel { + + // ======================================== + protected NumberFormat getNumberFormat () { return numberFormat; } + + // ======================================== + public JPMultiValues (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + protected boolean verify (JTextComponent editor) { + editor.setBorder (defaultBorder); + String txt = editor.getText (); + if (txt.isEmpty ()) + return true; + try { + Float.parseFloat (txt.replace (",", ".")); + return true; + } catch (NumberFormatException nfe) { + } + editor.setBorder (badValueBorder); + return false; + } + + protected JComponent getEditor () { + JPanel jPanel = new JPanel (); + editors = new JTextField [nbVal]; + for (int i = 0; i < nbVal; i++) { + if (localizedUserMultiLabels != null && localizedUserMultiLabels.length > i) + jPanel.add (localizedUserMultiLabels[i].getJLabel ()); + final JTextField editor = new JTextField (lastValues == null || lastValues[i] == null ? "" : + getNumberFormat ().format (lastValues [i]), 6); + editors [i] = editor; + defaultBorder = editor.getBorder (); + boolean unchange = lastValues != null && lastValues[i] != null && lastValues[i] == DoubleMix; + setUnchange (editor, unchange); + setChangeListener (editor); + editors [i].setInputVerifier (new InputVerifier () { + @Override + public boolean verify (JComponent input) { + return JPMultiValues.this.verify (editor); + } + }); + jPanel.add (editors[i]); + } + return jPanel; + } + + protected JComponent getValue () { + if (lastValues == null) + return null; + JPanel jPanel = new JPanel (); + boolean noVal = true; + for (int i = 0; i < lastValues.length; i++) { + if (localizedUserMultiLabels != null && localizedUserMultiLabels.length > i) + jPanel.add (localizedUserMultiLabels[i].getJLabel ()); + if (lastValues[i] == null) { + jPanel.add (getEmptyLabel ()); + continue; + } + noVal = false; + jPanel.add ((lastValues[i] == DoubleMix) ? getUnknownLabel () : + new JLabel (getNumberFormat ().format (lastValues[i]))); + } + return noVal ? null : jPanel; + } + + public String getLastValue () { + if (unchanged.size () >= nbVal) + return PropMix; + String newVal = ""; + String sep = ""; + boolean noVal = true; + for (int i = 0; i < nbVal; i++) { + newVal += sep; + sep = "|"; + if (unchanged.contains (editors [i])) { + newVal += "?"; + noVal = false; + continue; + } + String val = editors [i].getText ().replace (",", "."); + if (val.isEmpty ()) + continue; + try { + double dVal = Double.parseDouble (val); + if (parentValues != null && parentValues[i] != null && parentValues[i] == dVal) + continue; + newVal += getNumberFormat ().format (dVal).replace (",", "."); + noVal = false; + } catch (Exception e) { + e.printStackTrace (); + } + } + if (noVal) + newVal = ""; + return newVal; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropArticle.java b/src/java/adecWatt/view/jProp/JPropArticle.java new file mode 100644 index 0000000..62f5424 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropArticle.java @@ -0,0 +1,58 @@ +package adecWatt.view.jProp; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.text.JTextComponent; + +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCNL; + +import adecWatt.view.JEditable; +import adecWatt.view.JProp; +import static adecWatt.model.Prop.PropMix; + +public class JPropArticle extends JProp { + + static public final int minRow = 5; + + protected JTextArea editor; + private boolean unchange; + + // ======================================== + public JPropArticle (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + if (!edit && lastValue == null) + return; + Util.addComponent (localizedUserLabel.getJLabel (), jPropList, GBC); + Util.addComponent (new JLabel (" : "), jPropList, GBCNL); + editor = new JTextArea (lastValue); + Util.addComponent (Util.getJScrollPane (editor), jPropList, GBCNL); + editor.setEditable (edit); + setUnchange (editor, lastValue == PropMix); + if (edit) { + if (editor.getLineCount () < minRow) + editor.setRows (minRow); + setChangeListener (editor); + } + } + + public void setUnchange (JTextComponent jTextComponent, boolean unchange) { + super.setUnchange (jTextComponent, unchange); + this.unchange = unchange; + } + + public String getLastValue () { + String val = editor.getText (); + if (unchange) + val = PropMix; + return val; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropBuilding.java b/src/java/adecWatt/view/jProp/JPropBuilding.java new file mode 100644 index 0000000..bc25b79 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropBuilding.java @@ -0,0 +1,96 @@ +package adecWatt.view.jProp; + +import java.util.ArrayList; +import java.util.Vector; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.text.JTextComponent; + +import adecWatt.model.unit.Building; +import adecWatt.view.JEditable; +import static adecWatt.model.Prop.PropMix; + +public class JPropBuilding extends JPLabel implements JAutoComboBox.Filter { + + // ======================================== + protected ArrayList allBuidings; + protected ArrayList allBuidingsName; + protected Vector matchBuidings; + + protected JAutoComboBox choice; + + public JPropBuilding (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + @Override + public Vector match (String value) { + value = value.toLowerCase (); + Vector founds = new Vector (); + matchBuidings.clear (); + if (allBuidings != null) { + for (Building building : allBuidings) { + if (building.parentMatch (value)) { + founds.add (building.getLocalName ()); + matchBuidings.add (building); + } + } + } + return founds; + } + + protected boolean verify (JTextComponent editor) { + if (editor == null || allBuidingsName == null) + return false; + boolean result = allBuidingsName.contains (editor.getText ()); + editor.setBorder (result ? defaultBorder : badValueBorder); + return result; + } + + protected JComponent getValue () { + if (lastValue == null) + return null; + if (lastValue == PropMix) + return getUnknownLabel (); + try { + return new JLabel (permanentDB.getUnitById (lastValue).getName ()); + } catch (Exception e) { + return getMsgLabel (lastValue); + } + } + + protected JComponent getEditor () { + allBuidings = permanentDB.getAllBuildings (); + int index = -1; + if (allBuidings != null) { + allBuidingsName = new ArrayList (allBuidings.size ()); + for (Building building : allBuidings) { + if (lastValue != null && building.getId ().equals (lastValue)) + index = allBuidingsName.size (); + allBuidingsName.add (building.getLocalName ()); + } + } else + allBuidingsName = new ArrayList (0); + matchBuidings = new Vector (allBuidingsName.size ()); + choice = new JAutoComboBox (this); + JTextComponent editor = choice.getEditorComponent (); + defaultBorder = editor.getBorder (); + editors = new JTextComponent [] {editor}; + setChangeListener (editor); + if (index >= 0) + choice.setSelectedIndex (index); + return choice; + } + + public String getLastValue () { + String val = ""; + int index = choice.getSelectedIndex (); + if (index >= 0) + val = matchBuidings.get (index).getId (); + if (unchanged.size () > 0) + val = PropMix; + return val; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropCity.java b/src/java/adecWatt/view/jProp/JPropCity.java new file mode 100644 index 0000000..f9451e3 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropCity.java @@ -0,0 +1,79 @@ +package adecWatt.view.jProp; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Vector; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.text.JTextComponent; + +import misc.Util; + +import adecWatt.model.InseeDB; +import adecWatt.view.JEditable; + +public class JPropCity extends JPLabel implements JAutoComboBox.Filter { + static public final int maxPropal = 500; + + protected JComponent[] jComponents = new JComponent[2]; + protected JAutoComboBox jCity; + + protected ArrayList filteredCity; + + // ======================================== + protected void plotCity () { + if (filteredCity == null) + return; + int nbInsee = filteredCity.size (); + int idx = jCity.getSelectedIndex (); + if (nbInsee == 1) + idx = 0; + if (idx < 0) + return; + InseeDB.Insee insee = filteredCity.get (idx); + jEditable.plotCity (insee.latitude, insee.longitude); + } + + public Vector match (String value) { + try { + filteredCity = adecWatt.getInseeDB ().getCities (value); + } catch (Exception e) { + filteredCity = null; + } + if (filteredCity == null) + return null; + if (filteredCity.size () > maxPropal) { + filteredCity = null; + return null; + } + Vector filteredCityName = new Vector (filteredCity.size ()); + for (InseeDB.Insee insee : filteredCity) + filteredCityName.add (insee.name); + return filteredCityName; + } + + public JPropCity (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + protected JComponent getEditor () { + jCity = new JAutoComboBox (this); + JTextComponent editor = jCity.getEditorComponent (); + editors = new JTextComponent [] {editor}; + setChangeListener (editor); + editor.setText (lastValue); + jCity.updateFilter (); + JPanel jPanel = new JPanel (); + jPanel.add (jCity); + jPanel.add (Util.newIconButton ("PlotCity", new ActionListener () { + public void actionPerformed (ActionEvent e) { + plotCity (); + } + })); + Util.unBoxButton (jPanel); + return jPanel; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropCube.java b/src/java/adecWatt/view/jProp/JPropCube.java new file mode 100644 index 0000000..9d5138d --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropCube.java @@ -0,0 +1,12 @@ +package adecWatt.view.jProp; + +import adecWatt.view.JEditable; + +public class JPropCube extends JPMultiValues { + // ======================================== + public JPropCube (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropEnum.java b/src/java/adecWatt/view/jProp/JPropEnum.java new file mode 100644 index 0000000..eff6a65 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropEnum.java @@ -0,0 +1,57 @@ +package adecWatt.view.jProp; + +import java.util.Vector; +import javax.swing.JComponent; +import javax.swing.text.JTextComponent; + +import adecWatt.view.JEditable; +import static adecWatt.model.Prop.PropMix; + +public class JPropEnum extends JPLabel implements JAutoComboBox.Filter { + + // ======================================== + protected JAutoComboBox choice; + + public JPropEnum (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + @Override + public Vector match (String value) { + value = value.toLowerCase (); + Vector founds = new Vector (); + if (enumChoice != null) + for (String item : enumChoice) + if (item.toLowerCase ().indexOf (value) >= 0) + founds.add (item); + return founds; + } + + protected boolean verify (JTextComponent editor) { + if (editor == null || enumChoice == null) + return false; + boolean result = enumChoice.contains (editor.getText ()); + editor.setBorder (result ? defaultBorder : badValueBorder); + return result; + } + + // ======================================== + protected JComponent getEditor () { + choice = new JAutoComboBox (this); + JTextComponent editor = choice.getEditorComponent (); + defaultBorder = editor.getBorder (); + editors = new JTextComponent [] {editor}; + setChangeListener (editor); + choice.setSelectedItem (lastValue); + return choice; + } + + public String getLastValue () { + String val = (String) choice.getSelectedItem (); + if (unchanged.size () > 0) + val = PropMix; + return val; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropGeo.java b/src/java/adecWatt/view/jProp/JPropGeo.java new file mode 100644 index 0000000..9135fe8 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropGeo.java @@ -0,0 +1,120 @@ +package adecWatt.view.jProp; + +import java.awt.BorderLayout; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseEvent; +import java.text.NumberFormat; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SwingConstants; + +import org.openstreetmap.gui.jmapviewer.DefaultMapController; +import org.openstreetmap.gui.jmapviewer.JMapViewer; +import org.openstreetmap.gui.jmapviewer.MapMarkerDot; +import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; +import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; +import org.openstreetmap.gui.jmapviewer.tilesources.BingAerialTileSource; +import org.openstreetmap.gui.jmapviewer.tilesources.MapQuestOsmTileSource; +import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource; + +import misc.Util; + +import adecWatt.model.Prop; +import adecWatt.view.JEditable; +import adecWatt.view.JProp; + +public class JPropGeo extends JPMultiValues { + + // ======================================== + protected JMapViewer treeMap = new JMapViewer (); + protected MapMarkerDot here; + + protected NumberFormat getNumberFormat () { return Prop.geoFormat; } + + protected boolean verify (JTextField editor) { + boolean result = super.verify (editor); + if (!result) + return false; + updateGeo (); + return true; + } + protected void updateGeo () { + try { + here.setLat (Float.parseFloat (editors [0].getText ().replace (",", "."))); + here.setLon (Float.parseFloat (editors [1].getText ().replace (",", "."))); + treeMap.setDisplayToFitMapMarkers (); + treeMap.setZoom (16); + } catch (Exception e) { + } + } + public void setGeo (double latitude, double longitude) { + if (!editors[0].getText ().isEmpty () && !editors[1].getText ().isEmpty ()) + return; + forceGeo (latitude, longitude); + updateGeo (); + jEditable.toFront (map); + } + protected void forceGeo (double latitude, double longitude) { + editors[0].setText (Prop.geoFormat.format (latitude)); + editors[1].setText (Prop.geoFormat.format (longitude)); + here.setLat (latitude); + here.setLon (longitude); + treeMap.repaint (); + } + protected void setGeo () { + try { + here.setLat (lastValues[0]); + here.setLon (lastValues[1]); + treeMap.setDisplayToFitMapMarkers (); + treeMap.setZoom (16); + } catch (Exception e) { + } + } + public JPropGeo (String propName, JEditable jEditable) { + super (propName, jEditable); + jEditable.setFirstGeo (this); + treeMap.setScrollWrapEnabled (true); + here = new MapMarkerDot (47.95707, -2.56396); + treeMap.addMapMarker (here); + } + + JPanel map; + protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + if (!edit && (hidden || lastValue == null)) + return; + super.displayByType (edit, jPropList, jTabbedPane); + setGeo (); + JComboBox tileSourceSelector = new JComboBox<> (new TileSource[] { + new OsmTileSource.Mapnik (), + new OsmTileSource.CycleMap (), + new BingAerialTileSource (), + new MapQuestOsmTileSource () + //new MapQuestOpenAerialTileSource () + }); + tileSourceSelector.addItemListener (new ItemListener () { + public void itemStateChanged (ItemEvent e) { + treeMap.setTileSource ((TileSource) e.getItem ()); + } + }); + map = new JPanel (new BorderLayout ()); + map.add (Util.newLabel ("HelpOSM", SwingConstants.CENTER), BorderLayout.PAGE_START); + map.add (treeMap, BorderLayout.CENTER); + map.add (tileSourceSelector, BorderLayout.PAGE_END); + jTabbedPane.add (localizedUserLabel.getCurrentLabel (), map); + jEditable.addLocalizedUserLabel (localizedUserLabel); + if (edit) + treeMap.addMouseListener (new DefaultMapController (treeMap) { + @Override + public void mouseClicked (MouseEvent e) { + ICoordinate pos = map.getPosition (e.getPoint()); + forceGeo (pos.getLat (), pos.getLon ()); + } + }); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropIcon.java b/src/java/adecWatt/view/jProp/JPropIcon.java new file mode 100644 index 0000000..ac71e54 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropIcon.java @@ -0,0 +1,50 @@ +package adecWatt.view.jProp; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + +import misc.Util; +import static misc.Util.GBC; +import static misc.Util.GBCLNL; + +import adecWatt.view.JEditable; + +public class JPropIcon extends JPImage { + // ======================================== + protected int iconSize = 32; + + public JPropIcon (String propName, JEditable jEditable) { + super (propName, jEditable); + rightDB = iconDB; + } + + public JLabel getMainIcon (boolean edit) { + if (!edit && lastValue == null) + return jImage; + iconSize = 64; + setImage (); + if (edit) + setPopup (); + return jImage; + } + + protected ImageIcon getFitImage () { + return scaledImage.getSide (iconSize); + } + + protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + if (!edit && (hidden || lastValue == null)) + return; + setImage (); + Util.addComponent (localizedUserLabel.getJLabel (), jPropList, GBC); + Util.addComponent (new JLabel (" : "), jPropList, GBC); + Util.addComponent (jImage, jPropList, GBCLNL); + if (!edit) + return; + setPopup (); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropImage.java b/src/java/adecWatt/view/jProp/JPropImage.java new file mode 100644 index 0000000..210108a --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropImage.java @@ -0,0 +1,47 @@ +package adecWatt.view.jProp; + +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + +import misc.ScaledImage; + +import adecWatt.view.JEditable; + +public class JPropImage extends JPImage { + // ======================================== + + public JPropImage (String propName, JEditable jEditable) { + super (propName, jEditable); + rightDB = imageDB; + jImage.addComponentListener (new ComponentAdapter () { + public void componentResized (ComponentEvent e) { + if (scaledImage == null) + return; + Rectangle bounds = jImage.getBounds (); + jImage.setIcon (scaledImage.getInsideFit (bounds.width, bounds.height, ScaledImage.defaultAdjust)); + } + }); + } + + protected ImageIcon getFitImage () { + // XXX sauf si déjà "componentResized" + return scaledImage.getInsideFit (defaultImageWidth, defaultImageHeight, ScaledImage.defaultAdjust); + } + + protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + if (!edit && (hidden || lastValue == null)) + return; + setImage (); + jTabbedPane.add (localizedUserLabel.getCurrentLabel (), jImage); + jEditable.addLocalizedUserLabel (localizedUserLabel); + if (!edit) + return; + setPopup (); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropNumber.java b/src/java/adecWatt/view/jProp/JPropNumber.java new file mode 100644 index 0000000..9702d32 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropNumber.java @@ -0,0 +1,12 @@ +package adecWatt.view.jProp; + +import adecWatt.view.JEditable; + +public class JPropNumber extends JPMultiValues { + // ======================================== + public JPropNumber (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropPreview.java b/src/java/adecWatt/view/jProp/JPropPreview.java new file mode 100644 index 0000000..2697f0f --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropPreview.java @@ -0,0 +1,62 @@ +package adecWatt.view.jProp; + +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingConstants; +import misc.ScaledImage; +import misc.Util; + +import adecWatt.view.JEditable; +import adecWatt.view.JProp; + +public class JPropPreview extends JProp { + // ======================================== + protected JLabel jImage = new JLabel (); + protected ScaledImage scaledImage; + + public JPropPreview (String propName, JEditable jEditable) { + super (propName, jEditable); + jImage.setHorizontalAlignment (SwingConstants.CENTER); + jImage.addComponentListener (new ComponentAdapter () { + public void componentResized (ComponentEvent e) { + if (scaledImage == null) + return; + Rectangle bounds = jImage.getBounds (); + jImage.setIcon (scaledImage.getInsideFit (bounds.width, bounds.height, ScaledImage.defaultAdjust)); + } + }); + } + + protected void updateView () { + setImage (); + Util.packWindow (jImage); + } + + protected void setImage () { + scaledImage = jEditable.getPreview (); + if (scaledImage == null) { + jImage.setIcon (Util.loadActionIcon ("BreakIcon")); + return; + } + jImage.setIcon (scaledImage.getInsideFit (defaultImageWidth, defaultImageHeight, ScaledImage.defaultAdjust)); + + // try { + // javax.imageio.ImageIO.write (scaledImage.original, "png", new java.io.File ("/tmp/toto.png")); + // } catch (Exception e) { + // } + } + + protected void displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) { + setImage (); + if (scaledImage == null) + return; + jTabbedPane.add (localizedUserLabel.getCurrentLabel (), jImage); + jEditable.addLocalizedUserLabel (localizedUserLabel); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropSquare.java b/src/java/adecWatt/view/jProp/JPropSquare.java new file mode 100644 index 0000000..df7bba1 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropSquare.java @@ -0,0 +1,12 @@ +package adecWatt.view.jProp; + +import adecWatt.view.JEditable; + +public class JPropSquare extends JPMultiValues { + // ======================================== + public JPropSquare (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/JPropText.java b/src/java/adecWatt/view/jProp/JPropText.java new file mode 100644 index 0000000..8411eb0 --- /dev/null +++ b/src/java/adecWatt/view/jProp/JPropText.java @@ -0,0 +1,25 @@ +package adecWatt.view.jProp; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +import adecWatt.view.JEditable; +import static adecWatt.model.Prop.PropMix; + +public class JPropText extends JPLabel { + + // ======================================== + public JPropText (String propName, JEditable jEditable) { + super (propName, jEditable); + } + + protected JComponent getEditor () { + JTextField editor = new JTextField (lastValue, 12); + editors = new JTextField [] {editor}; + setUnchange (editor, lastValue == PropMix); + setChangeListener (editor); + return editor; + } + + // ======================================== +} diff --git a/src/java/adecWatt/view/jProp/package-info.java b/src/java/adecWatt/view/jProp/package-info.java new file mode 100644 index 0000000..af7000d --- /dev/null +++ b/src/java/adecWatt/view/jProp/package-info.java @@ -0,0 +1,24 @@ +/** + * Architecture des classes + * + * JFilePreview + * JImagePopup + * (JProp) + * JPLabel + * JPropText + * JPropCity + * JPropEnum + * JPropBuilding + * JPMultiValues + * JPropNumber + * JPropSquare + * JPropCube + * JPImage + * JPropIcon + * JPropImage + * JPropPreview + * JPropGeo + * JPropArticle + * + */ +package adecWatt.view.jProp; diff --git a/src/java/adecWatt/view/package-info.java b/src/java/adecWatt/view/package-info.java new file mode 100644 index 0000000..b8a982f --- /dev/null +++ b/src/java/adecWatt/view/package-info.java @@ -0,0 +1,29 @@ +/** + * Architecture des classes + * + * JLocalizedUserLabel + * + * JAdecWatt + * JAdecWattMenuBar + * JAdecWattToolBar + * JAdecWattDialog + * + * JUnitPopup + * JDragUnit + * JItemPopup + * + * JWorkspaceView + * JBuildingView + * JLightplotView + * JComp + * + * JTransform : editable + * JDefProp + * JDefChoice + * + * JEditable + * JProp + * jProp... + * + */ +package adecWatt.view; 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/RemoteUpdate.java b/src/java/misc/RemoteUpdate.java new file mode 100644 index 0000000..744abd2 --- /dev/null +++ b/src/java/misc/RemoteUpdate.java @@ -0,0 +1,736 @@ +package misc; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +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; + +import misc.Config; +import misc.ProgressState; +import misc.Util; + +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; + } + return; + } + if (local == null) { + switch (action) { + case RemoteRemove: + case Download: + todo = action; + } + 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; + } + 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); + } + } 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/Util.java b/src/java/misc/Util.java new file mode 100644 index 0000000..f4e8848 --- /dev/null +++ b/src/java/misc/Util.java @@ -0,0 +1,927 @@ +// ================================================================================ +// François MERCIOL 2012 +// Name : Util.java +// Language : Java +// Author : François Merciol +// CopyLeft : Cecil B +// Creation : 2012 +// Version : 0.1 (xx/xx/xx) +// ================================================================================ +package misc; + +import java.applet.Applet; +import java.applet.AudioClip; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.Normalizer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.List; +import java.util.Set; +import javax.swing.AbstractButton; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.DefaultCellEditor; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JSlider; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import javax.swing.plaf.basic.BasicButtonUI; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +import static misc.Config.FS; + +public class Util implements SwingConstants { + + // ======================================== + // Change Plugins.version too ! + static public final Long version = 20171101L; + + static public final int bufSize = 1024*1024; + static public final String NL = System.getProperty ("line.separator"); + static public final String ON = "On"; + static public final String OFF = "Off"; + + static public BasicButtonUI buttonNoUI = new BasicButtonUI (); + static public Border buttonNoBorder = BorderFactory.createEmptyBorder (2, 2, 2, 2); + + // ======================================== + static public final String toNumIn2Units (long bytes) { + if (bytes == 0) + return "0 "; + int u = 0; + for (; bytes > 1024*1024; bytes >>= 10) + u++; + + if (bytes < 1024) + return String.format ("%d %c", bytes, " kMGTPEZY".charAt (u)).replace (" ", ""); + u++; + return String.format ("%.1f %c", bytes/1024f, " kMGTPEZY".charAt (u)).replace (",0 ", " ").replace (" ", ""); + } + static public final String toNumIn10Units (long bytes) { + if (bytes == 0) + return "0 "; + int u = 0; + for (; bytes > 1000*1000; bytes >>= 10) + u++; + + if (bytes < 1000) + return String.format ("%d %c", bytes, " kMGTPEZY".charAt (u)).replace (" ", ""); + u++; + return String.format ("%.1f %c", bytes/1000f, " kMGTPEZY".charAt (u)).replace (",0 ", " ").replace (" ", ""); + } + @SuppressWarnings ({"unchecked", "rawtypes"}) + static public final T toEnum (String value, T defaultValue) { + try { + return (T) Enum.valueOf ((Class)defaultValue.getClass (), value); + } catch (Exception e) { + } + return defaultValue; + } + + // ======================================== + static public final String toColumn (String [] lines, int nbColumn) { + int size = lines.length; + if (size < 1) + return ""; + if (size < 2) + return lines [0]+"\n"; + String result = ""; + int nbLignes = size/nbColumn; + int nbLongColumn = size % nbColumn; + for (int i = 0, k = 0; k < size; i++) { + int idx = i; + String sep = ""; + for (int j = 0; j < nbColumn && k < size; j++, k++) { + result += sep + lines [idx]; + sep = "\t"; + idx += nbLignes; + if (j < nbLongColumn) + idx++; + } + result += "\n"; + } + return result; + } + + // ======================================== + static public final String[] set2string (Set set) { + String [] result = new String [set.size ()]; + int idx = 0; + for (String key : set) + result [idx++] = key; + return result; + } + + // ====================================================================== + static public JScrollPane getJScrollPane (Component view) { + return getJScrollPane (view, true, true); + } + static public JScrollPane getJScrollPane (Component view, boolean vNeed, boolean hNeed) { + return new JScrollPane (view, + vNeed ? JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED : JScrollPane.VERTICAL_SCROLLBAR_NEVER, + hNeed ? JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED : JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + } + + // ======================================== + static public JSplitPane getJSplitPane (int newOrientation, Component newLeftComponent, Component newRightComponent) { + JSplitPane result = new JSplitPane (newOrientation, newLeftComponent, newRightComponent); + result.setResizeWeight (0); + result.setOneTouchExpandable (true); + result.setContinuousLayout (true); + return result; + } + + // ======================================== + static public final void setEnabled (Component component, boolean enabled) { + component.setEnabled (enabled); + try { + for (Component component2 : ((Container) component).getComponents ()) + setEnabled (component2, enabled); + } catch (Exception e) { + } + } + + // ======================================== + static public final GridBagConstraints + GBC, GBCNL, GBCLNL, GBCBNL; + static { + GBC = new GridBagConstraints (); + GBC.insets = new Insets (1, 2, 1, 2); + GBC.weightx = GBC.weighty = 1.; + GBC.fill = GridBagConstraints.HORIZONTAL; + + GBCLNL = (GridBagConstraints) GBC.clone (); + GBCLNL.anchor = GridBagConstraints.WEST; + GBCLNL.fill = GridBagConstraints.NONE; + GBCLNL.gridwidth = GridBagConstraints.REMAINDER; + + GBCNL = (GridBagConstraints) GBC.clone (); + GBCNL.gridwidth = GridBagConstraints.REMAINDER; + + + GBCBNL = (GridBagConstraints) GBCNL.clone (); + GBCBNL.fill = GridBagConstraints.BOTH; + } + static public JPanel getGridBagPanel () { + return new JPanel (new GridBagLayout ()); + } + static public void addLabelFields (Container container, String label, Component... components) { + addLabel (label, RIGHT, container, GBC); + for (int i = 0; i < components.length; i++) + addComponent (components[i], container, i == components.length -1 ? GBCNL : GBC); + } + + // ======================================== + static public AbstractButton activeButton (AbstractButton button, String action, ActionListener actionListener) { + button.setActionCommand (action); + Bundle.addLocalizedActioner (button); + button.setToolTipText (Bundle.getAction (action)); + Bundle.addLocalizedToolTip (button); + if (actionListener != null) + button.addActionListener (actionListener); + return button; + } + + // ======================================== + static public final JCheckBox newCheckIcon (String action, ActionListener actionListener) { + JCheckBox button = new JCheckBox (loadActionIcon (action+OFF)); + button.setSelectedIcon (loadActionIcon (action+ON)); + activeButton (button, action, actionListener); + return button; + } + static public final JCheckBox newCheckIcon (String action, ActionListener actionListener, boolean defaultValue) { + JCheckBox button = newCheckIcon (action, actionListener); + button.setSelected (defaultValue); + return button; + } + static public final JCheckBox addCheckIcon (String action, ActionListener actionListener, Container container) { + JCheckBox button = newCheckIcon (action, actionListener); + container.add (button); + return button; + } + static public final JCheckBox addCheckIcon (String action, ActionListener actionListener, boolean defaultValue, Container container) { + JCheckBox button = newCheckIcon (action, actionListener); + container.add (button); + button.setSelected (defaultValue); + return button; + } + static public final void addCheckIcon (List actions, ActionListener actionListener, Container container) { + for (String action : actions) + addCheckIcon (action, actionListener, container); + } + static public final JCheckBox addCheckIcon (String action, ActionListener actionListener, boolean defaultValue, + Container container, GridBagConstraints constraint) { + JCheckBox button = newCheckIcon (action, actionListener, defaultValue); + addComponent (button, container, constraint); + return button; + } + + static public void setCheckIconTableCellEditorRenderer (String action, TableColumn tableColumn) { + tableColumn.setCellRenderer (new CheckIconTableCellEditorRenderer (action)); + tableColumn.setCellEditor (new DefaultCellEditor (newCheckIcon (action, null))); + } + + static public class CheckIconTableCellEditorRenderer implements TableCellRenderer { + JCheckBox jCheckBox; + public CheckIconTableCellEditorRenderer (String action) { + jCheckBox = Util.newCheckIcon (action, null); + } + public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + jCheckBox.setBackground (isSelected ? table.getSelectionBackground () : table.getBackground ()); + jCheckBox.setForeground (isSelected ? table.getSelectionForeground () : table.getForeground ()); + if (value instanceof Boolean) + jCheckBox.setSelected (((Boolean) value).booleanValue ()); + return jCheckBox; + } + } + + // ======================================== + static public final JCheckBox newCheckButton (String action, ActionListener actionListener) { + JCheckBox button = new JCheckBox (Bundle.getAction (action), loadActionIcon (action+OFF)); + button.setSelectedIcon (loadActionIcon (action+ON)); + activeButton (button, action, actionListener); + return button; + } + static public final JCheckBox addCheckButton (String action, ActionListener actionListener, Container container) { + JCheckBox button = newCheckButton (action, actionListener); + container.add (button); + return button; + } + static public final void addCheckButton (List actions, ActionListener actionListener, Container container) { + for (String action : actions) + addCheckButton (action, actionListener, container); + } + static public final JCheckBox addCheckButton (String action, ActionListener actionListener, + Container container, GridBagConstraints constraint) { + JCheckBox button = newCheckButton (action, actionListener); + addComponent (button, container, constraint); + return button; + } + // ======================================== + static public final JCheckBox newCheckButtonConfig (String action, ActionListener actionListener, boolean defaultValue) { + boolean startValue = Config.getBoolean (action+Config.checkedPostfix, defaultValue); + JCheckBox button = newCheckButton (action, actionListener); + button.setSelected (startValue); + return button; + } + + static public final JCheckBox addCheckButtonConfig (String action, ActionListener actionListener, boolean defaultValue, + Container container) { + JCheckBox button = newCheckButtonConfig (action, actionListener, defaultValue); + container.add (button); + return button; + } + + static public final JCheckBox addCheckButtonConfig (String action, ActionListener actionListener, boolean defaultValue, + Container container, GridBagConstraints constraint) { + JCheckBox button = newCheckButtonConfig (action, actionListener, defaultValue); + // XXX le test suivant a été supprimer, il faut vérifier que cela tourne toujours + //if (container != null) + addComponent (button, container, constraint); + return button; + } + + // ======================================== + static public final JRadioButton newRadioButton (String action, ActionListener actionListener, ButtonGroup group, String selected) { + JRadioButton button = new JRadioButton (Bundle.getAction (action), loadActionIcon (action+OFF), + action.equals (selected)); + button.setSelectedIcon(loadActionIcon (action+ON)); + activeButton (button, action, actionListener); + group.add (button); + return button; + } + + static public final void addRadioButton (List actions, ActionListener actionListener, ButtonGroup group, String selected, + Container container) { + for (String action : actions) { + JRadioButton button = newRadioButton (action, actionListener, group, selected); + container.add (button); + } + } + + static public final JRadioButton addRadioButton (String action, ActionListener actionListener, ButtonGroup group, String selected, + Container container, GridBagConstraints constraint) { + JRadioButton button = newRadioButton (action, actionListener, group, selected); + addComponent (button, container, constraint); + return button; + } + + // ======================================== + static public final JButton newButton (String action, ActionListener actionListener) { + JButton button = new JButton (Bundle.getAction (action), loadActionIcon (action)); + activeButton (button, action, actionListener); + return button; + } + static public final void newButton (List actions, ActionListener actionListener) { + for (String action : actions) + newButton (action, actionListener); + } + + static public final JButton addButton (String action, ActionListener actionListener, Container container) { + JButton button = newButton (action, actionListener); + container.add (button); + return button; + } + static public final void addButton (List actions, ActionListener actionListener, Container container) { + for (String action : actions) + addButton (action, actionListener, container); + } + static public final JButton addButton (String action, ActionListener actionListener, Container container, GridBagConstraints constraint) { + JButton button = newButton (action, actionListener); + addComponent (button, container, constraint); + return button; + } + + // ======================================== + static public final JButton newIconButton (String action, ActionListener actionListener) { + JButton button = new JButton (loadActionIcon (action)); + button.setAlignmentX (Component.CENTER_ALIGNMENT); + activeButton (button, action, actionListener); + return button; + } + static public final void newIconButton (List actions, ActionListener actionListener) { + for (String action : actions) + newIconButton (action, actionListener); + } + + static public final JButton addIconButton (String action, ActionListener actionListener, Container container) { + JButton button = newIconButton (action, actionListener); + container.add (button); + return button; + } + static public final void addIconButton (List actions, ActionListener actionListener, Container container) { + for (String action : actions) + addIconButton (action, actionListener, container); + } + static public final JButton addIconButton (String action, ActionListener actionListener, Container container, GridBagConstraints constraint) { + JButton button = new JButton (loadActionIcon (action)); + activeButton (button, action, actionListener); + addComponent (button, container, constraint); + return button; + } + + static public final void unBoxButton (Container container) { + for (AbstractButton button : collectButtons (null, container).values ()) + unBoxButton (button); + } + static public final void unBoxButton (AbstractButton button) { + button.setUI (buttonNoUI); + button.setBorder (buttonNoBorder); + } + + // ======================================== + static public final void addMenuItem (String action, ActionListener actionListener, Container container) { + JMenuItem item = new JMenuItem (Bundle.getAction (action), loadActionIcon (action)); + activeButton (item, action, actionListener); + container.add (item); + } + static public final void addMenuItem (List actions, ActionListener actionListener, Container container) { + for (String action : actions) + addMenuItem (action, actionListener, container); + } + + + // ======================================== + static public Hashtable> allCheckBox = new Hashtable> (); + static public void updateCheckBox (String action, boolean value) { + ArrayList buttons = allCheckBox.get (action); + if (buttons == null) + return; + Config.setBoolean (action+Config.checkedPostfix, value); + for (AbstractButton button : buttons) + if (button.isSelected () != value) + button.setSelected (value); + } + + static public final void addCheckMenuItem (List actions, ActionListener actionListener, Container container) { + for (String action : actions) + addCheckMenuItem (action, actionListener, container); + } + static public final JCheckBoxMenuItem addCheckMenuItem (String action, ActionListener actionListener, Container container) { + return addCheckMenuItem (action, actionListener, Config.getBoolean (action+Config.checkedPostfix, false), container); + } + static public final JCheckBoxMenuItem addCheckMenuItem (String action, ActionListener actionListener, + boolean defaultValue, Container container) { + boolean startValue = Config.getBoolean (action+Config.checkedPostfix, defaultValue); + JCheckBoxMenuItem item = new JCheckBoxMenuItem (Bundle.getAction (action), loadActionIcon (action+OFF), startValue); + item.setSelectedIcon (loadActionIcon (action+ON)); + activeButton (item, action, actionListener); + container.add (item); + ArrayList checkList = allCheckBox.get (action); + if (checkList == null) + allCheckBox.put (action, checkList = new ArrayList ()); + checkList.add (item); + return item; + } + + // ======================================== + static public final JMenu addJMenu (JMenuBar jMenuBar, String menuId) { + JMenu menu = new JMenu (Bundle.getTitle (menuId)); + menu.setActionCommand (menuId); + Bundle.addLocalizedMenu (menu); + jMenuBar.add (menu); + return menu; + } + + // ======================================== + static public void addComponent (Component component, Container container, GridBagConstraints constraint) { + GridBagLayout gridbag = (GridBagLayout) container.getLayout (); + gridbag.setConstraints (component, constraint); + container.add (component); + } + + // ======================================== + static public final Dimension space = new Dimension (10, 10); + static public void addTextFieldSlider (JTextField textField, JLabel label, JSlider slider, Container container, GridBagConstraints constraint) { + JPanel panel = getGridBagPanel (); + addComponent (textField, panel, GBC); + addComponent (label, panel, GBC); + addComponent (slider, panel, GBCBNL); + addComponent (panel, container, constraint); + } + + // ======================================== + static public JLabel newLabel (String messageId, int position) { + JLabel jLabel = new JLabel (Bundle.getLabel (messageId), position); + Bundle.addLocalizedLabel (jLabel, messageId); + return jLabel; + } + + // ======================================== + static public JLabel addLabel (String messageId, int position, Container container) { + JLabel jLabel = newLabel (messageId, position); + container.add (jLabel); + return jLabel; + } + + // ======================================== + static public JLabel addLabel (String messageId, int position, Container container, GridBagConstraints constraint) { + JLabel jLabel = newLabel (messageId, position); + addComponent (jLabel, container, constraint); + return jLabel; + } + + // ======================================== + static public JComboBox newEnum (Class> enumClass, Enum defaultValue) { + JComboBox jComboBox = Bundle.getEnum (enumClass, defaultValue); + Bundle.addLocalizedEnum (jComboBox, enumClass); + return jComboBox; + } + + // ======================================== + static public JComboBox addEnum (Class> enumClass, Enum defaultValue, Container container) { + JComboBox jComboBox = newEnum (enumClass, defaultValue); + container.add (jComboBox); + return jComboBox; + } + + // ======================================== + static public JComboBox addEnum (Class> enumClass, Enum defaultValue, Container container, GridBagConstraints constraint) { + JComboBox jComboBox = newEnum (enumClass, defaultValue); + addComponent (jComboBox, container, constraint); + return jComboBox; + } + + // ======================================== + static public final void setColumnLabels (JTable jTable, String [] columnLabels) { + for (int i = 0; i < columnLabels.length; i++) + jTable.getColumnModel ().getColumn (i).setHeaderValue (Bundle.getLabel (columnLabels [i])); + try { + Container parent = jTable.getParent (); + parent.repaint (); + } catch (Exception e) { + } + } + + static public int viewToModel (JTable table, int vColIndex) { + if (vColIndex >= table.getColumnCount()) { + return -1; + } + return table.getColumnModel ().getColumn (vColIndex).getModelIndex (); + } + public int modelToView (JTable table, int mColIndex) { + for (int c = 0; c < table.getColumnCount (); c++) { + TableColumn col = table.getColumnModel ().getColumn (c); + if (col.getModelIndex () == mColIndex) { + return c; + } + } + return -1; + } + + // ======================================== + static public boolean packBug = false; + static public final void packWindow (final Component startComponent) { + if (packBug) + return; + SwingUtilities.invokeLater (new Runnable() { + public void run () { + for (Component component = startComponent; + component != null; + component = component.getParent ()) { + try { + ((Window) component).pack (); + return; + } catch (Exception e) { + } + } + } + }); + } + + // ======================================== + static public final JFrame newJFrame (String title, Component component, boolean exit) { + JFrame jFrame = new JFrame (title); + jFrame.addWindowListener (new WindowAdapter () { + public void windowClosing (WindowEvent e) { + if (exit) + System.exit (0); + jFrame.setVisible (false); + } + }); + jFrame.getContentPane ().add (component, BorderLayout.CENTER); + jFrame.pack (); + jFrame.setLocationRelativeTo (null); + jFrame.setVisible (true); + return jFrame; + } + + // ======================================== + static public ImageIcon loadActionIcon (String action) { + return loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.buttonDirname, action+Config.iconsExt); + } + + // ======================================== + static public ImageIcon loadImageIcon (String... names) { + URL url = Config.getDataUrl (names); + return (url != null) ? new ImageIcon (url) : null; + } + + // ======================================== + static public Image loadImage (String... names) { + try { + return loadImageIcon (names).getImage (); + } catch (Exception e) { + return null; + } + } + + // ======================================== + static public final AudioClip loadAudio (String... names) { + URL url = Config.getDataUrl (names); + return (url != null) ? Applet.newAudioClip (url) : null; + } + + // ======================================== + @SuppressWarnings({"rawtypes", "unchecked"}) + static public final Hashtable collectMethod (Class javaClass, List... actions) { + Hashtable actionsMethod = new Hashtable (); + for (List arg : actions) + for (String action : arg) { + try { + actionsMethod.put (action, javaClass.getMethod ("action"+action)); + } catch (NoSuchMethodException e) { + try { + actionsMethod.put (action, javaClass.getMethod ("action"+action, new Class[] { boolean.class })); + } catch (NoSuchMethodException e1) { + Log.keepLastException ("Util::collectMethod can't find methode "+"action"+action, e1); + e.printStackTrace (); + } + } + } + return actionsMethod; + } + + // ======================================== + static public final Hashtable collectButtons (Hashtable buttons, JMenu jMenu) { + if (buttons == null) + buttons = new Hashtable (); + for (int i = 0; i < jMenu.getItemCount (); i++) { + try { + AbstractButton button = jMenu.getItem (i); + buttons.put (button.getActionCommand (), button); + } catch (Exception e) { + } + } + return buttons; + } + + static public class ActionControl { + String action; + int key; + boolean control; + public ActionControl (String action, int key) { + this (action, key, true); + } + public ActionControl (String action, int key, boolean control) { + this.action = action; + this.key = key; + this.control = control; + } + } + static public void setAccelerator (Hashtable buttons, ActionControl... actionsControl) { + for (ActionControl actionControl : actionsControl) + ((JMenuItem) buttons.get (actionControl.action)).setAccelerator (KeyStroke.getKeyStroke (actionControl.key, actionControl.control ? InputEvent.CTRL_DOWN_MASK : 0)); + } + + + // ======================================== + static public final Hashtable collectButtons (Hashtable buttons, Container container) { + if (buttons == null) + buttons = new Hashtable (); + for (Component component : container.getComponents ()) { + try { + AbstractButton button = (AbstractButton) component; + buttons.put (button.getActionCommand (), button); + } catch (Exception e) { + } + } + return buttons; + } + + // ======================================== + static public final void actionPerformed (final Hashtable actionsMethod, ActionEvent e, final Object object) { + String cmd = null; + try { + final Object source = e.getSource (); + if (source instanceof AbstractButton) + cmd = ((AbstractButton) source).getActionCommand (); + else if (source instanceof JComboBox) + cmd = ((JComboBox) source).getActionCommand (); + final String cmd2 = cmd; + if (cmd2 != null) + SwingUtilities.invokeLater (new Runnable() { + public void run () { + if (source instanceof JCheckBoxMenuItem) { + try { + boolean value = ((JCheckBoxMenuItem) source).isSelected (); + actionsMethod.get (cmd2).invoke (object, value); + updateCheckBox (cmd2, value); + return; + } catch (IllegalArgumentException e2) { + } catch (Exception e1) { + Log.keepLastException ("Util::actionPerformed (action "+cmd2+" on "+object+")", e1); + return; + } + } + try { + actionsMethod.get (cmd2).invoke (object); + } catch (Exception e1) { + Log.keepLastException ("Util::actionPerformed (action "+cmd2+" on "+object+")", e1); + } + } + }); + } catch (Exception e2) { + e2.printStackTrace (); + Log.keepLastException ("Util::actionPerformed (action "+cmd+" on "+object+")", e2); + } + } + + // ======================================== + @SuppressWarnings("unchecked") + static public List merge (List... args) { + List result = new ArrayList (); + for (List arg : args) + result.addAll (arg); + return result; + } + + // ======================================== + // static public File checkExt (File file, String ext) { + // try { + // String fileExt = file.getName (); + // fileExt = fileExt.substring (fileExt.lastIndexOf (".")).toLowerCase (); + // if (ext.toLowerCase ().equals (fileExt)) + // return file; + // } catch (Exception e) { + // } + // return new File (file.getParent (), file.getName ()+ext); + // } + + static public String getExtention (File file) { + return getExtention (file.getName ()); + } + static public String getExtention (String filename) { + try { + filename = filename.substring (filename.lastIndexOf (".")).toLowerCase (); + return filename.substring (1); + } catch (Exception e) { + return null; + } + } + + static public String getBase (File file) { + return getBase (file.getName ()); + } + static public String getBase (String filename) { + try { + return filename.substring (0, filename.lastIndexOf (".")); + } catch (Exception e) { + return filename; + } + } + + static public String changeExtention (String filename, String extention) { + try { + return filename.substring (0, filename.lastIndexOf ("."))+"."+extention; + } catch (Exception e) { + return filename+"."+extention; + } + } + + // ======================================== + static public void backup (File file, String extention, String backExtention) { + if (!file.exists ()) + return; + String newFileName = file.getName (); + if (newFileName.endsWith ("."+extention)) + newFileName = newFileName.substring (0, newFileName.length () - ("."+extention).length ()); + File backFile = new File (file.getParent (), newFileName+"."+backExtention); + backFile.delete (); + try { + Files.move (file.toPath (), backFile.toPath (), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + } + } + + // ======================================== + static public void copy (InputStream src, OutputStream dst, byte[] tmp, ProgressState progressState) + throws IOException { + copy (src, dst, tmp, progressState, true, true); + } + static public void copy (InputStream src, OutputStream dst, byte[] tmp, ProgressState progressState, boolean srcClose, boolean dstClose) + throws IOException { + try { + if (tmp == null) + tmp = new byte[bufSize]; + for (;;) { + if (progressState != null && progressState.isInterrupted ()) + return; + int nbRead = src.read (tmp, 0, tmp.length); + if (nbRead < 0) + break; + dst.write (tmp, 0, nbRead); + if (progressState != null && !progressState.addValue (nbRead)) + return; + } + } finally { + dst.flush (); + try { + if (dstClose) + dst.close (); + if (srcClose) + src.close (); + } catch (Exception e) { + } + } + } + + // ======================================== + static public final String ctrlName (String s) { + return s.replaceAll ("[^0-9a-zA-Z_\\-.]", ""); + } + + // ======================================== + static public final String toCapital (final String s) { + return s.substring (0, 1).toUpperCase ()+s.substring (1).toLowerCase (); + } + + static public final boolean containsOne (Collection set1, Collection set2) { + try { + if (set1.size () > set2.size ()) { + Collection tmp = set1; + set1 = set2; + set2 = tmp; + } + for (T e : set1) + if (set2.contains (e)) + return true; + } catch (Exception e) { + } + return false; + } + + static public final boolean containsPart (String subString, Collection set) { + if (set == null) + return false; + for (String s : set) + if (s.indexOf (subString) >= 0) + return true; + return false; + } + + // ======================================== + @SuppressWarnings("rawtypes") + static public final String getClassName (final Class aClass) { + String[] path = aClass.getName ().split ("\\."); + return path [path.length-1]; + } + + // ======================================== + /** + retourne vrai si s1 existe et est égale à s2 + */ + static public boolean cmp (String s1, String s2) { + return (s1 == s2) || ((s1 != null) && (s1.equals (s2))); + } + + // ======================================== + static int max (int... values) { + int result = 0; + for (int val : values) + result = Math.max (result, val); + return result; + } + + // ======================================== + static public void sleep (int s) { + try { + Thread.sleep (s*1000); + } catch (InterruptedException e) { + } + } + + // ======================================== + static public void deciSleep (int s) { + try { + Thread.sleep (s*100); + } catch (InterruptedException e) { + } + } + + // ======================================== + static private String convertToHex (byte[] data) { + StringBuffer buf = new StringBuffer (); + for (int i = 0; i < data.length; i++) { + int halfbyte = (data[i] >>> 4) & 0x0F; + int two_halfs = 0; + do { + if ((0 <= halfbyte) && (halfbyte <= 9)) + buf.append ((char) ('0' + halfbyte)); + else + buf.append ((char) ('a' + (halfbyte - 10))); + halfbyte = data[i] & 0x0F; + } while (two_halfs++ < 1); + } + return buf.toString (); + } + + public static String removeAccent (String source) { + return Normalizer.normalize (source, Normalizer.Form.NFD).replaceAll ("[\u0300-\u036F]", ""); + } + + static public String sha1 (String text) + throws NoSuchAlgorithmException, UnsupportedEncodingException { + MessageDigest md; + md = MessageDigest.getInstance ("SHA-1"); + byte[] sha1hash = new byte[40]; + md.update (text.getBytes ("iso-8859-1"), 0, text.length ()); + sha1hash = md.digest (); + return convertToHex (sha1hash); + } + + // ======================================== +} diff --git a/ws/launch-adecWatt.sh b/ws/launch-adecWatt.sh new file mode 100755 index 0000000..91268dd --- /dev/null +++ b/ws/launch-adecWatt.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd `dirname "$0"` +java -jar soft/AdecWatt.jar