package nc.noumea.mairie.organigramme.controller;
/*
* #%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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import nc.noumea.mairie.organigramme.core.entity.AbstractEntity;
import nc.noumea.mairie.organigramme.core.event.FermeOngletAbstractEntityEvent;
import nc.noumea.mairie.organigramme.core.event.OuvreOngletAbstractEntityEvent;
import nc.noumea.mairie.organigramme.core.event.OuvreOngletAdministationEvent;
import nc.noumea.mairie.organigramme.core.event.RechargeOngletAbstractEntityEvent;
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.utility.ZkUtil;
import nc.noumea.mairie.organigramme.dto.ProfilAgentDto;
import org.apache.commons.lang.StringUtils;
import org.zkoss.bind.BindUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
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.event.Events;
import org.zkoss.zk.ui.event.SerializableEventListener;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Messagebox.ClickEvent;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Tabbox;
import org.zkoss.zul.Tabpanel;
import org.zkoss.zul.Tabpanels;
import org.zkoss.zul.Tabs;
/**
* MainController permettant de gérer tous les comportements généraux de
* l'application. Construction de la sidebar, gestion des ouvertures d'onglets,
* ....
*
* @author Thomas
*/
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
public class MainController extends SelectorComposer<Component> {
private static final long serialVersionUID = 1L;
@Wire
Grid sideBarGrid;
@Wire
Borderlayout mainBorderLayout;
@WireVariable
AuthentificationService authentificationService;
/**
* Rempli la sidebar avec les items par défaut de l'application
*
* @param comp
* Component description
*/
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
ProfilAgentDto currentUser = authentificationService.getCurrentUser();
if (currentUser != null) {
mainBorderLayout.setVisible(true);
} else {
messageBoxAccesRefuse();
return;
}
// to initial view after view constructed.
Rows rows = sideBarGrid.getRows();
List<SidebarItem> listeItems = this.initSideBar();
for (SidebarItem item : listeItems) {
Row row = constructSidebarRow(item.getLabel(), item.getIconUri(), item.getUri());
rows.appendChild(row);
if (item.isOngletFixe()) {
// Onglet à afficher par défaut
ouvreOnglet(null, item.getLabel(), item.getUri(), true, false, null);
}
}
getTabbox().setSelectedIndex(0);
// On n'affiche pas la le menu de gauche
sideBarGrid.getParent().setVisible(false);
EventQueues.lookup("organigrammeQueue", EventQueues.DESKTOP, true).subscribe(new EventListener<Event>() {
@Override
public void onEvent(Event event) {
if (event instanceof OuvreOngletAdministationEvent) {
OuvreOngletAdministationEvent ouvreOngletAdministationEvent = (OuvreOngletAdministationEvent) event;
ouvreOnglet(null, ouvreOngletAdministationEvent.getTitreOnglet(), ouvreOngletAdministationEvent.getUri(), false, false, null);
}
if (event instanceof OuvreOngletAbstractEntityEvent) {
OuvreOngletAbstractEntityEvent ouvreOngletAbstractEntityEvent = (OuvreOngletAbstractEntityEvent) event;
AbstractEntity abstractEntity = ouvreOngletAbstractEntityEvent.getAbstractEntity();
Integer selectedTabIndex = ouvreOngletAbstractEntityEvent.getSelectedTabIndex();
ouvreOnglet(abstractEntity, abstractEntity.getLibelleCourt(), getEditViewURI(abstractEntity), false, false, selectedTabIndex);
}
if (event instanceof FermeOngletAbstractEntityEvent) {
AbstractEntity abstractEntity = ((FermeOngletAbstractEntityEvent) event).getAbstractEntity();
fermeOnglet(abstractEntity);
}
if (event instanceof RechargeOngletAbstractEntityEvent) {
RechargeOngletAbstractEntityEvent rechargeEvent = (RechargeOngletAbstractEntityEvent) event;
rechargeOnglet(rechargeEvent.getAbstractEntity(), rechargeEvent.getSelectedTabIndex());
}
if (event instanceof UpdateOngletAbstractEntityEvent) {
AbstractEntity abstractEntity = ((UpdateOngletAbstractEntityEvent) event).getAbstractEntity();
String suffixe = ((UpdateOngletAbstractEntityEvent) event).getSuffixe();
updateLibelleOnglet(abstractEntity, suffixe);
}
}
});
}
private void messageBoxAccesRefuse() {
Messagebox.show("Vous avez bien été authentifié, mais votre compte n'est pas configuré pour vous permettre d'accéder à l'application. Veuillez demander les droits à l'administrateur",
"Accès refusé", new Messagebox.Button[] { Messagebox.Button.OK }, Messagebox.ERROR, new EventListener<Messagebox.ClickEvent>() {
@Override
public void onEvent(ClickEvent evt) {
authentificationService.logout();
}
});
}
private String getEditViewURI(AbstractEntity abstractEntity) {
return "/layout/edit" + OrganigrammeUtil.getSimpleClassNameOfObject(abstractEntity) + ".zul";
}
/**
* Initialise la liste des items de la sidebar
*
* @return la liste contenant les items à ajouter à la sidebar
*/
private List<SidebarItem> initSideBar() {
List<SidebarItem> listeItems = new ArrayList<SidebarItem>();
// @formatter:off
listeItems.add(new SidebarItem("Organigramme", "/imgs/icon/organigramme.png", "/layout/organigramme.zul", true, false));
// @formatter:on
return listeItems;
}
/**
* Renvoie un item (i.e. une ligne) à ajouter dans la sidebar
*
* @param label
* : le libellé de l'item
* @param imageSrc
* : l'url de l'icone
* @param locationUri
* : l'url de la vue à afficher
* @return une ligne prêt a être ajoutée à la sidebar
*/
private Row constructSidebarRow(final String label, final String imageSrc, final String locationUri) {
// construct component and hierarchy
Row row = new Row();
Image image = new Image(imageSrc);
Label lab = new Label(label);
row.appendChild(image);
row.appendChild(lab);
// set style attribute
row.setSclass("sidebar-fn");
// new and register listener for events
EventListener<Event> onActionListener = new SerializableEventListener<Event>() {
private static final long serialVersionUID = 1L;
@Override
public void onEvent(Event event) throws Exception {
// redirect current url to new location
if (locationUri.startsWith("http")) {
// open a new browser tab
Executions.getCurrent().sendRedirect(locationUri);
return;
}
ouvreOnglet(null, label, locationUri, false, false, null);
}
};
row.addEventListener(Events.ON_CLICK, onActionListener);
return row;
}
/**
* Recharge l'onglet couramment sélectionné
*
* @param abstractEntity
*/
private void rechargeOnglet(AbstractEntity abstractEntity, Integer selectedTabIndex) {
if (abstractEntity == null) {
return;
}
Tabbox tabbox = getTabbox();
Tab tab = tabbox.getSelectedTab();
if (tab == null) {
return;
}
Tabpanel tabPanel = tabbox.getSelectedPanel();
final Map<String, Object> map = new HashMap<String, Object>();
map.put("entity", abstractEntity);
Components.removeAllChildren(tabPanel);
Executions.createComponents(getEditViewURI(abstractEntity), tabPanel, map);
selectionneSousOnglet(abstractEntity, selectedTabIndex);
}
private void selectionneSousOnglet(AbstractEntity abstractEntity, Integer selectedTabIndex) {
if (abstractEntity == null || selectedTabIndex == null) {
return;
}
// sélectionne le sous-onglet
final Map<String, Object> mapSelectionneSousOnglet = new HashMap<String, Object>();
mapSelectionneSousOnglet.put("entity", abstractEntity);
mapSelectionneSousOnglet.put("selectedTabIndex", selectedTabIndex);
BindUtils.postGlobalCommand(null, null, "selectionneSousOnglet", mapSelectionneSousOnglet);
}
private Tabbox getTabbox() {
Page currentPage = sideBarGrid.getPage();
Tabs mainTabboxTabs = getMainTabboxTabs(currentPage);
return (Tabbox) mainTabboxTabs.getParent();
}
/**
* Ouvre un onglet et le sélectionne (ou le sélectionne uniquement si il est
* déjà ouvert)
*
* @param abstractEntity
* : l'entity rattachée à l'onglet. null si c'est un onglet
* "simple" sans entity
* @param labelOnglet
* : le libellé a afficher dans l'onglet
* @param locationUri
* : l'url de la vue
* @param selectedTabIndex
*/
private void ouvreOnglet(final AbstractEntity abstractEntity, final String labelOnglet, final String locationUri, final boolean ongletFixe, boolean disabled, Integer selectedTabIndex) {
Page currentPage = sideBarGrid.getPage();
Tabs mainTabboxTabs = getMainTabboxTabs(currentPage);
Tabpanels mainTabboxTabPanels = getMainTabboxTabPanels(currentPage);
Tabbox tabbox = getTabbox();
// important de recharger pour limiter les problèmes de modifications
// concurrentes (pour éviter bug du style #7642)
if (selectionneOngletSiPresent(abstractEntity, labelOnglet, mainTabboxTabs, tabbox)) {
rechargeOnglet(abstractEntity, selectedTabIndex);
return;
}
// Si l'onglet n'est pas déjà ouvert on le crée
final Tab tab = new Tab();
tab.setLabel(labelOnglet);
if (abstractEntity != null) {
String className = OrganigrammeUtil.getSimpleClassNameOfObject(abstractEntity);
tab.setAttribute(className + "ongletId", abstractEntity.getId());
} else {
tab.setAttribute("ongletId", labelOnglet);
}
tab.setClosable(!ongletFixe);
mainTabboxTabs.appendChild(tab);
Tabpanel tabPanel = new Tabpanel();
final Map<String, Object> map = new HashMap<String, Object>();
map.put("entity", abstractEntity);
tab.addEventListener(Events.ON_CLOSE, new EventListener<Event>() {
@Override
public void onEvent(Event event) throws Exception {
Map<String, Object> mapEntiteOnglet = new HashMap<String, Object>();
mapEntiteOnglet.put("entity", abstractEntity);
mapEntiteOnglet.put("tab", tab);
BindUtils.postGlobalCommand(null, null, "onCloseEntiteOnglet", mapEntiteOnglet);
event.stopPropagation();
}
});
mainTabboxTabPanels.appendChild(tabPanel);
Executions.createComponents(locationUri, tabPanel, map);
if (disabled) {
ZkUtil.disableComponentAndChildren(tabPanel);
}
tabbox.setSelectedTab(tab);
selectionneSousOnglet(abstractEntity, selectedTabIndex);
}
public void fermeOnglet(AbstractEntity abstractEntity) {
if (abstractEntity != null) {
String className = OrganigrammeUtil.getSimpleClassNameOfObject(abstractEntity);
Page currentPage = sideBarGrid.getPage();
Tabs mainTabboxTabs = getMainTabboxTabs(currentPage);
for (Tab tab : mainTabboxTabs.<Tab> getChildren()) {
if (abstractEntity.getId() != null && abstractEntity.getId().equals(tab.getAttribute(className + "ongletId"))) {
tab.close();
return;
}
}
}
}
/**
* Met à jour le libellé de l'onglet qui gère l'entity passée en argument
*
* @param abstractEntity
* abstractEntity description
* @param suffixe
* : un suffixe facultatif
*/
public void updateLibelleOnglet(AbstractEntity abstractEntity, String suffixe) {
if (abstractEntity == null) {
return;
}
String className = OrganigrammeUtil.getSimpleClassNameOfObject(abstractEntity);
Page currentPage = sideBarGrid.getPage();
Tabs mainTabboxTabs = getMainTabboxTabs(currentPage);
for (Tab tab : mainTabboxTabs.<Tab> getChildren()) {
if (abstractEntity.getId() != null && abstractEntity.getId().equals(tab.getAttribute(className + "ongletId"))) {
tab.setLabel(abstractEntity.getLibelleCourt() + StringUtils.trimToEmpty(suffixe));
return;
}
}
}
private boolean selectionneOngletSiPresent(AbstractEntity abstractEntity, String labelOnglet, Tabs mainTabboxTabs, Tabbox tabbox) {
if (abstractEntity != null) {
// Sélectionne l'onglet si il est déjà ouvert (en fonction de son
// id)
String className = OrganigrammeUtil.getSimpleClassNameOfObject(abstractEntity);
for (Tab tab : mainTabboxTabs.<Tab> getChildren()) {
if (abstractEntity.getId() != null && abstractEntity.getId().equals(tab.getAttribute(className + "ongletId"))) {
tabbox.setSelectedTab(tab);
return true;
}
}
} else {
// Sélectionne l'onglet si il est déjà ouvert (en fonction de son
// label)
for (Tab tab : mainTabboxTabs.<Tab> getChildren()) {
if (labelOnglet != null && labelOnglet.equals(tab.getAttribute("ongletId"))) {
tabbox.setSelectedTab(tab);
return true;
}
}
}
return false;
}
private Tabpanels getMainTabboxTabPanels(Page currentPage) {
return (Tabpanels) Selectors.iterable(currentPage, "#mainTabbox-tabpanels").iterator().next();
}
private Tabs getMainTabboxTabs(Page currentPage) {
return (Tabs) Selectors.iterable(currentPage, "#mainTabbox-tabs").iterator().next();
}
static class SidebarItem {
String label;
String iconUri;
String uri;
boolean ongletFixe;
public SidebarItem(String label, String iconUri, String uri, boolean ongletFixe, boolean onlyAdmin) {
this.label = label;
this.iconUri = iconUri;
this.uri = uri;
this.ongletFixe = ongletFixe;
}
public String getLabel() {
return label;
}
public String getIconUri() {
return iconUri;
}
public String getUri() {
return uri;
}
public boolean isOngletFixe() {
return ongletFixe;
}
}
}