package nc.noumea.mairie.organigramme.viewmodel;
/*
* #%L
* Logiciel de Gestion des Organigrammes de la Ville de Nouméa
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2015 Mairie de Nouméa
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import nc.noumea.mairie.organigramme.core.dto.AbstractEntityDto;
import nc.noumea.mairie.organigramme.core.event.UpdateOngletAbstractEntityEvent;
import nc.noumea.mairie.organigramme.core.services.AuthentificationService;
import nc.noumea.mairie.organigramme.core.utility.OrganigrammeUtil;
import nc.noumea.mairie.organigramme.core.viewmodel.AbstractEditViewModel;
import nc.noumea.mairie.organigramme.core.viewmodel.AbstractViewModel;
import nc.noumea.mairie.organigramme.core.ws.IAdsWSConsumer;
import nc.noumea.mairie.organigramme.core.ws.ISirhWSConsumer;
import nc.noumea.mairie.organigramme.dto.EntiteDto;
import nc.noumea.mairie.organigramme.dto.EntiteHistoDto;
import nc.noumea.mairie.organigramme.dto.EnumStatutFichePoste;
import nc.noumea.mairie.organigramme.dto.FichePosteDto;
import nc.noumea.mairie.organigramme.dto.FichePosteTreeNodeDto;
import nc.noumea.mairie.organigramme.dto.ProfilAgentDto;
import nc.noumea.mairie.organigramme.dto.ReturnMessageDto;
import nc.noumea.mairie.organigramme.dto.TypeEntiteDto;
import nc.noumea.mairie.organigramme.entity.CouleurTypeEntite;
import nc.noumea.mairie.organigramme.enums.EntiteOnglet;
import nc.noumea.mairie.organigramme.enums.Statut;
import nc.noumea.mairie.organigramme.enums.StatutFichePoste;
import nc.noumea.mairie.organigramme.enums.Transition;
import nc.noumea.mairie.organigramme.services.CouleurTypeEntiteService;
import nc.noumea.mairie.organigramme.services.ExportGraphMLService;
import nc.noumea.mairie.organigramme.services.OrganigrammeService;
import nc.noumea.mairie.organigramme.services.ReturnMessageService;
import nc.noumea.mairie.organigramme.services.TypeEntiteService;
import nc.noumea.mairie.organigramme.utils.ComparatorUtil;
import nc.noumea.mairie.organigramme.utils.EntityUtils;
import nc.noumea.mairie.organigramme.utils.ExportExcelUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.DependsOn;
import org.zkoss.bind.annotation.ExecutionArgParam;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zhtml.Li;
import org.zkoss.zhtml.Ul;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zkplus.spring.DelegatingVariableResolver;
import org.zkoss.zul.Div;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Messagebox.ClickEvent;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Vlayout;
@Init(superclass = true)
@VariableResolver(DelegatingVariableResolver.class)
public class EditEntiteDtoViewModel extends AbstractEditViewModel<EntiteDto> implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(EditEntiteDtoViewModel.class);
// @formatter:off
@WireVariable
IAdsWSConsumer adsWSConsumer;
@WireVariable
ISirhWSConsumer sirhWSConsumer;
@WireVariable
TypeEntiteService typeEntiteService;
@WireVariable
OrganigrammeService organigrammeService;
@WireVariable
AuthentificationService authentificationService;
@WireVariable
ReturnMessageService returnMessageService;
@WireVariable(value = "ExportGraphMLServiceOrgaFichesPosteImpl")
ExportGraphMLService exportGraphMLService;
// @formatter:on
@WireVariable
CouleurTypeEntiteService couleurTypeEntiteService;
private static final String[] LISTE_PROP_A_NOTIFIER_DEPLACE_FDP = new String[] { "listeFichePoste", "fichePosteGroupingModel", "titreOngletFdp" };
private static final Integer ID_FICHE_POSTE_FICTIF = 1000;
/** Le currentUser connecté **/
private ProfilAgentDto profilAgentDto;
private FichePosteGroupingModel fichePosteGroupingModel;
private List<FichePosteDto> listeFichePoste;
private List<EntiteHistoDto> listeHistorique;
private String titreOngletFdp;
/** La Div général dans lequel sera ajouté l'arbre **/
Div hlayoutTreeFichesPoste;
Component view;
/**
* Map permettant rapidement d'accèder à une {@link FichePosteTreeNodeDto} à
* partir de son id html client
**/
Map<String, FichePosteTreeNodeDto> mapIdLiFichePosteTreeNodeDto;
/**
* Map permettant de savoir si le Li est ouvert ou non à partir de son id
* html client
**/
Map<String, Boolean> mapIdLiFichePosteTreeNodeDtoOuvert = new HashMap<String, Boolean>();
/**
* L'onglet en cours de sélection (par défaut, quand on ouvre une entité
* c'est caractéristique)
**/
private EntiteOnglet ongletSelectionne = EntiteOnglet.CARACTERISTIQUE;
private boolean afficheFdpInactive = false;
private boolean afficheFdpTableau = false;
private boolean afficheFdpNonReglementaires = false;
private boolean afficheAgentFdp = true;
private FichePosteTreeNodeDto fichePoste;
private List<FichePosteTreeNodeDto> listFichePosteTreeNodeDto;
// #28374 cette HashMap contient les fiches de poste des responsables
// hierarchique de chaque service
private HashMap<Integer, FichePosteTreeNodeDto> mapFichesPosteSuperieureByService = new HashMap<Integer, FichePosteTreeNodeDto>();
public boolean isAfficheFdpInactive() {
return afficheFdpInactive;
}
@DependsOn({ "fichePosteGroupingModel", "listeFichePoste" })
public boolean isAfficheFdpTableau() {
return afficheFdpTableau;
}
public boolean isModifiable() {
// On ne peux modifier que si on a le rôle édition
return profilAgentDto.isEdition() && this.entity != null;
}
public String getTitreOngletFdp() {
construireTitreOngletFdp();
return titreOngletFdp;
}
private void construireTitreOngletFdp() {
titreOngletFdp = "Fiches de postes";
if (this.fichePosteGroupingModel != null) {
int resultat = 0;
for (int i = 0; i < this.fichePosteGroupingModel.getGroupCount(); i++) {
resultat += this.fichePosteGroupingModel.getChildCount(i);
}
titreOngletFdp += " (" + resultat + ")";
} else if (this.listeFichePoste != null) {
titreOngletFdp += " (" + this.listeFichePoste.size() + ")";
}
}
@NotifyChange({ "fichePosteGroupingModel", "listeFichePoste", "titreOngletFdp" })
public void setAfficheFdpTableau(boolean afficheFdpTableau) {
this.afficheFdpTableau = afficheFdpTableau;
// On remet la liste à null pour qu'elle soit rechargée
this.fichePosteGroupingModel = null;
}
@NotifyChange({ "fichePosteGroupingModel", "listeFichePoste", "titreOngletFdp" })
public void setAfficheFdpInactive(boolean afficheFdpInactive) {
this.afficheFdpInactive = afficheFdpInactive;
// On remet la liste à null pour qu'elle soit rechargée
this.fichePosteGroupingModel = null;
}
@Command
public void deplierToutFdp() {
if (this.entity != null) {
for (Map.Entry<String, Boolean> entry : mapIdLiFichePosteTreeNodeDtoOuvert.entrySet()) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(entry.getKey(), true);
}
Clients.evalJavaScript("deplierToutFdp(" + this.entity.getIdEntite() + ");");
}
}
@Command
public void replierToutFdp() {
if (this.entity != null) {
for (Map.Entry<String, Boolean> entry : mapIdLiFichePosteTreeNodeDtoOuvert.entrySet()) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(entry.getKey(), false);
}
Clients.evalJavaScript("replierToutFdp(" + this.entity.getIdEntite() + ");");
}
}
public void setEntiteDirty(boolean dirty) {
boolean majTitreOnglet = this.entity.isDirty() != dirty;
this.entity.setDirty(dirty);
if (majTitreOnglet) {
updateTitreOnglet();
}
}
private void updateTitreOnglet() {
String suffixe = this.entity.isDirty() ? " (*)" : null;
EventQueues.lookup("organigrammeQueue", EventQueues.DESKTOP, true).publish(new UpdateOngletAbstractEntityEvent(this.entity, suffixe));
}
@Override
public void initSetup(@ExecutionArgParam("entity") EntiteDto entiteDto) {
profilAgentDto = authentificationService.getCurrentUser();
// On recharge l'entité depuis la base pour être sur d'être bien à jour
this.entity = adsWSConsumer.getEntiteWithChildren(entiteDto.getIdEntite());
}
public ProfilAgentDto getProfilAgentDto() {
return profilAgentDto;
}
public void setProfilAgentDto(ProfilAgentDto profilAgentDto) {
this.profilAgentDto = profilAgentDto;
}
/**
* L'entité est-elle éditable ?
*
* @return true si l'entité est éditable, false sinon
*/
public boolean isEditable() {
// On ne peux modifier que si on a le rôle édition et si ce n'est pas
// l'entité VDN
// #17117 : En dehors du statut "prévision", une entité n'est pas
// modifiable
return profilAgentDto.isEdition() && (this.entity != null && this.entity.isPrevision() && !this.entity.getSigle().equals("VDN"));
}
public boolean isTypeEntiteEditable() {
return profilAgentDto.isEdition() && (this.entity != null && !this.entity.getSigle().equals("VDN"));
}
public boolean isEdition() {
return profilAgentDto != null && profilAgentDto.isEdition();
}
public EntiteOnglet getOngletSelectionne() {
return ongletSelectionne;
}
public void setOngletSelectionne(EntiteOnglet ongletSelectionne) {
this.ongletSelectionne = ongletSelectionne;
}
/**
* Renvoie la liste des types d'entités triés par nom
*
* @return la liste des types d'entités triés par nom
*/
public List<TypeEntiteDto> getListeTypeEntite() {
return adsWSConsumer.getListeTypeEntite();
}
/**
* Affiche la liste des entités remplaçables, ie. la liste de toutes les
* entités qui ne sont pas dans un statut "prévision". Elle ne contient pas
* l'entité selectionnée (une entité ne peux pas être remplacée par
* elle-même).
*
* @return la liste des entités remplaçables
*/
public List<EntiteDto> getListeEntiteRemplace() {
List<EntiteDto> listeEntiteRemplace = new ArrayList<EntiteDto>();
listeEntiteRemplace.add(null);
listeEntiteRemplace.addAll(organigrammeService.findAllNotPrevision());
listeEntiteRemplace.remove(this.entity);
return listeEntiteRemplace;
}
/**
* Renvoie la liste des fiches de postes groupées par Sigle
*
* @return la liste des fiches de postes groupées par Sigle
*/
public FichePosteGroupingModel getFichePosteGroupingModel() {
if (this.entity == null || !this.ongletSelectionne.equals(EntiteOnglet.FDP)) {
return null;
}
if (this.fichePosteGroupingModel != null || this.afficheFdpTableau) {
return this.fichePosteGroupingModel;
}
String listIdStatutFDP = StatutFichePoste.getListIdStatutActif();
if (this.afficheFdpInactive) {
listIdStatutFDP += "," + StatutFichePoste.INACTIVE.getId();
}
List<FichePosteDto> listeFichePosteDto = sirhWSConsumer.getFichePosteByIdEntite(this.entity.getIdEntite(), listIdStatutFDP, true);
this.fichePosteGroupingModel = new FichePosteGroupingModel(listeFichePosteDto, new ComparatorUtil.FichePosteComparatorAvecSigleEnTete(this.entity.getSigle()), this.entity.getSigle());
return this.fichePosteGroupingModel;
}
/**
* Renvoie la liste des fiches de postes
*
* @return la liste des fiches de postes
*/
public List<FichePosteDto> getListeFichePoste() {
if (this.entity == null || !this.ongletSelectionne.equals(EntiteOnglet.FDP) || !this.afficheFdpTableau) {
return null;
}
String listIdStatutFDP = StatutFichePoste.getListIdStatutActif();
if (this.afficheFdpInactive) {
listIdStatutFDP += "," + StatutFichePoste.INACTIVE.getId();
}
listeFichePoste = sirhWSConsumer.getFichePosteByIdEntite(this.entity.getIdEntite(), listIdStatutFDP, true);
return listeFichePoste;
}
@Command
@NotifyChange("fichePosteGroupingModel")
public void replierTouteFdp() {
if (this.fichePosteGroupingModel != null) {
// On replie tous les groupes sauf celui de l'entité
for (int i = 0; i < this.fichePosteGroupingModel.getGroupCount(); i++) {
this.fichePosteGroupingModel.removeOpenGroup(i);
}
}
}
@Command
public void exportExcel() throws IOException {
ExportExcelUtil.genereExportExcel(this.entity, this.afficheFdpInactive, sirhWSConsumer);
}
@Command
@NotifyChange("fichePosteGroupingModel")
public void deplierTouteFdp() {
if (this.fichePosteGroupingModel != null) {
// On replie tous les groupes sauf celui de l'entité
for (int i = 0; i < this.fichePosteGroupingModel.getGroupCount(); i++) {
this.fichePosteGroupingModel.addOpenGroup(i);
}
}
}
/**
* Renvoie la liste de l'historique de l'entité
*
* @return la liste de l'historique de l'entité
*/
public List<EntiteHistoDto> getListeHistorique() {
if (this.entity == null || !this.ongletSelectionne.equals(EntiteOnglet.HISTORIQUE)) {
return null;
}
if (this.listeHistorique != null) {
return this.listeHistorique;
}
this.listeHistorique = adsWSConsumer.getListeEntiteHisto(this.entity.getIdEntite(), new HashMap<Integer, String>());
return this.listeHistorique;
}
@Command
@NotifyChange("entity")
public void onChangeValueEntity() {
setEntiteDirty(true);
}
@Command
@NotifyChange({ "listeHistorique", "fichePosteGroupingModel", "titreOngletFdp" })
public void selectOnglet(@BindingParam("onglet") int onglet) {
setOngletSelectionne(EntiteOnglet.getEntiteOngletByPosition(onglet));
afterCompose(getView());
}
/**
* Rafraichi l'entité depuis la base de donnée
*
* @param entiteDto
* : l'entité à rafraîchir
*/
@Command
@NotifyChange({ "*" })
public void refreshEntite(@BindingParam("entity") EntiteDto entiteDto) {
refreshEntiteGeneric(entiteDto, true);
}
@GlobalCommand
@NotifyChange({ "*" })
public void refreshEntiteGlobalCommand(@BindingParam("entity") EntiteDto entiteDto) {
if (entiteDto.getId().equals(this.entity.getId())) {
refreshEntiteGeneric(entiteDto, false);
}
}
@GlobalCommand
@NotifyChange({ "*" })
public void refreshToutOngletEntite() {
refreshEntiteGeneric(this.entity, false);
}
private void refreshEntiteGeneric(EntiteDto entiteDto, boolean showNotification) {
this.entity = adsWSConsumer.getEntiteWithChildren(entiteDto.getIdEntite());
// On force à null et on rafraîchi
this.fichePosteGroupingModel = null;
this.listeFichePoste = null;
this.listeHistorique = null;
this.fichePosteGroupingModel = getFichePosteGroupingModel();
this.listeFichePoste = getListeFichePoste();
this.listeHistorique = getListeHistorique();
setEntiteDirty(false);
updateTitreOnglet();
if (showNotification) {
Clients.showNotification("Entité " + this.entity.getSigle() + " rafraîchie.", "info", null, "top_center", 0);
}
}
/**
* Met à jour le {@link EntiteDto} avec les informations renseignées côté
* client
*
* @param entiteDto
* : l'{@link EntiteDto} à mettre à jour
* @return true si tout s'est bien passé, false sinon
*/
@Command
@NotifyChange({ "entity", "listeHistorique" })
public boolean updateEntite(@BindingParam("entity") EntiteDto entiteDto) {
if (!profilAgentDto.isEdition() || showErrorPopup(entiteDto)) {
return false;
}
entiteDto.setIdAgentModification(profilAgentDto.getIdAgent());
// On fait appel au WS ADS de mise à jour d'une entité
ReturnMessageDto returnMessageDto = adsWSConsumer.saveOrUpdateEntite(entiteDto);
if (!returnMessageService.gererReturnMessage(returnMessageDto, false)) {
return false;
}
// On recharge l'arbre complet d'ADS et on rafraichi le client. Ainsi on
// est sur d'avoir une version bien à jour
BindUtils.postGlobalCommand(null, null, "refreshOrganigrammeWithoutSelectedEntite", new HashMap<String, Object>());
setEntiteDirty(false);
this.listeHistorique = null;
return true;
}
/**
* Supprime l'{@link EntiteDto} de l'arbre DTO représentée par l'
* {@link EntiteDto} entiteDtoRoot et rafraichie côté client
*
* @param entiteDto
* : l'{@link EntiteDto} à supprimer
*/
@Command
@NotifyChange("*")
public void deleteEntite(@BindingParam("entity") EntiteDto entiteDto) {
if (!profilAgentDto.isEdition() && entiteDto.isPrevision()) {
return;
}
entiteDto.setIdAgentSuppression(profilAgentDto.getIdAgent());
final EntiteDto entiteDtoASupprimer = entiteDto;
String messageConfirmation = "Voulez-vous vraiment supprimer l'entité '" + entiteDto.getLabel() + "'";
boolean hasChildren = null != entiteDto.getEnfants() && !entiteDto.getEnfants().isEmpty();
if (hasChildren) {
messageConfirmation += "et ses sous-entités";
}
messageConfirmation += " ?";
Messagebox.show(messageConfirmation, "Suppression", new Messagebox.Button[] { Messagebox.Button.YES, Messagebox.Button.NO }, Messagebox.QUESTION, new EventListener<Messagebox.ClickEvent>() {
@Override
public void onEvent(ClickEvent evt) {
if (evt.getName().equals("onYes")) {
if (organigrammeService.deleteEntite(entiteDtoASupprimer)) {
fermeToutOnglet(entity);
setEntity(null);
// On recharge l'arbre complet d'ADS et on
// rafraichi le client. Ainsi on est sur d'avoir
// une version bien à jour
BindUtils.postGlobalCommand(null, null, "refreshOrganigrammeWithoutSelectedEntite", null);
}
}
}
});
}
private void fermeToutOnglet(EntiteDto entiteDto) {
fermeOnglet(entiteDto);
for (EntiteDto entiteDtoEnfant : entiteDto.getEnfants()) {
fermeToutOnglet(entiteDtoEnfant);
}
}
/**
* Verifie que l entite et ses sous entites sont tous en statut PREVISION
*
* @return
*/
public boolean isEntityWithAllEntityChildrenInPrevision() {
return isEntityWithAllEntityChildrenInPrevisionRecursive(this.entity, true);
}
private boolean isEntityWithAllEntityChildrenInPrevisionRecursive(EntiteDto entite, boolean result) {
if (!Statut.PREVISION.equals(entite.getStatut())) {
return false;
}
if (null != entite.getEnfants()) {
for (EntiteDto enfant : entite.getEnfants()) {
result = isEntityWithAllEntityChildrenInPrevisionRecursive(enfant, result);
if (!result)
return result;
}
}
return result;
}
@GlobalCommand
public void refreshArbreFichesPoste(@BindingParam("entiteCible") EntiteDto entiteCible) {
afterCompose(getView());
this.fichePosteGroupingModel = null;
this.listeFichePoste = null;
notifyChange(LISTE_PROP_A_NOTIFIER_DEPLACE_FDP);
ouvreOnglet(entiteCible, 0);
}
@Command
@NotifyChange({ "*" })
public void passerTransition(@BindingParam("transition") Transition transition) {
if (!profilAgentDto.isEdition()) {
return;
}
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("transition", transition);
arguments.put("entite", this.entity);
BindUtils.postGlobalCommand(null, null, "passerTransitionSurEntite", arguments);
}
/**
* L AfterCompose construit des elements javascript et html apres la
* construction de la page ZUL en HTML par ZK. Cela nous permet donc d
* inserer nos arbres de fiches de poste customisés avec des DI propre a
* chaque entite.
*
* @param view
* Component
*/
@AfterCompose
public void afterCompose(@ContextParam(ContextType.VIEW) Component view) {
// on sauvegarde la vue pour le changement de sous-onglet
if (null != view && null == getView()) {
setView(view);
}
// permet de gérer le onClickFDP
Selectors.wireEventListeners(view, this);
if (getOngletSelectionne().equals(EntiteOnglet.ORGANIGRAMME_FICHES_POSTE)) {
hlayoutTreeFichesPoste = (Div) view.getFellow("tabpanelTreeFichesPoste").getFellow("includeTreeFichesPoste").getFellow("treeFichesPoste");
listFichePosteTreeNodeDto = sirhWSConsumer.getTreeFichesPosteByEntite(this.entity.getIdEntite(), isAfficheFdpNonReglementaires());
creeArbre();
for (FichePosteTreeNodeDto fichePosteTreeNodeDto : getAllFichePosteTreeNodeDtoAPlat(this.entity)) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(fichePosteTreeNodeDto.getIdLi(), true);
}
try {
view.getFellow("tabpanelTreeFichesPoste").getFellow("includeTreeFichesPoste").getFellow("treeFichesPoste").getFellow("divChild").detach();
} catch (Exception e) {
// dans le cas ou la Div "divChild" n'existe pas encore
// car creer dans planner.render()
}
try {
Executions.createComponentsDirectly(createTreeFichesPoste(this.entity.getIdEntite()), null,
view.getFellow("tabpanelTreeFichesPoste").getFellow("includeTreeFichesPoste").getFellow("treeFichesPoste"), null);
} catch (Exception e) {
LOGGER.debug("Une erreur est survenue dans la creation du planning : " + e.getMessage());
}
}
}
/**
* Evenement qui se déclenche lors d'un click sur une entité côté client
*
* @param event
* : l'évenement click qui contient dans getData() l'id du li
* selectionné
*/
@Listen("onClickFDP = #editEntiteLayout")
public void onClickFDP(Event event) {
FichePosteTreeNodeDto node = mapIdLiFichePosteTreeNodeDto.get(event.getData());
setFichePoste(node);
}
@Listen("onClickFlecheDeplierReplierFdp = #editEntiteLayout")
public void onClickFlecheDeplierReplierFdp(Event event) {
FichePosteTreeNodeDto fichePosteTreeNodeDto = mapIdLiFichePosteTreeNodeDto.get(event.getData());
if (fichePosteTreeNodeDto != null) {
String idLi = fichePosteTreeNodeDto.getIdLi();
boolean ouvert = mapIdLiFichePosteTreeNodeDtoOuvert.get(idLi) != null ? !mapIdLiFichePosteTreeNodeDtoOuvert.get(idLi) : false;
mapIdLiFichePosteTreeNodeDtoOuvert.put(idLi, ouvert);
}
}
/**
* Exporte au format GraphML l'arbre ayant pour racine l'{@link EntiteDto}
* entiteDto
*
* @param node
* le noeud à partir duquel on exporte
*/
@Command
public void lancerExport(@BindingParam("fichePoste") FichePosteTreeNodeDto node) {
try {
if (getFichePoste() == null) {
return;
}
exportGraphMLService.exportGraphMLFromFichesPoste(mapIdLiFichePosteTreeNodeDto.get(getFichePoste().getIdLi()), this.afficheAgentFdp, mapIdLiFichePosteTreeNodeDtoOuvert, this.entity);
} catch (IOException e) {
AbstractViewModel.showErrorPopup("Une erreur est survenu lors de l'ajout du logo de la Mairie dans le fichier d'export");
}
}
/**
* Creer un arbre de fiche de poste en recuperant un arbre de
* FichePosteTreeNodeDto depuis SIRH-WS
*
*/
public void creeArbre() {
if (listFichePosteTreeNodeDto != null) {
Div vlayout = hlayoutTreeFichesPoste;
for (FichePosteTreeNodeDto node : listFichePosteTreeNodeDto) {
HashMap<Integer, FichePosteTreeNodeDto> mapFichesPosteSuperieureByServiceTmp = EntityUtils.getFichesPosteChefDeService(node);
for (Integer key : mapFichesPosteSuperieureByServiceTmp.keySet()) {
if (!mapFichesPosteSuperieureByService.containsKey(key)) {
mapFichesPosteSuperieureByService.put(key, mapFichesPosteSuperieureByServiceTmp.get(key));
}
}
}
Component arbre = genereArbre(listFichePosteTreeNodeDto);
int i = 0;
while (!CollectionUtils.isEmpty(vlayout.getChildren()) && i < vlayout.getChildren().size()) {
if (vlayout.getChildren().get(i).getId().contains("organigramme-fichesPoste")) {
vlayout.removeChild(vlayout.getChildren().get(i));
}
i++;
}
if (arbre == null) {
return;
}
vlayout.appendChild(arbre);
}
}
private List<FichePosteTreeNodeDto> getAllFichePosteTreeNodeDtoAPlat(EntiteDto entiteDtoRoot) {
if (null == listFichePosteTreeNodeDto || listFichePosteTreeNodeDto.isEmpty()) {
listFichePosteTreeNodeDto = sirhWSConsumer.getTreeFichesPosteByEntite(entiteDtoRoot.getIdEntite(), true);
}
List<FichePosteTreeNodeDto> result = new ArrayList<FichePosteTreeNodeDto>();
getAllFichePosteTreeNodeDtoAPlatRecursive(result, listFichePosteTreeNodeDto);
return result;
}
private void getAllFichePosteTreeNodeDtoAPlatRecursive(List<FichePosteTreeNodeDto> result, List<FichePosteTreeNodeDto> listeEnfant) {
if (!CollectionUtils.isEmpty(listeEnfant)) {
for (FichePosteTreeNodeDto fichePosteTreeNodeDto : listeEnfant) {
result.add(fichePosteTreeNodeDto);
getAllFichePosteTreeNodeDtoAPlatRecursive(result, fichePosteTreeNodeDto.getFichePostesEnfant());
}
}
}
/**
* Permet d inserer les fonctions javascripts et les layout et div utile au
* framework jquery.orgchart
*
* @param idEntite
* : l'entité en cours
* @return le html qui sera ajouté
*/
private String createTreeFichesPoste(Integer idEntite) {
StringBuffer result = new StringBuffer();
result.append("<div id='divChild'><html>");
result.append("<div id=\"panel-entier" + idEntite + "\">");
result.append("<div id=\"chart" + idEntite + "\" class=\"chart\" /> ");
result.append("</div>");
result.append("<script type=\"text/javascript\">");
result.append(" $(\"#organigramme-fichesPoste-" + idEntite + "\").orgChart({container: $('#chart" + idEntite + "')});");
result.append(" var hauteurFenetre = $(\"#panel-entier\").parent().height();");
result.append(" $('#chart" + idEntite + "').height(hauteurFenetre - 100);");
result.append(" $('#panel-entier" + idEntite + "').height(hauteurFenetre);");
result.append(" $('#chart" + idEntite + "').kinetic();");
result.append(" $(window).trigger('resize');");
result.append("</script>");
result.append("</html></div>");
return result.toString();
}
/**
* Génére les composants {@link Ul}/{@link Li} qui forment l'arbre (ces
* {@link Ul}/{@link Li} html seront retravaillées par le plugin jQuery Org
* Chart afin de les transformer en div/table/tr/td et de les afficher sous
* forme d'arbre)
*
* @param listFichePosteTreeNodeDto
* : les nodes des FDP
* @return le {@link Ul} de plus haut niveau qui est ajouté au
* {@link Vlayout}
*/
public Component genereArbre(List<FichePosteTreeNodeDto> listFichePosteTreeNodeDto) {
if (listFichePosteTreeNodeDto == null || listFichePosteTreeNodeDto.isEmpty()) {
return null;
}
mapIdLiFichePosteTreeNodeDto = new HashMap<String, FichePosteTreeNodeDto>();
// Initialisation de l'entité ROOT
Ul ulRoot = new Ul();
ulRoot.setId("organigramme-fichesPoste-" + this.entity.getIdEntite());
ulRoot.setSclass("hide");
FichePosteTreeNodeDto rootFictif = new FichePosteTreeNodeDto();
rootFictif.setIdFichePoste(ID_FICHE_POSTE_FICTIF + this.entity.getIdEntite());
rootFictif.setNumero("0000/00");
rootFictif.setTitre(this.entity.getSigle());
rootFictif.setSigle(this.entity.getLabelCourt());
rootFictif.setService(this.entity.getLabel());
rootFictif.setAgent("");
rootFictif.setIdStatutFDP(2);
rootFictif.getFichePostesEnfant().addAll(listFichePosteTreeNodeDto);
setFichePoste(rootFictif);
Li li = creeLiEntite(ulRoot, rootFictif);
li.setSclass("hide");
// Initialisation du reste de l'arbre
genereArborescenceHtml(listFichePosteTreeNodeDto, li);
return ulRoot;
}
/**
* Crée une feuille unitaire
*
* @param ul
* : le {@link Ul} parent
* @param node
* : le node de la FDP
* @return le composant {@link Li} représentant l'entité
*/
public Li creeLiEntite(Ul ul, final FichePosteTreeNodeDto node) {
Li li = new Li();
String numFichePoste = OrganigrammeUtil.splitByNumberAndSeparator(node.getNumero(), 8, "\n");
Div divNumFichePoste = new Div();
divNumFichePoste.appendChild(new Label(numFichePoste));
// #17877 les FDP gelée
if (null != node.getIdStatutFDP() && node.getIdStatutFDP().equals(EnumStatutFichePoste.GELEE.getStatut())) {
Label labelGelee = new Label(" GELEE");
labelGelee.setStyle("font-weight: bold; color:red;");
divNumFichePoste.appendChild(labelGelee);
}
li.appendChild(divNumFichePoste);
Div divTitreFichePoste = new Div();
// #18575 Si le titre de la FDP est trop long, alors pour ne pas que ça
// sorte de la case, on raccourcis le nom de l'agent
String suffixeSigleSiEnfant = CollectionUtils.isEmpty(node.getFichePostesEnfant()) ? "" : " (" + node.sigle + ")";
String libelleTitreEtSigle = node.getTitre() + suffixeSigleSiEnfant;
String libelleAgent = node.getAgent();
String libelleAgentAbbreviate = libelleTitreEtSigle.length() > 50 ? StringUtils.abbreviate(libelleAgent, 27) : libelleAgent;
String libelleTitreEtSigleAbbreviate = StringUtils.abbreviate(libelleTitreEtSigle, 80);
divTitreFichePoste.appendChild(new Label(libelleTitreEtSigleAbbreviate));
li.appendChild(divTitreFichePoste);
if (isAfficheAgentFdp()) {
Div divAgent = new Div();
divAgent.appendChild(new Label(libelleAgentAbbreviate));
li.appendChild(divAgent);
}
li.setParent(ul);
// #28374 : la demande serait d'avoir le chef d'entité de la même
// couleur que l'entité
// retourne l entite seulement si la fiche de poste est la superieure
// hierarchique de ce service
CouleurTypeEntite couleurTypeEntite = null;
if (!node.getServiceAffichageExportYed().equals("")) {
EntiteDto entitePourFichePosteChef = EntityUtils.getBackgroundColorOfFichePoste(node, entity, mapFichesPosteSuperieureByService);
if (null != entitePourFichePosteChef) {
couleurTypeEntite = couleurTypeEntiteService.findByIdTypeEntite(entitePourFichePosteChef.getTypeEntite().getId());
if (couleurTypeEntite != null) {
entitePourFichePosteChef.getTypeEntite().setCouleurEntite(couleurTypeEntite.getCouleurEntite());
entitePourFichePosteChef.getTypeEntite().setCouleurTexte(couleurTypeEntite.getCouleurTexte());
}
}
}
// #28374 : la demande serait d'avoir le chef d'entité de la même
// couleur que l'entité
// CouleurTypeEntite couleurTypeEntite = null;
// if(!node.getServiceAffichageExportYed().equals("")
// && null != node.getIdServiceADS()) {
// try {
// couleurTypeEntite =
// couleurTypeEntiteService.findByIdTypeEntite(EntityUtils.getEntiteByIdServiceAds(
// node.getIdServiceADS(), entity).getTypeEntite().getId());
// } catch(Exception e) {
// couleurTypeEntite = null;
// }
// }
// #17875 Affichage en rouge des FDP non réglementaires
if (null != node.getReglementaire() && "Non".equals(node.getReglementaire().trim())) {
li.setStyle("background-color:red; color:white;");
} else if (null != couleurTypeEntite) {
// #28374 : la demande serait d'avoir le chef d'entité de la même
// couleur que l'entité
li.setStyle("background-color:" + couleurTypeEntite.getCouleurEntite() + "; color: " + couleurTypeEntite.getCouleurTexte() + ";");
} else {
li.setStyle("background-color:#FFFFCF; color:#000000;");
}
li.setSclass("statut-" + StringUtils.lowerCase(node.getStatutCss()) + " fichePoste");
li.setId(node.getIdLi());
li.setDynamicProperty("title", creeTooltipEntite(node, libelleTitreEtSigle, libelleAgent));
// On maintient une map permettant d'aller plus vite lors d'un click
// event pour retrouver FichePosteTreeNodeDto correspondant à l'id du Li
mapIdLiFichePosteTreeNodeDto.put(li.getId(), node);
return li;
}
/**
* Genere l arborescence de l arbre avec les fiches de poste enfant
*
* @param listeFichePosteTreeNodeDto
* la liste des fiches de postes
* @param component
* Component
* @return Component
*/
public Component genereArborescenceHtml(List<FichePosteTreeNodeDto> listeFichePosteTreeNodeDto, Component component) {
Ul ul = new Ul();
ul.setParent(component);
for (final FichePosteTreeNodeDto fichePosteTreeNode : listeFichePosteTreeNodeDto) {
Li li = creeLiEntite(ul, fichePosteTreeNode);
if (null != fichePosteTreeNode.getFichePostesEnfant() && !fichePosteTreeNode.getFichePostesEnfant().isEmpty()) {
List<FichePosteTreeNodeDto> listeFichePosteDtoEnfant = new ArrayList<FichePosteTreeNodeDto>();
listeFichePosteDtoEnfant.addAll(fichePosteTreeNode.getFichePostesEnfant());
Collections.sort(listeFichePosteDtoEnfant, new ComparatorUtil.FichePosteCategorieComparator());
genereArborescenceHtml(listeFichePosteDtoEnfant, li);
}
}
return ul;
}
public Div getHlayoutTreeFichesPoste() {
return hlayoutTreeFichesPoste;
}
public void setHlayoutTreeFichesPoste(Div hlayoutTreeFichesPoste) {
this.hlayoutTreeFichesPoste = hlayoutTreeFichesPoste;
}
public Component getView() {
return view;
}
public void setView(Component view) {
this.view = view;
}
@GlobalCommand
public void onCloseEntiteOnglet(@BindingParam("entity") AbstractEntityDto abstractEntityDto, @BindingParam("tab") Tab tab) {
if (abstractEntityDto != null && abstractEntityDto instanceof EntiteDto) {
EntiteDto entiteDto = (EntiteDto) abstractEntityDto;
if (entiteDto.getId().equals(this.entity.getId())) {
if (this.entity.isDirty()) {
final EntiteDto entiteASauver = this.entity;
final Tab tabAFermer = tab;
Messagebox.show("Voulez-vous enregistrer les modifications apportées à l'entité '" + this.entity.getSigle() + "' ?", "Fermeture de l'onglet", new Messagebox.Button[] {
Messagebox.Button.YES, Messagebox.Button.NO, Messagebox.Button.CANCEL }, Messagebox.QUESTION, new EventListener<Messagebox.ClickEvent>() {
@Override
public void onEvent(ClickEvent evt) {
if (evt.getName().equals("onYes")) {
updateEntite(entiteASauver);
tabAFermer.onClose();
}
if (evt.getName().equals("onNo")) {
tabAFermer.onClose();
}
}
});
} else {
tab.onClose();
}
}
}
}
/**
* @return statut de l'entité
*/
@DependsOn("entity")
public Statut getStatut() {
if (this.entity == null) {
return null;
}
return entity.getStatut();
}
/**
* @return la liste des transitions autorisées pour cette entité
*/
public List<Transition> getListeTransitionAutorise() {
if (this.entity == null) {
return null;
}
return this.entity.getListeTransitionAutorise();
}
/**
* L'entité est-elle créable ?
*
* @return true si l'entité est créable, false sinon
*/
public boolean isCreable() {
// On ne peux créer que si on a le rôle édition
return profilAgentDto.isEdition() && this.entity != null;
}
public boolean isAfficheFdpNonReglementaires() {
return afficheFdpNonReglementaires;
}
public void setAfficheFdpNonReglementaires(boolean afficheFdpNonReglementaires) {
this.afficheFdpNonReglementaires = afficheFdpNonReglementaires;
afterCompose(getView());
}
public boolean isAfficheAgentFdp() {
return afficheAgentFdp;
}
public void setAfficheAgentFdp(boolean afficheAgentFdp) {
this.afficheAgentFdp = afficheAgentFdp;
afterCompose(getView());
}
private String creeTooltipEntite(FichePosteTreeNodeDto node, String titre, String agent) {
// le champ réglementaire + la catégorie
List<String> listeLigneTooltip = new ArrayList<String>();
if (!StringUtils.isEmpty(titre)) {
listeLigneTooltip.add("Titre : " + titre);
}
if (!StringUtils.isEmpty(agent)) {
listeLigneTooltip.add("Agent : " + agent);
}
if (!StringUtils.isEmpty(node.getReglementaire())) {
listeLigneTooltip.add("Réglementaire : " + node.getReglementaire());
}
if (!StringUtils.isEmpty(node.getCategorie())) {
listeLigneTooltip.add("Catégorie : " + node.getGradePoste() + " (" + node.getCategorie() + ")");
}
return StringUtils.join(listeLigneTooltip, "<br/>");
}
public FichePosteTreeNodeDto getFichePoste() {
return fichePoste;
}
public void setFichePoste(FichePosteTreeNodeDto fichePoste) {
this.fichePoste = fichePoste;
}
public List<FichePosteTreeNodeDto> getListFichePosteTreeNodeDto() {
return listFichePosteTreeNodeDto;
}
public void setListFichePosteTreeNodeDto(List<FichePosteTreeNodeDto> listFichePosteTreeNodeDto) {
this.listFichePosteTreeNodeDto = listFichePosteTreeNodeDto;
}
@Command
public void deplierNiveau() {
deplierReplierNiveau(true);
}
@Command
public void replierNiveau() {
deplierReplierNiveau(false);
}
@Listen("onClickToutDeplierFdp = #editEntiteLayout")
public void onClickToutDeplierFdp(Event event) {
if (fichePoste != null) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(fichePoste.getIdLi(), true);
setLiOuvertOuFerme(fichePoste.getFichePostesEnfant(), true);
}
}
@Listen("onClickToutReplierFdp = #editEntiteLayout")
public void onClickToutReplierFdp(Event event) {
if (fichePoste != null) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(fichePoste.getIdLi(), false);
setLiOuvertOuFerme(fichePoste.getFichePostesEnfant(), false);
}
}
private void setLiOuvertOuFerme(List<FichePosteTreeNodeDto> listeFichePosteTreeNodeDto, boolean ouvert) {
for (FichePosteTreeNodeDto fichePosteTreeNodeDto : listeFichePosteTreeNodeDto) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(fichePosteTreeNodeDto.getIdLi(), ouvert);
setLiOuvertOuFerme(fichePosteTreeNodeDto.getFichePostesEnfant(), ouvert);
}
}
private Map<FichePosteTreeNodeDto, Integer> getMapFdpNiveau(FichePosteTreeNodeDto node, Map<FichePosteTreeNodeDto, Integer> mapFdpNiveau, Integer niveau) {
if (node.getIdFichePoste().equals(ID_FICHE_POSTE_FICTIF + this.entity.getIdEntite())
|| (null != mapIdLiFichePosteTreeNodeDtoOuvert.get(node.getIdLi()) && mapIdLiFichePosteTreeNodeDtoOuvert.get(node.getIdLi()))) {
for (FichePosteTreeNodeDto fdpDtoEnfant : node.getFichePostesEnfant()) {
mapFdpNiveau.put(fdpDtoEnfant, niveau);
}
for (FichePosteTreeNodeDto fdpDtoEnfant : node.getFichePostesEnfant()) {
if (mapIdLiFichePosteTreeNodeDtoOuvert.get(fdpDtoEnfant.getIdLi()) && !CollectionUtils.isEmpty(fdpDtoEnfant.getFichePostesEnfant())) {
getMapFdpNiveau(fdpDtoEnfant, mapFdpNiveau, niveau + 1);
}
}
}
return mapFdpNiveau;
}
private Integer getMaxNiveauFromMap(Map<FichePosteTreeNodeDto, Integer> mapFdpNiveau) {
Map.Entry<FichePosteTreeNodeDto, Integer> maxEntry = null;
for (Map.Entry<FichePosteTreeNodeDto, Integer> entry : mapFdpNiveau.entrySet()) {
if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0) {
maxEntry = entry;
}
}
return maxEntry.getValue();
}
private void deplierReplierNiveau(boolean deplier) {
if (fichePoste != null) {
Map<FichePosteTreeNodeDto, Integer> mapFdpNiveau = new HashMap<FichePosteTreeNodeDto, Integer>();
mapFdpNiveau.put(fichePoste, 0);
mapFdpNiveau = getMapFdpNiveau(fichePoste, mapFdpNiveau, 1);
Integer maxNiveauOuvert = getMaxNiveauFromMap(mapFdpNiveau);
List<FichePosteTreeNodeDto> listeFdpDto = new ArrayList<FichePosteTreeNodeDto>();
listeFdpDto.add(fichePoste);
Integer niveauRecherche = deplier ? maxNiveauOuvert : maxNiveauOuvert - 1;
if (!niveauRecherche.equals(0)) {
if (deplier) {
for (int niveauParcouru = 0; niveauParcouru <= niveauRecherche; niveauParcouru++) {
deplierReplierParNiveau(deplier, listeFdpDto, niveauParcouru);
}
} else {
deplierReplierParNiveau(deplier, listeFdpDto, maxNiveauOuvert - 1);
}
}
}
}
private void deplierReplierParNiveau(boolean deplier, List<FichePosteTreeNodeDto> listeFdpDto, int niveauParcouru) {
for (FichePosteTreeNodeDto fdpDtoNiveau : getListeFromFdpAndNiveau(listeFdpDto, niveauParcouru, new ArrayList<FichePosteTreeNodeDto>())) {
mapIdLiFichePosteTreeNodeDtoOuvert.put(fdpDtoNiveau.getIdLi(), deplier);
String fdpIdLi = fdpDtoNiveau.getIdLi();
if (deplier) {
Clients.evalJavaScript("deplierNiveau('" + fdpIdLi + "');");
} else {
Clients.evalJavaScript("replierNiveau('" + fdpIdLi + "');");
}
}
}
private List<FichePosteTreeNodeDto> getListeFromFdpAndNiveau(List<FichePosteTreeNodeDto> listeEnfant, Integer niveau, List<FichePosteTreeNodeDto> result) {
if (niveau.equals(0)) {
result.addAll(listeEnfant);
return result;
}
for (FichePosteTreeNodeDto entiteDtoEnfant : listeEnfant) {
getListeFromFdpAndNiveau(entiteDtoEnfant.getFichePostesEnfant(), niveau - 1, result);
}
return result;
}
@Command
@NotifyChange({ "*" })
public void ouvrirPopupDeplacerFichesPoste() {
if (!this.entity.isTransitoire()) {
Messagebox.show("L'entité doit être dans le statut transitoire pour pouvoir déplacer les FDP", "Erreur", Messagebox.OK, Messagebox.ERROR);
return;
}
Map<String, Object> args = new HashMap<>();
args.put("entity", this.entity);
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("entity", this.entity);
Executions.createComponents("/layout/popupDeplacerFichesPoste.zul", null, arguments);
BindUtils.postGlobalCommand(null, null, "ouvrePopupDeplacerFichesPoste", args);
}
public boolean isEntiteVDN() {
if (this.entity == null) {
return false;
}
if (this.entity.getSigle().toLowerCase().equals("vdn")) {
return true;
}
return false;
}
@Command
@NotifyChange({ "*" })
public void ouvrirPopupTransitoireFichesPoste() {
if (!this.entity.isTransitoire()) {
Messagebox.show("L'entité doit être dans le statut transitoire pour pouvoir rendre transitoires les FDP", "Erreur", Messagebox.OK, Messagebox.ERROR);
return;
}
Map<String, Object> args = new HashMap<>();
args.put("entity", this.entity);
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("entity", this.entity);
Executions.createComponents("/layout/popupTransitoireFichesPoste.zul", null, arguments);
BindUtils.postGlobalCommand(null, null, "ouvrePopupTransitoireFichesPoste", args);
}
@Command
@NotifyChange({ "*" })
public void ouvrirPopupInactiveFichesPoste() {
if (!this.entity.isTransitoire()) {
Messagebox.show("L'entité doit être dans le statut transitoire pour pouvoir rendre inactives les FDP", "Erreur", Messagebox.OK, Messagebox.ERROR);
return;
}
Map<String, Object> args = new HashMap<>();
args.put("entity", this.entity);
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("entity", this.entity);
Executions.createComponents("/layout/popupInactiveFichesPoste.zul", null, arguments);
BindUtils.postGlobalCommand(null, null, "ouvrePopupTransitoireFichesPoste", args);
}
}