/* * codjo.net * * Common Apache License 2.0 */ package net.codjo.segmentation.gui.settings; import net.codjo.mad.client.request.RequestException; import net.codjo.mad.client.request.Result; import net.codjo.mad.client.request.Row; import net.codjo.mad.common.structure.StructureReader; import net.codjo.mad.gui.framework.GuiContext; import net.codjo.mad.gui.request.DataLink; import net.codjo.mad.gui.request.DetailDataSource; import net.codjo.mad.gui.request.JoinKeys; import net.codjo.mad.gui.request.ListDataSource; import net.codjo.mad.gui.request.ErrorHandler; import net.codjo.mad.gui.request.event.DataSourceAdapter; import net.codjo.mad.gui.request.event.DataSourceEvent; import net.codjo.mad.gui.request.util.ButtonPanelLogic; import net.codjo.mad.gui.request.util.ProxyErrorHandler; import net.codjo.mad.gui.structure.StructureCache; import net.codjo.segmentation.gui.plugin.SegmentationGuiPlugin; import net.codjo.segmentation.gui.preference.PreferenceGui; import net.codjo.segmentation.gui.preference.PreferenceGuiManager; import net.codjo.segmentation.gui.preference.PreferenceGuiManagerFactory; import net.codjo.xml.XmlException; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import org.apache.log4j.Logger; /** * Logique de la fen�tre de param�trage d'un axe. */ public class ClassificationStructureLogic { private static final Logger LOG = Logger.getLogger(ClassificationStructureLogic.class.getName()); private static final String DELETE_CLASS_STRUCTURE_HANDLER = "deleteClassificationStructure"; private static final String NEW_CLASSI_STRUCTURE_HANDLER = "newClassificationStructure"; private String updateClassStructureHandler = "updateClassificationStructure"; private String selectClassStrucByClassIdHandler = "selectClassificationStructureByClassId"; private ClassificationStructureGui gui; private DetailDataSource dataSource; private ListDataSource axisSleevesDataSource; private DetailDataSource selectedSleeveDataSource; private AxisTreeLogic axisTreeLogic; private ButtonPanelLogic buttonPanelLogic; private AxisTreeToolBarLogic axisTreeToolBarLogic; private PreferenceGuiManager prefManager; private List<String> additionalAxisSleevesColumns = new ArrayList<String>(); private ExpressionButtonListener expressionButtonListener; private DataLink axisSleevesLink; public ClassificationStructureLogic(DetailDataSource dataSource) throws Exception { this(dataSource, new ClassificationStructureGui("Axe d'analyse")); } public void setAdditionalAxisSleevesColumns(List<String> additionalAxisSleevesColumns) { this.additionalAxisSleevesColumns = additionalAxisSleevesColumns; } public void addAdditionalAxisSleevesColumn(String columnName) { additionalAxisSleevesColumns.add(columnName); } public ClassificationStructureLogic(DetailDataSource dataSource, ClassificationStructureGui gui) throws Exception { this.gui = gui; this.dataSource = dataSource; buttonPanelLogic = new ButtonPanelLogic(gui.getButtonPanelGui()); axisTreeToolBarLogic = new AxisTreeToolBarLogic(gui.getAxisTreeToolBar()); buttonPanelLogic.showUndoRedo(false); if (dataSource.getLoadResult() != null) { gui.getClassificationType().setEnabled(false); } initPreferenceGui(dataSource.getGuiContext()); gui.setMaximumNodeDepth((Integer)dataSource.getGuiContext() .getProperty(SegmentationGuiPlugin.SEGMENTATION_AXIS_TREE_MAX_DEPTH)); PreferenceGui[] allPreference = prefManager.getAllPreference(); for (PreferenceGui anAllPreference : allPreference) { gui.getClassificationType().addItem(anAllPreference.getFamilyId()); } SegmentationSettingsCustomizer customizer = (SegmentationSettingsCustomizer)dataSource.getGuiContext() .getProperty(SegmentationSettingsCustomizer.SEGMENTATION_SETTINGS_CUSTOMIZER); if (customizer != null) { customizer.doPreDataSourceInit(this, dataSource); } initLogic(); if (customizer != null) { customizer.doPostDataSourceInit(this, dataSource); } //noinspection InstanceVariableUsedBeforeInitialized axisSleevesDataSource.addPropertyChangeListener(ListDataSource.SELECTED_ROW_PROPERTY, new SleeveSelectionListener()); } private void initPreferenceGui(GuiContext ctxt) throws IOException, XmlException, RequestException { StructureCache structureCache = (StructureCache)ctxt.getProperty(StructureCache.STRUCTURE_CACHE); StructureReader madReader = structureCache.getStructureReader(); prefManager = new PreferenceGuiManagerFactory(madReader).getPreferenceGuiManager(); } public void setUpdateClassificationStructureHandler(String updateClassStructureHandler) { this.updateClassStructureHandler = updateClassStructureHandler; } public void setSelectClassificationStructureByClassIdHandler(String selectClassStrucByClassIdHandler) { this.selectClassStrucByClassIdHandler = selectClassStrucByClassIdHandler; } protected void initLogic() throws Exception { selectedSleeveDataSource = new DetailDataSource(dataSource.getGuiContext()); axisSleevesDataSource = buildAxisSleevesDataSource(); dataSource.addDataSourceListener(new FatherDataSourceListener()); // Initialisation du ListDataSource de l'arbre et liaison avec le datasource p�re. linkDataSources(); declareFields(); dataSource.load(); axisTreeLogic = new AxisTreeLogic(this.dataSource, axisSleevesDataSource, this.gui.getAxisTree()); axisTreeToolBarLogic.init(axisTreeLogic); // On attache l'arbre � la fen�tre g�n�rale. // On cr�e les listeners declareSleeveField("sleeveName"); gui.addSleeveDustbinListener(new DustbinListener()); declareSleeveField("formula"); dataSource.addPropertyChangeListener("classificationName", new ClassificationNameListener()); expressionButtonListener = new ExpressionButtonListener(dataSource, axisSleevesDataSource, selectedSleeveDataSource, prefManager, gui); gui.addExpressionActionListener(expressionButtonListener); } private void declareFields() { dataSource.declare("classificationName", getGui().getClassificationName()); dataSource.declare("classificationType", getGui().getClassificationType()); dataSource.declare("classificationId"); dataSource.setFieldValue("classificationId", "-1"); selectedSleeveDataSource.declare("sleeveCode", getGui().getSleeveCode()); selectedSleeveDataSource.declare("sleeveName", getGui().getSleeveName()); selectedSleeveDataSource.declare("sleeveDustbin", getGui().getSleeveDustbin()); selectedSleeveDataSource.declare("formula", getGui().getFormula()); } protected void declareSleeveField(String fieldName) { selectedSleeveDataSource.addPropertyChangeListener(fieldName, new SleevePropertyChange()); } public DetailDataSource getDataSource() { return dataSource; } public DetailDataSource getSelectedSleeveDataSource() { return selectedSleeveDataSource; } public ListDataSource getAxisSleevesDataSource() { return axisSleevesDataSource; } public AxisTreeLogic getAxisTreeLogic() { return axisTreeLogic; } public ClassificationStructureGui getGui() { return gui; } public void setAxisSleevesLinkErrorHandler(ErrorHandler handler) { axisSleevesLink.setErrorHandler(handler); } private void linkDataSources() { axisSleevesLink = new DataLink(dataSource, axisSleevesDataSource, new JoinKeys("classificationId")); axisSleevesLink.setLoadPolicy(DataLink.Policy.AFTER_FATHER); axisSleevesLink.setSavePolicy(DataLink.Policy.AFTER_FATHER); axisSleevesLink.start(); ProxyErrorHandler checker = new ProxyErrorHandler(axisSleevesLink.getErrorHandler()); axisSleevesLink.setErrorHandler(checker); buttonPanelLogic.setMainDataSource(dataSource); buttonPanelLogic.addSubDataSource(axisSleevesDataSource); buttonPanelLogic.addErrorChecker(checker); } private ListDataSource buildAxisSleevesDataSource() { ListDataSource listDataSource = new ListDataSource(); listDataSource.setLoadFactoryId(getAxisSleevesLoadFactoryId()); listDataSource.setInsertFactoryId(NEW_CLASSI_STRUCTURE_HANDLER); listDataSource.setUpdateFactoryId(updateClassStructureHandler); listDataSource.setDeleteFactoryId(DELETE_CLASS_STRUCTURE_HANDLER); List<String> columns = new ArrayList<String>(); columns.add("classificationId"); columns.add("sleeveId"); columns.add("sleeveRowId"); columns.add("sleeveCode"); columns.add("sleeveName"); columns.add("sleeveDustbin"); columns.add("terminalElement"); columns.add("formula"); columns.addAll(additionalAxisSleevesColumns); listDataSource.setColumns(columns.toArray(new String[]{})); return listDataSource; } protected String getAxisSleevesLoadFactoryId() { return selectClassStrucByClassIdHandler; } public void addClassificationExtensionField(String label, String fieldName, JComponent component) { getGui().getClassifExtensionPanel() .addItem(label, component, new Insets(0, 0, 2, 5), new Insets(0, 5, 2, 0)); dataSource.declare(fieldName, component); } public void addSleeveExtensionField(String label, String fieldName, JComponent component) { component.setName(fieldName); getGui().getSleeveExtensionPanel() .addItem(label, component, new Insets(0, 0, 2, 5), new Insets(0, 5, 2, 0)); selectedSleeveDataSource.declare(fieldName, component); additionalAxisSleevesColumns.add(fieldName); declareSleeveField(fieldName); } public void setClassificationTypeEnabled(boolean enabled) { getGui().getClassificationType().setEnabled(enabled); } public void addClassificationTypeActionListener(ActionListener actionListener) { getGui().getClassificationType().addActionListener(actionListener); } public ButtonPanelLogic getButtonPanelLogic() { return buttonPanelLogic; } /** * <p> DataSourceListener charg� de v�rifier et modifier la ListDataSource contenant les donn�es des * poches au moment de la sauvegarde. On v�rifie qu'il y a une poche fourre-tout, on supprime toutes les * poches et on les recr�e, en recalculant le code poche � partir de la position de la poche dans l'arbre. * </p> * * <p> Le m�canisme de suppression-recr�ation a �t� mis en place � cause de la contrainte d'unicit� * existant sur le couple (CLASSIFICATION_ID, SLEEVE_CODE). </p> */ private class FatherDataSourceListener extends DataSourceAdapter { @Override public void beforeSaveEvent(DataSourceEvent event) { AxisTreeModel axisTreeModel = axisTreeLogic.getModel(); // S'il n'existe pas de poche fourre-tout, on lance une // Exception : une popup sera pr�sent�e � l'utilisateur. if (!axisTreeModel.hasDustBin()) { throw new ClassificationException("Il faut une poche fourre-tout."); } // S'il existe une poche non fourre-tout sans formule, on lance une // Exception : une popup sera pr�sent�e � l'utilisateur. String sleeveNameWithoutFormula = axisTreeModel.getSleeveNameWithoutFormula(); if (sleeveNameWithoutFormula != null) { throw new ClassificationException("La poche '" + sleeveNameWithoutFormula + "' n'a pas de formule."); } // S'il existe 2 poches avec le m�me nom. String doubleSleeveName = axisTreeModel.findDoubleSleeveName(); if (doubleSleeveName != null) { throw new ClassificationException("Plusieurs poches portent le libell� '" + doubleSleeveName + "'."); } } } /** * Listener charg� de mettre � jour le nom de l'axe lorsqu'il est chang� dans le TextField. */ class ClassificationNameListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { String classificationName = gui.getClassificationName().getText(); AxisTreeNode axe = (AxisTreeNode)axisTreeLogic.getModel().getRoot(); axe.setName(classificationName); axisTreeLogic.getModel().nodeChanged(axe); } } /** * Listener charg� d'afficher les donn�es de la poche s�lectionn�e. */ private class SleeveSelectionListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { final Row selectedRow = ((ListDataSource)evt.getSource()).getSelectedRow(); if (selectedRow != null) { Object currentSelection = axisTreeLogic.getLastPathComponent(); if (currentSelection != null) { // TreePath selectionPath = axisTreeLogic.getGui().getSelectionPath(); // if (selectionPath != null) { // Object currentSelection = selectionPath.getLastPathComponent(); if (currentSelection instanceof Sleeve) { final Sleeve sleeve = ((Sleeve)currentSelection); if (sleeve.isTerminal()) { boolean dustbinAllreadyExists = axisTreeLogic.getModel().hasDustBin(); setSleeveDisplay(sleeve.isDustbin(), dustbinAllreadyExists); } else { setFolderDisplay(); } final Result loadResult = new Result(); loadResult.addRow(new Row(selectedRow)); selectedSleeveDataSource.setLoadResult(loadResult); expressionButtonListener .setSelectedSleeveRowId(selectedRow.getFieldValue("sleeveRowId")); expressionButtonListener.setSelectedClassificationId( dataSource.getSelectedRow().getFieldValue("classificationId")); } else { // Cas o� l'axe est s�lectionn� disableSelectionDisplay(); selectedSleeveDataSource.clear(); } } } else { // Cas o� aucune poche n'est s�lectionn�e disableSelectionDisplay(); selectedSleeveDataSource.clear(); } try { selectedSleeveDataSource.load(); } catch (RequestException exception) { LOG.error("SleeveSelectionListener.propertyChange", exception); } } } protected void disableSelectionDisplay() { gui.setSleeveNameEnabled(false); gui.setSleeveDustbinEnabled(false); gui.setSleeveEditExpressionButtonEnabled(false); gui.setSleeveExtensionFieldsEnabled(false); } protected void setSleeveDisplay(boolean isDustbin, boolean dustbinAllreadyExists) { gui.setSleeveNameEnabled(true); gui.setSleeveDustbinEnabled(isDustbin == dustbinAllreadyExists); gui.setSleeveEditExpressionButtonEnabled(!isDustbin); gui.setSleeveExtensionFieldsEnabled(true); } protected void setFolderDisplay() { gui.setSleeveNameEnabled(true); gui.setSleeveDustbinEnabled(false); gui.setSleeveEditExpressionButtonEnabled(false); gui.setSleeveExtensionFieldsEnabled(false); } protected class SleevePropertyChange implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { if (axisSleevesDataSource.getSelectedRow() != null) { final int selectedRowIndex = axisSleevesDataSource.getSelectedRowIndex(); axisSleevesDataSource.setValue(selectedRowIndex, evt.getPropertyName(), (String)evt.getNewValue()); axisTreeLogic.updateTree(); } } } /** * Listener charg� de mettre � jour le statut fourre-tout lorsqu'il est chang� par la CheckBox. */ // class DustbinListener implements PropertyChangeListener { // public void propertyChange(PropertyChangeEvent event) { class DustbinListener implements ActionListener { public void actionPerformed(ActionEvent event) { if (axisSleevesDataSource.getSelectedRow() != null) { Object currentSelection = axisTreeLogic.getLastPathComponent(); if (currentSelection != null && currentSelection instanceof Sleeve) { Sleeve selectedSleeve = (Sleeve)currentSelection; // TreePath path = axisTreeLogic.getGui().getSelectionPath(); // if (path != null && path.getLastPathComponent() instanceof Sleeve) { // Sleeve selectedSleeve = (Sleeve)path.getLastPathComponent(); final int selectedRowIndex = axisSleevesDataSource.getSelectedRowIndex(); if (Boolean.valueOf(selectedSleeveDataSource.getFieldValue( "sleeveDustbin"))) { boolean expressionIsEmpty = selectedSleeve.getFormula() == null || selectedSleeve.getFormula().trim().length() == 0; if (!expressionIsEmpty) { // si on convertit une poche en fourre-tout et qu'on a d�ja // �dit� son �quation, il faut lancer un message de confirmation // pour effacer l'�quation if (gui.confirmClearFormula()) { selectedSleeveDataSource.setFieldValue("formula", ""); } else { selectedSleeveDataSource.setFieldValue("sleeveDustbin", "false"); return; } } } axisSleevesDataSource.setValue(selectedRowIndex, "sleeveDustbin", selectedSleeveDataSource.getFieldValue("sleeveDustbin")); axisTreeLogic.updateTree(); gui.enableFormula(!selectedSleeve.isDustbin()); } } } } }